CVE-2017-18640: SnakeYAML 反序列化漏洞深度分析
0x00 漏洞背景与详情
- CVE ID: CVE-2017-18640
- 受影响组件: SnakeYAML (Java 生态中最流行的 YAML 解析库)
- 受影响版本: SnakeYAML < 1.26
- 漏洞类型: 反序列化 / 不安全的对象实例化
- 危险等级: 极高危 (Critical, CVSS 9.8)
CVE-2017-18640 是 Java 领域极为经典且影响深远的反序列化漏洞。由于大量主流框架(如 Spring Boot)依赖 SnakeYAML 进行配置解析或数据交互,该漏洞的影响面极广。漏洞的核心在于 SnakeYAML 在默认配置下,允许通过特定的 YAML 标签(Tags)在反序列化时实例化任意 Classpath 中的 Java 类,从而导致远程代码执行 (RCE)。
0x01 漏洞原理分析
SnakeYAML 遵循 YAML 1.1 规范,支持“显式类型标记”(Explicit Tags)。在 YAML 文档中,可以使用 !! 语法后接完整的 Java 类名来强制指定数据的反序列化类型。
漏洞触发逻辑:
- SnakeYAML 的默认
Constructor(构造器)在解析包含!!标签的节点时,会尝试通过反射调用目标类的构造函数进行实例化。 - 在 SnakeYAML 1.26 之前的版本中,默认构造器没有对允许实例化的类进行任何白名单或黑名单限制。
- 攻击者可以利用这一特性,传入恶意的
!!类名和特定的初始化参数,诱导应用程序实例化具有危险副作用的 Gadget 类,从而触发代码执行。
0x02 POC 与基础利用案例
在利用该漏洞时,最著名的 Gadget 链是基于 JDK 原生类 javax.script.ScriptEngineManager 的,该利用链无需依赖任何第三方库。
1. 经典 POC 示例
2. 执行逻辑拆解
- 攻击者在公网服务器准备一个恶意 JAR 包,该 JAR 包利用 Java SPI 机制,在
META-INF/services/javax.script.ScriptEngineFactory文件中注册了一个恶意的工厂类,并将执行命令的代码写入恶意类的静态代码块或构造函数中。 - 目标系统使用
new Yaml().load(payload)解析上述 YAML 字符串。 - SnakeYAML 依次实例化
URL、URLClassLoader,并将恶意 URL 传入。 - 随后实例化
ScriptEngineManager,由于其机制,它会使用传入的URLClassLoader去加载远程的 JAR 包并触发 SPI 注册逻辑。 - 恶意类被加载并实例化,代码执行完成。
0x03 高级利用姿势与实战场景
1. 不出网环境利用 (JNDI 注入 / 本地 Gadget)
如果目标机器无法访问外网,ScriptEngineManager 链将失效。此时可尝试其他本地 Gadget:
- JNDI 注入:
- 本地类触发:利用 Classpath 中已有的组件,如
org.springframework.beans.factory.config.PropertyPathFactoryBean结合 JNDI,或者C3P0的JndiRefForwardingDataSource。
2. 内存马 (Memory Shell) 注入
获取 RCE 权限后,为了持久化隐藏,攻击者常通过加载远程 JAR 或直接在本地利用链中编写恶意逻辑,通过反射机制(获取 StandardContext)在当前 Web 容器中动态注册 Filter、Servlet 或 Controller 型的内存马。
3. WAF 与特征检测绕过
由于 !! 和 ScriptEngineManager 等特征过于明显,实战中常常需要绕过 WAF:
- YAML 语法混淆:利用 YAML 的锚点 (
&) 和引用 (*) 语法打断连续关键字。 - 多行折叠:使用
|或>语法改变 Payload 结构布局。 - Unicode 转义:对关键的 Java 类名进行 Unicode 编码转义,以绕过简单的正则匹配。
0x04 应急排查与日志痕迹分析
在遭遇攻击时,防守方应重点关注以下排查维度:
1. 流量与日志审计
- 特征匹配:在 WAF、Nginx 日志或应用 Access 日志中,检索包含
!!、javax.script.ScriptEngineManager、java.net.URLClassLoader、JdbcRowSetImpl的请求数据。 - 解析错误日志:如果 Payload 构造错误或类找不到,应用日志中会抛出
org.yaml.snakeyaml.constructor.ConstructorException异常。
2. 网络外联分析
- 检查应用服务器是否有异常的主动外联记录,特别是向未知 IP 的 80/443 端口发起下载 JAR 包的 HTTP 请求,或者向外发起 1099 (RMI)、1389 (LDAP) 端口的请求。
3. 主机与进程检查
- 检查 Java 进程的子进程树,确认是否出现了
sh,bash,cmd.exe或calc.exe等非预期的命令执行。 - 检查操作系统的临时目录(如
/tmp)是否有随机生成的、被动态下载执行的 JAR 包。
0x05 修复与防御建议
- 升级组件(强烈推荐):
升级 SnakeYAML 到
1.26或更高版本。 - 启用 SafeConstructor:
在代码中实例化
Yaml时,强制使用SafeConstructor,它只允许实例化 Java 原生基本类型,彻底杜绝了任意类实例化漏洞。 - 白名单防御:
如果业务逻辑确实需要解析自定义的 Java 类,必须继承
Constructor类并重写相关的类检查逻辑,实施严格的白名单控制。