Java安全 - ROME链
字数 1977 2025-08-19 12:42:36

Java安全 - ROME链分析

1. 背景介绍

ROME链是Java反序列化漏洞利用中的一条重要攻击链,主要利用了ROME库中的相关类进行反序列化攻击。这条链在Java反序列化漏洞利用中具有重要地位,因为它不依赖JDK内部类,而是利用第三方库中的类实现攻击。

2. 关键类分析

2.1 HashTable类

在反序列化漏洞利用中,HashTable的readObject()方法是重要的入口点:

private void readObject(java.io.ObjectInputStream s)
    throws IOException, ClassNotFoundException {
    // Read in the threshold and loadFactor
    s.defaultReadObject();
    
    // Read the original capacity
    int origCapacity = s.readInt();
    // Read number of elements
    int elements = s.readInt();
    
    // Initialize the table
    int capacity = (int)(elements * loadFactor) + 1;
    if (capacity > origCapacity && origCapacity >= 0) {
        if (capacity > MAXIMUM_CAPACITY)
            capacity = MAXIMUM_CAPACITY;
        float newLoadFactor = loadFactor;
        // Check loadFactor because of 1.2 bug
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            newLoadFactor = 0.75f;
        @SuppressWarnings("unchecked")
        Entry<K,V>[] newTable = (Entry<K,V>[])new Entry[capacity];
        table = newTable;
        threshold = (int)Math.min(capacity * newLoadFactor, MAXIMUM_CAPACITY + 1);
        initHashSeedAsNeeded(capacity);
    }
    
    // Read the number of elements and then all the key/value objects
    for (; elements > 0; elements--) {
        @SuppressWarnings("unchecked")
        K key = (K)s.readObject();
        @SuppressWarnings("unchecked")
        V value = (V)s.readObject();
        put(key, value);  // 关键点:这里会调用put方法
    }
}

关键点:在反序列化过程中,HashTable会读取序列化数据中的键值对,并通过put()方法将它们重新放入表中。这为我们提供了触发后续链的机会。

2.2 为什么不能直接往HashTable中put

在构造利用链时,不能直接在Payload中使用HashTable.put()方法,原因如下:

  1. 提前触发问题:如果直接调用put()方法,会立即执行相关操作,而不是在反序列化过程中执行
  2. 序列化控制:我们需要确保操作是在反序列化过程中执行,而不是在构造Payload时执行
  3. 对象状态:反序列化时的对象状态可能与直接操作时不同

3. ROME链核心组件

3.1 ToStringBean类

ToStringBean是ROME链中的关键类,它能够通过反射调用任意对象的toString方法:

public String toString() {
    try {
        // 通过反射调用对象的toString方法
        return BeanUtils.toString(this._obj);
    } catch (Exception e) {
        return super.toString();
    }
}

3.2 EqualsBean类

EqualsBean是另一个关键类,它能够通过反射调用任意对象的equals和hashCode方法:

public boolean equals(Object obj) {
    return BeanUtils.equals(this._obj, obj);
}

public int hashCode() {
    return BeanUtils.hashCodeForBean(this._obj);
}

4. ROME链构造原理

ROME链的构造基于以下原理:

  1. HashTable的哈希冲突处理:当HashTable中两个键的hashCode相同时,会调用equals方法进行比较
  2. EqualsBean的利用:我们可以控制EqualsBean来触发任意对象的hashCode或equals方法
  3. ToStringBean的利用:通过ToStringBean可以触发任意对象的toString方法

5. 完整利用链分析

完整的ROME链调用过程如下:

  1. 反序列化入口HashTable.readObject()
  2. 触发hashCode/equals:在反序列化过程中,HashTable会计算键的hashCode并可能调用equals方法
  3. EqualsBean触发:通过精心构造的EqualsBean,触发ToStringBean的toString方法
  4. ToStringBean反射调用:ToStringBean通过反射调用恶意对象的toString方法
  5. 最终执行恶意代码:通过反射调用TemplatesImpl等类的恶意方法

6. 利用链构造步骤

6.1 基础构造

  1. 创建一个恶意对象(如TemplatesImpl)
  2. 用ToStringBean包装这个恶意对象
  3. 用EqualsBean包装ToStringBean
  4. 构造两个HashTable键,使它们的hashCode相同
  5. 将EqualsBean作为HashTable的键

6.2 详细构造过程

// 1. 创建恶意TemplatesImpl对象
TemplatesImpl templates = createMaliciousTemplates();

// 2. 用ToStringBean包装
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);

// 3. 用EqualsBean包装
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);

// 4. 构造HashTable
HashMap hashMap = new HashMap();
hashMap.put(equalsBean, "value");

// 5. 序列化这个HashTable
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(hashMap);
oos.close();

// 6. 反序列化触发漏洞
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();

7. 关键注意事项

  1. HashTable键的hashCode控制:必须确保两个键的hashCode相同才能触发equals方法
  2. EqualsBean的类型设置:EqualsBean的类型必须与ToStringBean的实际类型匹配
  3. 反序列化顺序:必须确保所有对象在反序列化时能正确重建
  4. ROME库版本:不同版本的ROME库可能有不同的行为

