
Wenden Sie einen Teile-und-herrsche-Ansatz an, um EDRs zu umgehen.
Teile und herrsche ist ein Algorithmus, der in der Programmierung üblicherweise eingesetzt wird, um ein komplexes Problem zu lösen, indem man es in viele einfachere Teilprobleme zerlegt. Wir können diesen Ansatz auf die offensive Sicherheit mit einem anderen Ziel anwenden: EDRs zu verwirren, sodass sie den Überblick über unsere Aktivitäten verlieren und keine Warnung auslösen. Dies ähnelt dem, was man in letzter Zeit bei fast jeder Phishing-Kampagne in freier Wildbahn sieht: lange Infektionsketten, bei denen mehrere Dateien Schritt für Schritt ausgeführt werden (z.B. .url -> .one -> .js -> .bat -> .dll), anstatt direkt die endgültige Payload auszuführen. Jede der ausgeführten Dateien führt eine einfache Aufgabe aus (eine andere Datei herunterladen, eine Änderung in der Registrierung vornehmen, Dateien zwischen Verzeichnissen verschieben oder deren Namen/Erweiterungen ändern usw.), die für sich genommen schwer als bösartig einzustufen ist, und bereitet so die Umgebung für die endgültige Ausführung vor.
Ich habe beschlossen, diese einfache Idee zu testen, aber angewendet auf etwas anderes, in diesem Fall eine Remote-Process-Injection. Der Code in diesem Repository ist nichts Neues, im Gegenteil, es ist wahrscheinlich eine der gängigsten und einfachsten Möglichkeiten, einen Shellcode in einen entfernten Prozess zu injizieren: die Verwendung von NtOpenProcess, NtAllocateVirtualMemory, NtWriteVirtualMemory, NtProtectVirtualMemory und NtCreateThreadEx. Der einzige Unterschied besteht darin, dass ich den Prozess nach jedem dieser Aufrufe mit NtCreateUserProcess forke. Da der geforkte Prozess die Ausführung ab RIP + 1 fortsetzt und der Speicher vollständig vom Elternprozess kopiert wird, können wir die Remote-Process-Injection mit 5 verschiedenen Prozessen durchführen; wir müssen nur sicherstellen, dass alle für die nachfolgenden API-Aufrufe erforderlichen Handles ordnungsgemäß vererbt werden.
Auf diese Weise zerlegen wir die Shellcode-Injektion in einfachere Aufgaben und führen jede davon in einem getrennten Kontext (Prozess) aus.
Ich habe diesen PoC gegen drei der heutzutage gängigsten EDRs getestet: MDE, CrowdStrike und SentinelOne. Die Ergebnisse sprechen für sich: 2 von 3 EDRs lösten einen Remote-Process-Injection-Alarm aus, wenn der PoC ohne die Forks ausgeführt wurde; im Gegensatz dazu löste keiner von ihnen einen Alarm aus, sobald ich den Fork-Mechanismus einführte.
Natürlich können wir auch mit dem Fork-Mechanismus in der Roh-Telemetrie die Ereignisse sehen, die der Prozesserstellung, der Thread-Erstellung und auch dem gesamten prozessübergreifenden Verhalten entsprechen, aber es scheint nicht auszureichen, damit die EDRs die Aktivität als bösartig einstufen, was den Zweck dieses PoC beweist. Indem wir das bösartige Verhalten in einfachere Aufgaben aufteilen und jede davon aus einem anderen Prozess ausführen, können wir die EDRs verwirren und daran hindern, eine Warnung auszulösen.
Dieses gleiche Ergebnis könnte auf verschiedene Weise erzielt werden; ich habe den Fork-Mechanismus nur verwendet, um meinen Code zu vereinfachen und die prozessübergreifende Aktivität zu reduzieren.
Wenn du das selbst testen möchtest, kompiliere den Code mit und ohne die Aufrufe der Funktion fork() und führe dann beide Payloads in einer Umgebung mit dem gewünschten EDR aus.
Da wir das LITCRYPT-Plugin verwenden, um String-Literale zu verschleiern (nur für den Dinvoke_rs-Code), muss die Umgebungsvariable LITCRYPT_ENCRYPT_KEY vor dem Kompilieren des Codes gesetzt werden:
C:\Users\User\Desktop\Split> set LITCRYPT_ENCRYPT_KEY="yoursupersecretkey"
Danach einfach den Code kompilieren und das Tool ausführen:
C:\Users\User\Desktop\Split> cargo build --release
C:\Users\User\Desktop\Split\target\release> split.exe -h
Diese Technik reicht für sich allein nicht aus, um einen EDR zu umgehen; wenn dein Code überhaupt nicht opsec ist, wirst du sehr wahrscheinlich trotzdem erwischt. Das ist keine Wunderwaffe, sondern nur eine weitere Evasionsebene, die du deinen Tools hinzufügen kannst. Nichtsdestotrotz ist der hier präsentierte Code aus den folgenden Gründen u.a. überhaupt nicht opsec:
Andererseits habe ich diesen Ansatz nur gegen die genannten EDRs getestet, und ich weiß nicht, ob auch andere EDRs umgangen werden. Du kannst es testen und mir sagen, wie es gelaufen ist ;)