linux下java反序列化通杀回显方法的低配版实现
故事的起因
一直觉得shiro反序列化是一个很舒服的洞,payload原生加密(无特征),实战中有概率遇见并且又是java反序列化洞所以危害又很大。不过尽管这样shiro打起来依然有java反序列化的两个痛点。第一是可用的gadget,第二个带内回显的问题。不过某天在刷tw的时候发现第二个痛点国内已经有大佬有成熟解决方案了。
注意看图,shiro的回显并不在http响应包中而是在http响应包之前,很玄学的回显对吧?联想最近在看了一篇文章通杀漏洞利用回显方法-linux平台,按我的理解这篇文章的思路大致是通过java反序列化执行代码&&系统命令获取到发起这次请求时服务端socket的文件描述符,然后在文件描述符写入回显内容。上图的回显效果和这种思路非常相似。
技术的难点
实现这种技术的难点在于如何通过java反序列化执行代码&&系统命令获取本次http请求用到socket的文件描述符。因为在服务器对外开放的时会有fd下会有许多socket描述符。
这里给出获取socket文件描述符我的一个低配版思路及实现,至于为啥是低配版会在文章最后提到。首先注意到socket后面的数字不同,这个数字实际上是inode号。这个inode号也出现在/proc/net/tcp中。
注意到每一个inode号对应唯一条tcp连接信息并且这条信息中的remote_address项记录了远程连接的ip和端口号。说到这里其实获取socket思路就很明显了:通过指定客户端发起请求的源端口号,通过cat grep awk组合大法在tcp表中拿到inode,把拿到的inode号再去fd目录下再用cat grep wak大法拿到文件描述符的数字,再调用java代码打开文件描述符即可实现带内回显。
实现细节
指定端口号
requests库可以重新实现Http达到指定请求端口的目的。
1 | class SourcePortAdapter(HTTPAdapter): |
获取socket对应的文件描述符
整个流程使用的命令如下
1 | a=`cat /proc/$PPID/net/tcp6|awk '{if($10>0)print}'|grep -i %s|awk '{print $10}'`; |
往文件描述中写数据
现在假设shiro存在反序列化并且所用gadget的末端是走的TemplatesImpl,那么我们可以把ysoserial中的硬编码的命令执行改成下面这样的代码执行。
1 | String[] cmd = { "/bin/sh", "-c", "a=`cat /proc/$PPID/net/tcp6|awk '{if($10>0)print}'|grep -i %s|awk '{print $10}'`;b=`ls -l /proc/$PPID/fd|grep $a|awk '{print $9}'`;echo -n $b"}; |
我这种低配版指令ifconfig后效果实现效果如下,服务端会直接返回数据并断掉连接,所以没有了后面http响应包,requests库无法识别返回的内容报错。
总结
- 我这种方法因为需要保证请求源端口,所以没办法按照图中师傅实现的一样在burp中(burp代理后发起请求的端口不可控)。同样的道理如果脆弱的shiro应用在反代后面,因为反代的源端口不可预测所以没办法用这种低配版方案拿到回显。但实际情况不出网的shiro肯定是在内网里面的,所以从这角度想想还有点鸡肋,就当抛砖引玉了~
- 在上面引用的文章中提到了 “jvm所有的对象都存储在堆内存中,也许可以通过某种方法直接获取存储在堆内存中的socket对象实现回显”,我猜可以在burp里面利用的情况应该是通过某种黑魔法获取到了本次请求的socket对象了(或者是更底层的方法)所以才不要以客户端源口作为过滤条件。
- 写到这忽然想起,那个图片payload貌似没有打码,或许把payload用shiro常见的密钥撞一下撞可以看到标准版思路的片段?体力不够,溜了。
研究这个问题时候也请教了相关的大哥接收到了一些提示,因为属于他人知识产权,文章并未提及。在此谢过指点我的大哥们。
linux下java反序列化通杀回显方法的低配版实现
https://cl0und.github.io/2020/02/24/linux下java反序列化通杀回显方法的低配版实现/