1. hashmap
Map是一个集合,本质上还是数组,HashMap是Map的子接口。该集合的结构为key–>value,两个一起称为一个Entry(jdk7),在jdk8中底层的数组为Node[]。当new HashMap()时,在jdk7中会直接创建一个长度为16的数组;jdk8中并不直接创建,而是在调用put方法时才去创建一个长度为16的数组。
hashmap作为入口类。反序列化的入口类就是jdk中经常被使用的类,继承了Serialize接口,具备readObject方法,调用一些类和该类中的某种方法(方法中可以直接或者间接调用危险函数)
2. 首先看看urldns链子的作用
服务器是否存在反序列化漏洞
- 触发反序列化操作:通过构造包含 URL 的 HashMap 并进行序列化和反序列化操作,如果服务器成功执行了反序列化,并且触发了对 URL 的访问产生 DNS 请求,那么可以初步判断服务器存在反序列化漏洞的可能性。
- 检测漏洞利用条件:验证服务器是否在不恰当的场景下执行了反序列化,例如从不可信的数据源接收序列化数据并进行反序列化操作。
二、服务器对外部资源访问的控制情况 - 网络访问限制:观察服务器在处理包含 URL 的 HashMap 反序列化时,是否能够成功访问外部 URL 产生 DNS 请求。如果服务器对外部网络访问有严格的控制,可能无法触发 DNS 请求,这也反映了服务器的安全策略对反序列化漏洞利用的限制程度。
- 安全防护机制:了解服务器是否有针对反序列化过程中外部资源访问的监测和防护机制,例如防火墙规则、入侵检测系统等。
三、确定潜在的攻击面 - 漏洞影响范围:如果验证成功,说明服务器可能容易受到基于反序列化漏洞的攻击。可以进一步分析可能受到影响的业务模块和系统组件,确定潜在的攻击面。
- 攻击路径探索:根据验证结果,探索可能的攻击路径,例如通过构造更复杂的利用链,结合其他漏洞或弱点,尝试实现更严重的攻击效果,如远程代码执行。
可以看到,我们了解到urldns链子,我突然有些想法,首先我们可以利用一些原生类,因为这些类是一直存在的,我们可以直接利用就像是urldns链子一样.php也有原生的类.同时php一般都利用魔术方法进行利用,java也有这些方法比如 tostring 方法. 但是java又不一样,因为java更多的是利用重写readobject方法.我们除了盯着原生类去看是否又反序列化漏洞之外,我们还可以看到很多代码审计重写的类去挖掘.不断尝试不同链子.
3. urldns链子为什么能够验证shiro等反序列化漏洞?
这一点,我也是刚刚搞懂,首先我们知道urldns是以hashmap为起点作为一个链子入口,我们可以构造链子去打hashmap的反序列化。但是如果说我们验证比如说其他的反序列化漏洞,如果有序列化hashmap这个类的对象,我们可以以这个类为起点,去构造新的链子触发新的类的操作。所以urldns链子的路径不是一成不变的,只有入口是确定的。
4. 分析
跟着大佬的步骤一步一步进行分析.
首先拿到hashmap类的源码
找到readobject方法,查看重写方法的实现。跟踪hash方法
1 | static final int hash(Object key) { |
这个方法很短啊,看到就是传进来一个object对象然后一个判断key对象是否存在,不存在则返回0.存在则返回hashcode的值。这个其实很奇妙,因为我们要看传入进来的这个k到底是什么对象,因为不同的对象对应的hashcode可能被重写了(这里可以提一点,object类已经定义了hashcode这个方法,因此无论是什么对象,都会执行他自己的hashcode)。因此执行的不一定是object这个类的对象,因此可以看到我们的urldns这条链子打的是URL类的一个对象。进入这URL类对象的hashcode
首先看到这个类定义了一个私有属性为-1 ,同时还有个hashcode方法,这个hashcode方法基本就是
判断是否是-1 不是-1说明已经计算了hash值,不是则继续计算,继续执行。又是一个hashcode方法 但是此时我们的对象换成了handler 对象,我们跟进handler 查看这个对象的hashcode方法。
这是个无法被序列化的属性,其实之前我们就应该知道必须是hashcode 值必须是-1才会执行这个handler对象的hashcode
发现这个方法接收一个URL 对象参数 进入gethostaddress
继续进入 gethostaddress
1 | synchronized InetAddress getHostAddress() { |
这个才是主角,查看文档
方法首先判断host 和hostaddress都不为空之后,就会执行这个方法,解析这个域名的ip
这正是我们想要达到的目的所在。可以看到这些都是一环套一环的,就是有些方法之间互相调用,然后找到一些危险方法。可以执行一些功能操作。
5. urldns链
5.1 序列化
1 | package mytest; |
6. 防护
放在classpath,将应用代码中的java.io.ObjectInputStream替换为SerialKiller,之后配置让其能够允许或禁用一些存在问题的类,SerialKiller有Hot-Reload,Whitelisting,Blacklisting几个特性,控制了外部输入反序列化后的可信类型。
一、Hot-Reload 特性
Hot-Reload(热加载)特性允许在应用运行时动态更新配置,无需重启应用即可使新的配置生效。这对于需要频繁调整可信类型列表的场景非常有用,可以快速响应安全需求的变化,提高系统的灵活性和可维护性。
二、Whitelisting(白名单)特性
白名单特性允许明确指定哪些类是被允许进行反序列化的。只有在白名单中的类才能够成功反序列化,其他类将被拒绝。这样可以确保只有经过授权的类能够被反序列化,防止恶意类被加载和执行,从而增强系统的安全性。
三、Blacklisting(黑名单)特性
黑名单特性与白名单相反,它用于明确指定哪些类是不被允许进行反序列化的。任何在黑名单中的类在反序列化过程中都会被阻止,从而避免潜在的安全风险。这种特性可以针对已知的存在安全问题的类进行快速排除,降低被攻击的可能性。