JAVA反序列化漏洞防御方法浅谈

      许多程序设计语言(如JAVA)允许用户将应用数据输出到磁盘上或者通过网络流传输,从而将应用数据转化成了另一种适合传输的格式(通常是二进制),这一过程叫序列化。反之,即读序列化的数据过程叫反序列化。 而漏洞发生在代码中接受从用户的序列化数据并且尝试在程序中反序列化并使用这些数据。这一个过程可以导致各种结果,包括远程代码执行。

      2015年影响最大的漏洞之一是Java反序列化漏洞。该漏洞已经被利用并攻击一些我们熟知的产品,例如Paypal, Cisco,产生了巨大的危害。 这些产品不仅影响应用程序(如JBoss,Jenkins)而且影响Android系统。更严重的是,直到目前,还没有有效的方法可以完全阻止这类漏洞攻击。

      本文先介绍JAVA反序列化漏洞,再介绍一些可能的防御方法以及这些方法的缺陷。最后给出一个可能的防御方法。

      攻击简介:

      通过使用JVM序列化(java.jo.ObjectlnputStream), 攻击者可以传递类的实例(字节流可以触发某个在classpath上的类的安装)诱使readObject 方法执行系统命令(如getshell)。一旦getshell, 攻击者可以任意修改Java服务器。这一类攻击叫“反序列化未授信的数据(desearization of untrusted data)”(CWE-502)。类似的漏洞也在Python, PHP以及Rails中发现。
QQ图片20161124191238.png

QQ图片20161124191303.png
     Marshalling Pickles指出应用服务器通常会打开RMI或者JMX端口。攻击者通过这些端口可以攻击JVM。而提出的解决方案是找出应用服务器所有commons-collections的jar包,并删除它们。问题是,不仅仅common-collection会引发java反序列化。ysoserial tool指出JVM 其他4种序列化的使用。而Matthias Kaiser更是指出有更多的java序列化攻击将会产生。因此单纯的删除common-collection jar包不能彻底解决这个问题。

现有的解决方法以及不足

一、隔离

     在数据中心中,仅将管理端口对外开放是非常危险的,事实上JMX和RMI是为数据中心内部设计的,是不应该对外开放。从这个角度,防御者也许会觉得网络隔离,沙箱,容器,虚拟机可以创建安全的数据中心,从而阻止攻击者直接获得访问端口的权限。然而这种内外网隔离的思路就像防火墙,仅仅阻止了攻击者的一个攻击通道而已。成千上万的其他的攻击通道仍然向攻击者打开。

  • 他们可能会使用后门,从一个内网不安全的个人机入手,用钓鱼邮件来诱使使用者下载恶意代码。

  • 他们也可以从物理位置上潜入,通过wifi, USB来入侵内网。



二、信息验证和加密

       通信加密SSL/TLS也不能防御。SSL/TLS可以防御从外网发动的“中间人”攻击,因为攻击这没有私钥破解TLS会话。然而攻击者可能在内网,SSL/TLS就无能为力了。加密以及数字签名的组合防御方法也无法阻挡从内网发动的攻击。同样的道理,混淆也不是一个解决办法,因为被攻击的主机会对混淆的数据最终做“解混淆”。


三、输入验证

       所有从I/O读取的数据都是不可信的(文件可以被窜改,网络输入也可以被改写)。序列化的数据是从I/O读取的,一种保护的方法也许是对输入进行验证。然而序列化的逻辑非常复杂,“在反序列化过程中对输入进行检查是非常困难的”,不仅CERT guide没有做到,Josh Bloch也没有做到。有人会说可以采用白名单,即在ObjectInputStream.resolveClass里面对可以序列化的对象做**。然而白名单的缺点是:

  • 很难全面的列出所有的类;

  • whitelist只能防止未知类被调用,但不能防止已知的有弱点的类被反序列化。Wouter Coekaerts使用嵌套的已知的HashSets(在白名单中)产生反序列化攻击,造成了拒绝服务。



四、开发代码安全

       从开发角度,可以有多种缓解JAVA反序列化的方法,可以禁掉RMI以及JMX的端口,或者可以借助JVM agent解决办法(如Tapiki或者HypericSigar), 甚至可以安装Jolokia或者jmxtrans来试图减少攻击面。接下来,可以借助JSON或者其他独立的二进制协议(如Protocol Buffers/Capn Proto/Thrift/Avro). 最后开发会仔细阅读 安全代码指南,避免代码中可能出现的序列化漏洞。 然而问题是无论如何保证自己的代码编写安全规范,也不能**第三方库中会有序列化漏洞。GitHub显示所有公开项目中大约有67万个ObjectInputStream的实例。即使你对代码进行全面的扫描,并且证实ObjectInputStream.readObject没有在你的代码里调用,仍然有被攻击的风险。如果代码依赖reflection, 那么你仍然可能面临ObjectInputStream被实例化的可能。


五、SecurityManager保护

       JVM有SecurityManager保护。然而SecurityManager只能**实现ObjectInputStream的子类。因此只能保护那些自定义的ObjectInputStream子类,第三方库调用ObjectInputStream是不能受到保护的。



推荐安全防护策略
        安全策略大致有三方面。

  • 禁止JVM使用序列化功能。
  • 如果不能禁止,则是使用白名单的notsoerial,并且记录序列化,确保网络通信使用TLS客户证书。此外,可以让运维团队使用Burp Suite来识别网络中的Java序列化。
  • 对要用到第三方库,并且该库使用ObjectInputStream的,可以利用ValidatingObjectInputSream或者SerialKiller替换ObjectInputStream。




云锁-服务器安全首选软件,一键查杀木马、病毒、后门,一键修复系统漏洞,实时监控系统性能,高效抵御CC等黑客攻击
发表于 2016-11-24 19:15:40 | 显示全部楼层 |阅读模式

回复 | 使用道具 举报

该帖共收到 1 条回复!
了解了mmm
发表于 2017-7-27 14:04:34 | 显示全部楼层

回复 | 使用道具 举报

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

本版积分规则

发布主题

QQ|论坛首页|站点统计|小黑屋|云锁论坛-服务器安全技术讨论专业论坛、云锁软件技术讨论 ( 京ICP备14002707号-3  

GMT+8, 2017-10-20 11:08 , Processed in 2.150689 second(s), 34 queries .

Powered by 云锁

© 2014-2018 JOWTO Inc.

快速回复 返回顶部 返回列表