现代软件应用程序是由数以千计的从公共资源库中获取的第三方组件拼接而成的。这种代码的重用对软件行业有很大的好处,它减少了开发时间和成本,使开发人员能够更快地增加功能,但由于复杂的依赖关系系统往往难以跟踪,它也产生了重大的漏洞管理问题。
继承自第三方代码的漏洞多年来一直困扰着应用程序,但在政府赞助的软件供应链攻击时代,这个问题比以往任何时候都更有意义。软件组合分析工具可以帮助发现其中的一些风险,但微妙的依赖性盲点仍然存在,即使是有安全意识的开发人员也很难抓住所有继承的缺陷。
来自ReversingLabs的安全研究人员最近对NuGet仓库进行了扫描,发现有5万个软件包正在使用一个名为zlib的流行库的过时和脆弱版本。他们中的许多人没有明确地把它列为依赖关系。
依赖性跟踪是一针见血的
为了发现所有的漏洞,开发人员不仅需要跟踪他们在自己的应用程序中使用的组件,还需要跟踪这些组件所基于的第三方库和包。依赖关系链可以深入很多层。达姆施塔特大学的研究人员在2019年对npm资源库进行的分析发现,平均来说,导入一个JavaScript包会对39个不同维护者的79个其他包引入隐性信任。当时,研究人员还发现,近40%的软件包依赖的代码至少有一个公开的漏洞。
一个问题是,只有与同一存储库上的软件包有关的依赖关系才会被软件包存储库及其相应的软件包管理工具所追踪。但这并不是第三方代码进入项目的唯一途径。一些开发者静态链接库或手动编译来自其他项目的代码,这些代码存在于软件包库之外,这些信息不容易用自动扫描工具找到。
ReversingLabs发现超过50个NuGet软件包包含主动利用的漏洞,因为它们捆绑了过时的和脆弱的7Zip、WinSCP和PuTTYgen版本。这些都是流行的压缩或网络连接程序,它们不直接托管在NuGet上,但可能有其他开发者在NuGet上为它们创建的包装包。
NuGet是.NET编程语言的主要仓库,那里托管的大多数组件都是以ZIP档案的形式发送,扩展名为.nupkg,包含预编译的Windows .DLL库,旨在导入其他软件项目中。
ReversingLabs发现的一个易受攻击的NuGet包名为WinSCPHelper,是WinSCP的一个封装库。它允许集成它的应用程序通过SFTP协议管理远程服务器上的文件。WinSCPHelper自2017年以来没有在NuGet上更新过,但最后一个版本自发布以来被下载了超过34000次,在过去6周内被下载了约700次。最新的WinSCP版本是5.17.10,包含一个关键的远程代码执行漏洞的补丁,但与WinSCPHelper捆绑的版本是一个更老的版本--5.11.2。
"虽然在这种情况下,被分析的软件包明确指出它使用了WinSCP,但它没有在依赖列表中披露版本,你不能轻易发现哪些漏洞影响了它的基础依赖,"研究人员说。"这是手工作业,仍然可以做到,但需要一些努力"。
识别无声的漏洞
但追踪依赖关系可能比这更难。以zlib为例,它是最广泛使用的开源数据压缩库之一,最初写于1995年。这个库几乎已经成为事实上的标准,并由其维护者作为源代码提供。这意味着开发人员倾向于自己编译它,并在他们的项目中静态地链接它,由于它是如此无处不在,所以常常不提它的存在。
通过静态文件分析,ReversingLabs发现超过5万个NuGet软件包使用zlib 1.2.8版本,该版本发布于2013年,包含四个高度或严重的漏洞。一些被识别的软件包通过其他没有明确列出依赖关系的第三方组件继承了这个旧的zlib版本和它的漏洞,促使研究人员把这些称为沉默的漏洞。
ReversingLabs提供的一个例子是一个名为DicomObjects的NuGet包,它实现了医学中的数字成像和通信(DICOM)协议。DICOM是一个用于传输和管理医学成像数据的标准。它在医院中被广泛使用,并被许多成像设备支持,如医疗扫描仪、打印机、服务器和工作站。
DicomObjects被医疗软件开发者用来轻松构建DICOM解决方案,它有近54000次下载,由一家名为Medical Connections的英国公司维护。该软件包将Microsoft.AspNet.WebApi.Client、Newtonsoft.Json和System.Net.Http列为依赖项,但据ReversingLabs称,它还捆绑了一个名为ceTe.DynamicPDF.Viewer.40.x86.dll的商业PDF库,但没有明确提及。DynamicPDF Viewer在NuGet上被列为一个单独的软件包,但DicomObjects中捆绑的版本是一个更老的版本,包括zlib 1.2.8。
"这是最常见的软件维护问题之一,"研究人员说。"开发者创建了一个软件包,决定使用第三方软件,但在随后的更新过程中,依赖性被忽略了。在这种情况下,事情就更糟糕了,因为任何地方都没有明确提到DicomObjects软件包依赖于DynamicPDF.Viewer。我们没有办法知道DynamicPDF.Viewer依赖于有漏洞的zlib库。以这种方式堆叠隐藏的依赖关系会导致多层次的无声漏洞,并使软件维护和审计的难度大大增加"。
Medical Connections没有立即回应评论请求。
另一个例子是一个叫做librdkafka.redist的高度流行的软件包,这是一个实现Apache Kafka协议的C库。Apache Kafka是一个开源的高性能流处理框架,用于处理实时数据传输。librdkafka.redist包有1890万次下载,其中312000次是2个月前发布的最新版本1.7.0。这个版本的librdkafka.redist使用zlib 1.2.8,但在NuGet或GitHub的项目依赖列表中没有明确说明。
这个问题在一年多以前就被报告在GitHub上的项目bug追踪器上,目前被标记为要在1.8.0版本中修复。该项目首席开发者Magnus Edenhill审查了这四个zlib漏洞,并表示其中只有两个适用于librdkafka,通过Kafka消耗的消息成功利用这些漏洞的风险似乎非常低。Edenhill没有立即回应评论请求。
其他13个NuGet软件包依赖于librdkafka.redist,包括一些由一家名为Confluent的数据基础设施公司开发的软件包,该公司拥有许多大型企业客户。
"安全软件开发是一个复杂的问题,因为它涉及到开发的多个阶段的许多参与者,"ReversingLabs的研究人员说。"无论你的公司生产什么类型的软件,迟早都需要将第三方的依赖关系纳入你的解决方案。这将引入管理安全和代码质量风险的需要。软件供应链攻击对网络社区的威胁越来越大。它们是传统漏洞的DDoS类似物"。
供应链风险
NuGet并不是唯一存在这种脆弱依赖问题的软件包库,人们可以说,不是由NuGet或其他库来迫使开发者更关注这些问题。然而,有些平台比其他平台更积极主动。GitHub积极扫描其平台上托管的公共代码库,分析它们的依赖关系,如果这些依赖关系中有任何已知的漏洞,就通知其所有者。该公司维护一个公共咨询数据库,其中包括npm(JavaScript)、RubyGems(Ruby)、NuGet(.NET)、pip(Python)、Maven(Java)的已知漏洞,并刚刚宣布支持Go模块。
开源治理公司Sonatype在其《2020年软件供应链报告》中指出,下一代攻击的数量同比增长了430%,黑客试图主动向开源软件项目注入恶意软件,试图毒害其依赖链上的更多项目和应用程序。黑客利用开源组件中的已知漏洞的传统攻击仍然强劲,但利用的时间已经减少,攻击者在公开披露的几天内就利用了新发现的漏洞。同时,有一半的公司需要一周以上的时间来了解这些漏洞,并在一周或更长时间后将缓解措施落实到位。
攻击者显然对利用软件供应链很感兴趣,但成千上万的具有继承性漏洞的软件包仍在公共资源库中,并作为企业软件的基础模块。