|
2017年,部实安全研究员在GitHub上发现一个令人窒息的体注案例。某知名开源项目,入漏其XML解析器处理用户上传的部实SVG图片时,直接拼接了文件内容到XML实体中。体注攻击者只需构造一个包含外部实体引用的入漏SVG文件,就能读取服务器上的部实/etc/passwd。更讽刺的体注是,这个漏洞存在了整整四年,入漏直到有人用它拿到了云服务器的部实IAM临时凭证。 XML外部实体注入(XXE)的体注本质,是入漏XML规范允许文档引用外部资源。解析器在处理<!DOCTYPE>声明时,部实会按照实体定义去获取内容。体注如果这个内容来自本地文件系统或内网地址,入漏就会造成信息泄露。说白了,就是解析器太“听话”,你让它读什么它就读什么。 一个典型的攻击载荷长这样: <?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <foo>&xxe;</foo> 服务器返回的响应里,/etc/passwd的内容就躺在<foo>标签里。更狠的玩法是结合expect://协议直接执行系统命令,或者用gopher://打内网Redis。 我见过最离谱的案例是某银行移动端App。开发团队为了省事,把用户反馈功能做成了XML格式提交。攻击者用Burp Suite抓包,把<content>标签替换成外部实体引用,直接读出了数据库配置文件。那个文件里明文写着MySQL root密码——运维连密码加密都懒得做。 防护手段其实不复杂。最彻底的办法是禁用DTD,PHP里用libxml_disable_entity_loader(true),Java里设置XMLConstants.FEATURE_SECURE_PROCESSING。但很多老代码根本改不动,那就退而求其次,把外部实体解析关掉,只允许内部实体。 有个细节容易被忽略:JSON接口也可能中招。某些框架会自动把JSON转成XML处理,比如JAXB。攻击者把Content-Type改成application/xml,绕过JSON校验,照样触发漏洞。所以不能只看报文格式,得看后端到底用什么解析。 还有个隐蔽的场景是Office文档。Word的.docx本质是ZIP包,里面全是XML。攻击者修改word/document.xml,插入外部实体引用,受害者打开文档就能触发。2014年那次针对某国会议员的攻击,用的就是这招——恶意文档通过邮件附件传播,读取了受害者电脑里的加密钱包文件。 修复这类漏洞,别只盯着解析器配置。代码审计要追到数据流源头,凡是接受XML输入的点都得排查。我自己踩过坑,以为把DocumentBuilderFactory的setFeature全设成true就安全了,结果漏了http://apache.org/xml/features/disallow-doctype-decl这个特性。测试时用经典payload能拦住,但换成带CDATA的变种就绕过去了。 说到底,XXE不是新技术,2013年就进了OWASP Top 10。但直到现在,每年漏洞报告里还有大量案例。原因无非是三点:开发者不知道默认配置不安全、代码复用没做安全评估、测试用例只覆盖正常功能。别指望框架能自动挡掉所有攻击——libxml2在2.9.0版本后默认不加载外部实体,但很多语言绑定层自己重新实现了解析逻辑,等于把安全默认值又改回去了。 最后说个实操技巧。排查历史代码时,用grep -r "DocumentBuilderFactory\|SAXParserFactory\|XMLReader"搜项目,凡是出现这些类的地方,逐个检查是否显式禁用了外部实体。这活儿枯燥,但真能救命。我上周刚帮朋友公司扫出三个可被利用的入口,其中一个还是他们CTO亲自写的工具类。 |