8. 防御措施

  1. 升级ROME库:使用最新版本的ROME库
  2. 反序列化过滤:实现ObjectInputFilter限制反序列化的类
  3. 最小权限原则:运行Java应用时使用最小必要权限
  4. 代码审计:检查应用中是否存在不安全的反序列化操作

9. 变种与扩展

ROME链可以与其他链结合使用:

  1. 与TemplatesImpl结合:通过ToStringBean触发TemplatesImpl的恶意字节码加载
  2. 与JNDI注入结合:通过toString方法触发JNDI查找
  3. 与其他第三方库结合:利用其他库的类似特性构造混合链

10. 调试技巧

调试ROME链时需要注意:

  1. 断点设置:在HashTable.readObject()、EqualsBean.hashCode()/equals()、ToStringBean.toString()设置断点
  2. 调用栈分析:观察反序列化时的完整调用栈
  3. 对象状态检查:检查反序列化过程中各关键对象的状态变化

11. 总结

ROME链是Java反序列化攻击中的重要技术,它利用了ROME库中的EqualsBean和ToStringBean类,结合HashTable的反序列化特性,实现了不依赖JDK内部类的攻击链。理解这条链的原理和构造方法对于Java安全研究和防御具有重要意义。

Java安全 - ROME链分析 1. 背景介绍 ROME链是Java反序列化漏洞利用中的一条重要攻击链,主要利用了ROME库中的相关类进行反序列化攻击。这条链在Java反序列化漏洞利用中具有重要地位,因为它不依赖JDK内部类,而是利用第三方库中的类实现攻击。 2. 关键类分析 2.1 HashTable类 在反序列化漏洞利用中,HashTable的 readObject() 方法是重要的入口点: 关键点 :在反序列化过程中,HashTable会读取序列化数据中的键值对,并通过 put() 方法将它们重新放入表中。这为我们提供了触发后续链的机会。 2.2 为什么不能直接往HashTable中put 在构造利用链时,不能直接在Payload中使用 HashTable.put() 方法,原因如下: 提前触发问题 :如果直接调用 put() 方法,会立即执行相关操作,而不是在反序列化过程中执行 序列化控制 :我们需要确保操作是在反序列化过程中执行,而不是在构造Payload时执行 对象状态 :反序列化时的对象状态可能与直接操作时不同 3. ROME链核心组件 3.1 ToStringBean类 ToStringBean 是ROME链中的关键类,它能够通过反射调用任意对象的toString方法: 3.2 EqualsBean类 EqualsBean 是另一个关键类,它能够通过反射调用任意对象的equals和hashCode方法: 4. ROME链构造原理 ROME链的构造基于以下原理: HashTable的哈希冲突处理 :当HashTable中两个键的hashCode相同时,会调用equals方法进行比较 EqualsBean的利用 :我们可以控制EqualsBean来触发任意对象的hashCode或equals方法 ToStringBean的利用 :通过ToStringBean可以触发任意对象的toString方法 5. 完整利用链分析 完整的ROME链调用过程如下: 反序列化入口 : HashTable.readObject() 触发hashCode/equals :在反序列化过程中,HashTable会计算键的hashCode并可能调用equals方法 EqualsBean触发 :通过精心构造的EqualsBean,触发ToStringBean的toString方法 ToStringBean反射调用 :ToStringBean通过反射调用恶意对象的toString方法 最终执行恶意代码 :通过反射调用TemplatesImpl等类的恶意方法 6. 利用链构造步骤 6.1 基础构造 创建一个恶意对象(如TemplatesImpl) 用ToStringBean包装这个恶意对象 用EqualsBean包装ToStringBean 构造两个HashTable键,使它们的hashCode相同 将EqualsBean作为HashTable的键 6.2 详细构造过程 7. 关键注意事项 HashTable键的hashCode控制 :必须确保两个键的hashCode相同才能触发equals方法 EqualsBean的类型设置 :EqualsBean的类型必须与ToStringBean的实际类型匹配 反序列化顺序 :必须确保所有对象在反序列化时能正确重建 ROME库版本 :不同版本的ROME库可能有不同的行为 8. 防御措施 升级ROME库 :使用最新版本的ROME库 反序列化过滤 :实现ObjectInputFilter限制反序列化的类 最小权限原则 :运行Java应用时使用最小必要权限 代码审计 :检查应用中是否存在不安全的反序列化操作 9. 变种与扩展 ROME链可以与其他链结合使用: 与TemplatesImpl结合 :通过ToStringBean触发TemplatesImpl的恶意字节码加载 与JNDI注入结合 :通过toString方法触发JNDI查找 与其他第三方库结合 :利用其他库的类似特性构造混合链 10. 调试技巧 调试ROME链时需要注意: 断点设置 :在HashTable.readObject()、EqualsBean.hashCode()/equals()、ToStringBean.toString()设置断点 调用栈分析 :观察反序列化时的完整调用栈 对象状态检查 :检查反序列化过程中各关键对象的状态变化 11. 总结 ROME链是Java反序列化攻击中的重要技术,它利用了ROME库中的EqualsBean和ToStringBean类,结合HashTable的反序列化特性,实现了不依赖JDK内部类的攻击链。理解这条链的原理和构造方法对于Java安全研究和防御具有重要意义。