RePR - LastPyMile: Identifying the Discrepancy between Sources and Packages
原文作者:Duc-Ly Vu, Fabio Massacci, Ivan Pashchenko, Henrik Plate
原文标题:LastPyMile: Identifying the Discrepancy between Sources and Packages
原文来源:ESEC/FSE 2021
笔记作者:outx
好论文再读再品又是另一些发现 - 220223
0x00 Intro
通常情况下开源的软件包会在其对应的存储库上提供源代码,但开发者往往更倾向于使用集成式的包管理器来使用这些开源软件包(PyPI对应的pip)。这种方便的做法是假设源代码和软件包之间没有差异的,这会带来一定的安全风险。作者提出并实现了一种方法,名为LastPyMile,主要用于识别软件包的构造和其源代码库之间的差异,以防止恶意软件的注入。
0x01 Background
作者背调了目前软件供应链的情况,多达99%的代码库包含开源代码,85%到97%的企业代码库包含开源代码。正是因为开源代码的流行,方便了开发者根据具体情况基于其他开发者预先构建好的开源软件包进行自身软件构建。
通常来说,这些开源软件包的源代码和其实际包中的代码是没有任何差异的。但实际上,手动或自动构建工具,亦或是出于一些恶意目的,这两者之间是可能会存在着差异性的,如下表。可以看到正常软件包的发布版本相较于其源代码的变动是很小的,而恶意软件包则有很明显的误差。
作者通过调研PyPI生态,研究了一个PyPI包从开发、构建到发布和安全审查的过程,如下图所示。对于PyPI来说,其在软件包在上传过程中通常只会检查一个setup.py文件,但在真实世界中,能够注入恶意代码的地方远远不止setup.py文件。
但不论如何,代码注入攻击中,考虑到注入的隐蔽性,通常只会修改原本代码中的一小部分。这也是作者的研究聚焦点。
0x02 Method
RQ1: 是否存在一种方法能够有效地识别其中的差异性?
有一种现成的解决方案,即git log,但是想要拿到完整的信息需要遍历所有git日志中的修订,且在这个过程中每次调用都会产生一个进程,这无疑是增加了分析机器的负担。作者的解决办法则是通过巧妙地结合软件包和运行软件的所有必需项目的散列值,以一种可扩展的方式提取这些差异。
Answer
作者提出了一种方法用于解答这个问题,将其命名为LastPyMile,整体框架如下。
图的上半部分展示了包存储库(如PyPI)中安全审查的典型过程,主要是识别软件项目发布期间可能会出现的可疑组件。而在图的下半部分则展示了LastPyMile是如何增强传统安全审查过程的,具体步骤包括:
- 在预备过程中,LastPyMile会在各处收集PyPI包的Github链接,包括元数据、主页以及包内。
- 遍历该包Github代码库中所有历史commit,以计算所有文件的哈希值并收集代码库中文件行数。
- 在收集了Github代码库中所有文件的哈希值和行数后,对PyPI包进行拆解,计算其中组件哈希值并切收集文件行数。
- 对于PyPI包中组件哈希值和行数与代码库中文件哈希值和行数,以确定其差异性。
RQ2: 源代码和包存储库之间的“正常”差异有多大?
作者研究了PyPI生态中超过2000个流行的软件包,这种差异是普遍存在的。但在Python源文件中一般只会发生很少的修改,所以作者采用审查作为替代方案。
Answer
- 比较PyPI中的代码和相应的源代码库,平均有5.8%的运行时需要文件和2.6%的普通文件有差异。
作者提到了可疑APIs的调用,说不能简单地将调用定义为可疑,会产生大量告警。这里存疑,因为告警和漏报的平衡点实在是很难界定。不过作者给出了差异性最大的文件名,如下表。
RQ3: LastPyMile能否与软件包扫描器相结合,同时保持可控的警报数量?
Answer
为了在该领域发挥效力,应该允许开发者和开发组织使用相同的工具来扫描软件包的源代码库,作为其审查过程的一部分。结合LastPyMile可以显著降低现有检测软件的告警数量
0x03 Conclusion
作者调研了已发布的PyPI包和源代码库之间的差异性,以了解软件发布过程中恶意代码注入的安全风险。但作者表明这其中还是会有些问题,比如恶意代码还可以隐藏在网页、项目配置文件等其他位置,甚至是requirements.txt中。读者在读完这篇文章后也同样认为只考虑了py文件中的差异性其实是不够的,一旦攻击者提前上传一个恶意包,然后通过修改requirements.txt引入该恶意包便能轻松绕过这种检测方式,这里还需要深入研究PyPI包的安装和导入过程,制定更加全面的检测方法。