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

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

阻止下一个Log4j

注:这篇博文是之前发表在Dark Reading上

软件测试是出了名的困难。谷歌搜索cve引起的基本CRLF(换行字符)问题,你会看到成千上万的条目。人类已经能够把人送上月球,但还没有找到一种合适的方法来处理文本文件中的行尾。正是这些微妙的角落用例很容易被程序员忽视。

Log4j固有的复杂性将这一挑战提升到了一个新的高度。的Log4Shell脆弱性(CVE-2021-44228)自2013年以来一直没有引起注意。在Log4Shell漏洞以零日漏洞的形式暴露给整个行业之前,我们可以使用哪些工具来成功发现它?期望这种自动检测现实吗安全漏洞当他们还不为人知的时候?如果是这样,那么像Log4j这样经过严格测试的模块是如何躲过所有防线的呢?

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

零日漏洞检测挑战

由于每个人的后见之明都是20/20,所以现在很清楚,日志API函数最终将接收用户控制的数据,而JNDI注入是一个主要问题。然而,在发现Log4Shell之前,这两个事实都不那么明显。对于前一个事实,验证应用程序和库之间输入的责任分离没有很好地定义,并且攻击面的精确定义也不清楚。对于后者,尽管人们知道JNDI注射已经有几年了,但人们对其缺乏认识。

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

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


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

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

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

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

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

在本文的其余部分中,我们将说明现代过程间静态分析器在使用/不使用一组预定接收器分析Log4j时将面临的困难。

零日检测通过静态分析-更深的看

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

那么我们的分析器能做什么呢?它可以over-approximate。只要有危险的代码路径五月存在于你的代码中,你的代码将被声明为“危险的”。就像让你的前门整夜开着并不能保证有人会偷走你的智能电视一样,静态分析器也会给出类似于“最好把你的前门锁上”这样的话。

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

静态分析器固有的过度逼近使它们能够扩展到现实生活中的代码。想想循环。动态方法将不可避免地单独探索循环的后续迭代。这意味着要覆盖的状态数是无限的。简而言之,静态分析器可以总结循环的效果通过考虑0、1、2、…次迭代的效果结合

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

越来越多的公司在他们的开发周期中使用面向安全的静态分析。静态分析工具越来越多地在开发人员通过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