一些图省事的同学可能会说直接用 java 启动一个 rmi 服务就可以了,这样做的问题是比较多的,一方面 xray 是用 go 写的,再套一个 java 会很奇怪 。而且就算可以用 java,我们也需要为每个检测目标启动不同的服务,因为在同时扫描多个网站时,需要鉴别漏洞请求来源于哪个网站 。这其实牵涉到反连平台的一个关键问题:如果做请求关联,就是需要知道这条反连的请求是扫描那个目标时触发的 。
有个简单的方案是根据端口来区分,rmi 本质上是一个 socket 服务,我们可以在发送 payload 前启动一个随机的 socket 服务,然后将这个 socket 服务的端口填入 payload 中,内部只需要维持一个 map{“port” -> “request”} 即可 。理论上是可行的,但这样需要启动大量的 socket 服务来监听端口,听着就很脏,有没有更好的方法呢?
我们上面输入的 dataSourceName中输入的是 rmi://127.0.0.1:1099/aaa,/aaa这一部分像极了 http 的 path,我们设法取到这个值理论上就和 http 服务的反连平台基本一致了 。不妨来看看 RMI 服务的协议,https://docs.oracle.com/javase/9/docs/specs/rmi/protocol.html#overview, 发现这个协议还挺简单的,我用 wireshark 调了一下,大致流程是:
- client -> server dial tcp and send
4a 52 4d 4900 024bJRMIVersionProtocol(StreamProtocol)2. server -> client, repsond with client infos4e00093132372e302e302e31 0000 d399ProtocolACKLength127.0.0.154169其中 127.0.0.1:54169 对于 server 来讲就是 socket.RemoteAddr【Fastjson 反序列化漏洞自动化检测】3. client -> server, call
50xxxxxxxxxxxxxxxCall SerializationData 这里的 SerializationData 其实就是 String 的序列化数据,这里面必然包含这我们想要的那个 path, 我在实现时并没有按照 java 序列化数据的格式去乖乖读取,而是用了一个简单的办法,我发现 String 的序列化数据的真正内容都在最后面,那么我其实从后往前读取就可以找到想要的 path,具体方法可以从后往前读固定的长度,也可以给path 设置一个标记符,读到就结束,我用的是后者 。至此,我们把上面讨论的内容用代码串起来就可以做到 fastjson 的高效自动化检测了,该插件现已加入 xray 高级版,欢迎体验 。我取了4个版本相对关键的 fastjson 版本验证了一下,效果图如下:

文章插图
一点想法上面的实现还有个我觉得不够完美的点,由于我自行实现的 RMI 只实现了握手部分,取得 path 后就关掉连接了,这其实会导致服务端有一个异常信息 。其实有时间的话完全可以把剩下的协议部分实现以下,返回一个最简单的结果就可以,这个留给大家去发挥吧 。
在研究这个漏洞时,发现大家的研究点都集中在漏洞利用上,然而发现漏洞其实是利用漏洞的起点,而如何高效、自动化的检测漏洞也是非常值得我们去思考和研究的 。由于我之前没接触过 Java,很多都是花三分钟现学的,虽然文中结论我大都自己调试过,但精力有限,如有错误,欢迎与我联系改正 。
来源:https://zhuanlan.zhihu.com/p/99075925推荐阅读
- 大唐我李恪反了 吴王李恪
- 如何分辨汽车轮胎正反面?装反有多危险?
- 小孩喉咙长泡反复发烧
- “自动启停”烦透了,简直是“反人类”设计,这3种情况千万别开
- 遇事第一反应里,藏着你的见识和格局
- 为什么整天不停地喝茶,反而越喝越渴?
- 警惕7种茶喝错反致癌
- 葡萄千万别这样吃 吃错了不防癌抗癌反而致疾病
- 4款中药清肠茶 减肥不反弹
- 立冬后算深秋吗 立秋下雨是顺秋还是反秋
