zoukankan      html  css  js  c++  java
  • Yso中的URLDNS分析学习

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

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

     
    首先先去 dnslog.cn 获取一个url
     

     
     

    java -jar ysoserial-0.0.6-SNAPSHOT-all.jar URLDNS "http://pk3q64.dnslog.cn" > Test.txt
     
     
    查看生成的文件
     

     

     
    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查询的记录
     

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

    简单的观察一下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
     

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

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

     
    我们这里面调用的就是 URLDNS
     

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

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

    分析

     
    DNSURL 反序列化的链为

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

    首先序列化点在 HashMap的 readObject 方法(因为实现了Serializable接口)
     

     
    readObject 调用了 putVal方法,且参数里调用了 HashMap的hash方法
     

    继续跟进
     
     

     
    因为HashMap里面的 key 与 Value 是一个对应的关系,所以看看 ysoserial传入的 key 是什么吧

     
    显然传入的 keyURL
     
    因此是调用了 URL 中的 hashCode方法,跟进看一下
     

     
    hashcode 的值为 -1 则调用 handler.hashcode 方法
     
    其实这个值默认就是 -1
     

     
    yso中也是用反射将其强制设置为 -1
     

     
    调用的 hander.hashCode 其实也就是我们传入的 hander
     

     
    URL 的构造方法中将其初始化为我们传入的
     

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

     
    这里面将 u 传入 getHostAddress
     
    跟进getHostAddress
     

     
    其中将 u.getHost() 的结果放入 InetAddress.getByName 此函数将是根据主机名获取对应ip,相当于发出一次dnslog请求
     
    我们查看一下 URL.getHost()
     

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

    后续思考

     
    我们查看一下HashMap的 put 方法看看
     

     
    发现也调用了 hash方法

     
    那这样我们利用 ysoserial 生成 POC的时候,也不是会有dns请求吗?
     

     
     
    我们测试一下
     

    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);
        }
    }
    

     

     
    确实会产生很多请求
     

     
    有个方法就是通过反射修改 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
    ");
            Field justhash = Class.forName("java.net.URL").getDeclaredField("hashCode");
            justhash.setAccessible(true);
            justhash.set(url,123);
            test.put(url,233);
        }
    }
    

     

     
    那么 URLDNS 呢
     

     
    也没有产生请求
     
    原因在这个

     
    这个 SilentURLStreamHandler 继承了 URLStreamHandler
     
    重写了里面的 openConnectiongetHostAddress
     

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

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

    原因是因为 URL 里面的 handler 设置的是 transient
     

     
    因为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);
        }
    }
    
    

     

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

    总结

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

  • 相关阅读:
    python的多线程
    python的socket解析
    python的os.system函数的应用
    自动化测试的4种模型
    测试中的一些常见名词解析
    mysql存储过程详解
    mysql时间加减函数
    十周课程总结
    实验&报告7
    实验& 报告7
  • 原文地址:https://www.cnblogs.com/Mikasa-Ackerman/p/Yso-zhong-deURLDNS-fen-xi-xue-xi.html
Copyright © 2011-2022 走看看