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

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

防止下一个Log4j

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

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

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

请注意,这个问题比以下问题更难回答:如何在我的代码库中检测和修补已知的Log4j脆弱版本(这个问题在过去几周被广泛讨论,在本文中不再赘述)。

零日漏洞检测挑战

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

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

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


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

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

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

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

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

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

静态分析中的零日检测——更深入的探索

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

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

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

静态分析器固有的过近似值使得它们可以扩展到现实生活中代码.认为循环。动态方法将不可避免地分别探索循环的后续迭代。这字面上意味着要覆盖的状态数量是无限的。简而言之,静态分析器将会总结循环的效果通过考虑0、1、2、…迭代的影响结合

那么静态分析器的缺点是什么呢?缺乏准确性,或者换句话说,假阳性。由于静态分析器将许多代码路径的效果组合在一起,包括non-feasible的,主要的问题是,用户在他们的包上面临无数被声明为“危险”的虚假代码路径。这与动态方法的精确、可重构输出形成了鲜明的对比,动态方法能够精确定位错误的确切位置。

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