如何防止下一个Log4j风格的零日漏洞

来自JFrog安全研究团队关于如何检测和防止代码中未知安全漏洞的高级见解

防止下一个Log4j

注:这篇博客文章是之前发表在《黑暗阅读》上

软件测试是出了名的难。搜索谷歌,查找由basic引起的cveCRLF(换行符)问题,你会看到成千上万的条目.人类已经能够把人送上月球,但还没有找到一种适当的方法来处理文本文件中的行尾。正是那些微妙的极端情况很容易被程序员忽视。

Log4j固有的复杂性将这一挑战提升到了一个新的水平。的Log4Shell脆弱性(CVE-2021-44228)自2013年以来一直没有引起注意。在Log4Shell漏洞作为零日漏洞被曝光之前,可以使用哪些工具成功地发现它?期望自动检测这种情况现实吗安全漏洞当他们还是未知的时候?如果是这样,那么像Log4j这样经过大量测试的模块是如何逃脱所有防线的呢?

注意,这是一个比以下问题更难回答的问题:我如何在我的代码库中检测和修补已知的易受攻击的Log4j版本(在过去的几周里,这个问题已经得到了广泛的讨论,本文将不再赘述)。

零日漏洞检测挑战

由于每个人都是事后诸觉,现在很清楚的一点是,日志API函数最终将接收用户控制的数据,而JNDI注入是一个主要问题。然而,在发现Log4Shell之前,这两个事实都不是那么明显。对于前一种情况,应用程序和库之间验证输入的责任分离没有很好地定义,攻击面的精确定义也不清楚。对于后者,尽管JNDI注入在几年前就已经为人所知¹˒²,但人们还没有意识到这一点。

因此,检测CVE-2021-44228(或其他类似漏洞)的最大障碍可能是模糊性。对于哪些值可以信任或不可以信任,以及哪些操作可以或不可以对这些值进行操作,并没有绝对和完整的定义。在实践中,任何分析都将依赖于对这些灰色区域的解释。

当需求模糊时,开发人员会发现自己处于不利地位。面向安全的代码审查试图检查大型软件模块的行为是否有“任何错误”,这是一项艰巨的任务。审查人员倾向于寻找局部错误,因为掌握被几十个函数调用分隔开的程序不同部分之间的关系是不可行的。与此形成鲜明对比的是,对于试图利用代码中怀疑存在的“特定”漏洞的攻击者来说,任务要容易得多。


直接从我们的安全研究团队了解有关Log4j漏洞的所有信息!
观看Log4shell点播网络研讨会

自动零日漏洞检测-它能工作吗?

Fuzzing是一种有效的动态分析技术,通过在随机(或伪随机)输入上执行程序并寻找崩溃或违反某些断言的实例来识别未知漏洞。在这种情况下,模糊会有帮助吗?

模糊通常意味着寻找表明内存损坏的崩溃。在内存安全的Java上下文中,崩溃通常不会有严重的安全影响。对于有意义的模糊,需要在特定的逻辑条件上定制钩子,以指示有问题的行为。此外,还需要构造一个提供输入(在我们的例子中是Log4j API函数)的模糊工具。这两种构造都可能需要一些手工工作。在此设置后,绒毛可以使用为了检测这个错误,甚至是其他软件中的类似错误(前提是所需的钩子和控制足够相似)。然而,在手工代码审查的情况下,需求的模糊性和与尝试不同假设相关的手工工作很可能会导致在模糊测试中忽略这个问题。

这就引出了我们的最后一个主题,静态分析,它在不实际执行程序的情况下检查程序可能的行为。静态分析的一种特别有趣的形式是数据流分析-跟踪数据在程序中的可能路径,从数据源开始,到达数据接收器。在讨论的案例中,从Log4j API函数参数开始并到达JNDI查找的数据路径的存在表明存在可利用的漏洞。

在这篇文章的剩余部分,我们将说明现代过程间静态分析器在分析Log4j时有或没有一组预定接收器时所面临的困难。

通过静态分析的零日检测-更深层次的观察

请看下面的代码片段示例(取自log4j-2.14.1-core).当LogEvente在它的一个字段中包含用户控制的字符串,它向静态分析器发出信号,表示应该进一步跟踪e。检查虚拟调用(appender.append (e))揭示了Appender接口有超过20种实现。静态分析器如何确定使用的是哪个实现?它没有!它不能。根据著名的停止的问题,静态地确定在运行时将实际采用哪条代码路径实际上是不可行的

那么我们的分析器能做什么呢?它可以over-approximate.每当危险的代码路径五月存在于您的代码中,您的代码将被声明为“危险”。就像开着前门过夜并不能保证有人会偷你的智能电视一样,静态分析仪会说一些相当于:“最好把前门锁上”的话。

附录;//接口私有无效tryCallAppender(final LogEvent e){尝试{appender.append(e);} catch(最终的RuntimeException错误){…

静态分析器固有的过度近似是允许它们伸缩的原因现实生活中的代码.想想循环。动态方法将不可避免地单独探索循环的后续迭代。这意味着要覆盖的状态数是无限的。简而言之,静态分析器可以总结一个循环的效果通过考虑0、1、2、…迭代的影响结合

那么静态分析器的缺点是什么呢?缺乏精确性,换句话说,就是假阳性。由于静态分析器将许多代码路径的效果组合在一起,包括不可行的,主要的问题是用户在他们的包中面临着无数被声明为“危险”的伪代码路径。这与动态方法的精确、可重构输出相反,动态方法能够精确定位错误的确切位置。

越来越多的公司在开发周期中使用面向安全的静态分析。静态分析工具越来越多地为开发人员通过IDE集成编写代码提供指导。然而,由于上面描述的挑战,大多数现有工具在没有适当的接收器定义的情况下将“拒绝”执行数据路径分析。在许多方面,这些工具是绝对正确的。甚至一组明确的预定义接收器,有无数的假阳性,所以想象一下会发生什么没有他们。

我们建议业界应该转向一种更具“交互性”的静态分析仪类型。想象一下,有一种工具可以在开发人员编写代码时向他们提供关于用户输入的潜在风险的信息。例如,它标记来自用户控制输入的数据流,而不考虑预定义的接收器,并提供受污染的用户控制输入的可视化指导,而不是确定的目的地。人们可以想到一个IDE,它用红色粗体字体显示可能来自攻击者的字符串,让程序员可以在这些“数据流提示”看起来可疑时检查它们。进一步扩展这个想法,程序员可以选择放大某些代码区域并定义它们自己的(内部,非API)源。这种灵活的方法可能会改变零日漏洞检测的游戏规则。


预定x射线安全工具的演示!
预约演示

结论

总而言之,数据流静态分析承诺使开发人员能够在早期识别涉及受操纵的用户输入(如Log4Shell)的漏洞。如今数据流分析是一个活跃的领域安全研究;将此技术广泛应用于开发工具中,并作为开发工具的一部分DevSecOps过程应该是一个行业目标。

虽然用户控制的入口点的定义通常可以通过程序的API来实现,但定义使用用户控制输入的危险代码接收器则比较棘手。对于零日漏洞检测来说更是如此。记住这个重要的概念:开发人员并不总是知道要寻找什么安全警告信号。但是,有一个自动的“同伴”,把它的虚拟手指放在用户控制的输入上,这显然是有帮助的。为了实现这一点,我们提倡以“左移”静态分析插件的形式支持交互式IDE。

¹https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf
²https://www.veracode.com/blog/research/exploiting-jndi-injections-java
³http://bodden.de/pubs/nal+17jit.pdf