本文共 2657 字,大约阅读时间需要 8 分钟。
关于如何检测与修复Java反序列化漏洞的一次技术沉淀
在近期的技术研究中,发现一个与Java反序列化相关的重要发现:在某些特定的框架中,例如WebLogic、WebSphere、JBoss等,存在严重的反序列化漏洞。特别是在JBoss5.x和6.x版本中,该漏洞主要体现在httpinvoker
组件的ReadOnlyAccessFilter
中的doFilter
方法中。
为了更好地理解反序列化漏洞的内在机制,我们可以从以下两个维度进行分析:
一、反序列化漏洞的产生机理
反序列化漏洞的出现通常与ObjectInputStream
的使用相关。具体而言,当一个类实现了java.io.Serializable
接口后,它就具备了自定义反序列化的能力。因此,只有实现了这个接口的类,才能通过readObject()
方法被反序列化。
在具体的实现细节中,每个实现了java.io.Serializable
的类,都会有自己的readObject()
方法。这个方法的主要职责是从数据流中读取字节序列,并将其转换为目标对象。如果这个方法被恶意修改,潜在的风险就在所难以及ray。
就JBoss5.x/6.x反序列化漏洞而言,具体的漏洞点位于httpinvoker
组件中。这意味着如果控制方具备一定的技术条件,可以通过特定的请求发送恶意序列化数据,从而控制受害者的系统。
二、如何发现反序列化漏洞
在实际操作中,对于反序列化漏洞的发现,可以分为以下两种情况:
第一种情况:基于源代码审计
在源代码审计中,我们需要重点关注类中实现了java.io.Serializable
接口的类的readObject()
方法。特别是要检查ObjectInputStream
的使用是否遵循安全规范。例如,当创建一个新的ObjectInputStream
对象时,是否仅限用来反序列化内部已知的、曾经注册过的类?如果有未知类被反序列化,就很可能存在安全隐患。
第二种情况:基于黑盒测试(Black Box Testing)
对于黑盒测试,其核心在于分析实际运作中的反序列化数据。在这种方式下,我们可以观察到从远程会话中传送过的数据序列。例如,通常会有数据以rO0AB
开头的形式传输,这正是反序列化数据流量的典型特征。
针对这种数据特点,可以使用类似ysoserial
这样的工具,将其转化为针对不同外部库的攻击ayload。对这些payload进行进一步的加工,使之能够以类似https://example.com/path/payload
的形式发送到目标系统,从而触发反序列化漏洞。
三、常见的对策建议
针对反序列化漏洞的修复,一般建议采取以下三类措施:
第一类:对类的权限进行严格管理
在ObjectInputStream
的resolveClass
方法中,除了实现默认的反序列化机制之外,可以自定义一个新的ObjectInputStream
。这个自定义的ObjectInputStream
在处理类名解析(即resolveClass
方法)时,实施类的授权管理检验。只有已经预先批准过的类,才能被允许进行反序列化。否则,将抛出相应的异常,阻止恶意序列化对象的建立。
具体实现方法是:自定义一个继承自ObjectInputStream
的类,重编译其resolveClass
方法。逻辑大致如下:
cutomObjectInputStreampublic class MyObjectInputStream extends ObjectInputStream { public MyObjectInputStream(ObjectStreamClass desc) throws IOException { super(desc); } @Override protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String className = desc.getName(); // 检查className是否为信任的类 if (!isAllowdClass(className)) { throw new SecurityException("未授权的类加载"); } return super.resolveClass(desc); }}
第二类:禁止外部执行操作
为了防止反序列化漏洞被用来执行恶意代码,可以禁用JVM的Runtime.exec
方法。具体实现方式是,在顶级安全管理器中进行权限管理,即:
System.getSecurityManager();SecurityManager sm = new MySecurityManager();System.setSecurityManager(sm);class MySecurityManager extends SecurityManager { @Override public void checkExec(String cmd, ProcessImpl proc, InputStream stdin, OutputStream stdout, OutputStream stderr) throws SecurityException { throw new SecurityException("禁止外部命令执行"); }}
第三类:及时更新第三方库
对于像commons-collections
、commons-io
这样的第三方库,应定期检查并及时更新到最新版本。此外,也要密切关注相关项目的安全公告,及时修复已知的安全漏洞。
四、总结
综上所述,Java反序列化漏洞的防范是一个系统性工程,既需要源代码审计的支持,也需要黑盒测试的能力。此外,在运行时环境中,通过对ObjectInputStream
和Runtime.exec
的限制,也能大大降低反序列化漏洞的危害。为了应对这一挑战,建议在项目部署前,采取综合性的防护措施。
转载地址:http://eiryk.baihongyu.com/