
Freeze.rs ist ein Payload-Toolkit zum Umgehen von EDRs mithilfe angehaltener Prozesse und direkter Syscalls, geschrieben in RUST.
Um die neueste Version von Freeze.rs anzusehen oder ein Problem zu melden, siehe https://github.com/Tylous/Freeze.rs.
Wenn Sie mehr über die in diesem Framework verwendeten Techniken erfahren möchten, werfen Sie bitte einen Blick auf SourceZero Blog und das ursprüngliche Tool.
Freeze.rs ist ein Tool zur Erstellung von Payloads, das dazu dient, EDR-Sicherheitskontrollen zu umgehen, um Shellcode auf eine verdeckte Weise auszuführen. Freeze.rs nutzt mehrere Techniken, um nicht nur Userland-EDR-Hooks zu entfernen, sondern auch Shellcode so auszuführen, dass andere Endpunkt-Überwachungskontrollen umgangen werden.
Wenn ein Prozess erstellt wird, wird Ntdll.dll als erste DLL geladen; dies geschieht bevor irgendwelche EDR-DLLs geladen werden. Das bedeutet, dass es eine kleine Verzögerung gibt, bevor eine EDR geladen werden kann und beginnt, die Assembly von System-DLLs zu hooken und zu modifizieren. Bei der Betrachtung von Windows-Syscalls in Ntdll.dll können wir sehen, dass noch nichts gehooked ist. Wenn wir einen Prozess in einem angehaltenen Zustand erstellen (einen, der in der Zeit eingefroren ist), können wir sehen, dass keine anderen DLLs geladen sind, außer Ntdll.dll. Sie können auch sehen, dass keine EDR-DLLs geladen sind, was bedeutet, dass die in Ntdll.dll befindlichen Syscalls unverändert sind.
Um diesen sauberen angehaltenen Prozess zu verwenden, um Hooks aus dem Freeze.rs-Loader zu entfernen, benötigen wir eine Möglichkeit, programmatisch den Speicher des sauberen angehaltenen Prozesses zu finden und zu lesen. Hier kommt die Address Space Layout Randomization (ASLR) ins Spiel. ASLR ist ein Sicherheitsmechanismus, der auf Stack-Speicher-Korruptions-Schwachstellen basierende Angriffe verhindern soll. ASLR randomisiert den Adressraum innerhalb eines Prozesses, um sicherzustellen, dass alle speichergemappten Objekte, der Stack, der Heap und das ausführbare Programm selbst einzigartig sind. Nun wird es interessant, denn während ASLR funktioniert, funktioniert es nicht für positionsunabhängigen Code wie DLLs. Was bei DLLs (insbesondere bekannten System-DLLs) passiert, ist, dass der Adressraum einmal beim Booten randomisiert wird. Das bedeutet, dass wir keine Informationen eines entfernten Prozesses auflisten müssen, um die Basisadresse seiner ntdll.dll zu finden, da sie in allen Prozessen gleich ist, einschließlich desjenigen, den wir kontrollieren. Da die Adresse jeder DLL pro Bootvorgang an derselben Stelle liegt, können wir diese Informationen aus unserem eigenen Prozess abrufen und müssen niemals den angehaltenen Prozess auflisten, um die Adresse zu finden.
Mit diesen Informationen können wir die API ReadProcessMemory verwenden, um den Speicher eines Prozesses zu lesen. Dieser API-Aufruf wird allgemein mit dem Lesen von LSASS im Rahmen von credential-basierten Angriffen assoziiert; er ist jedoch an sich nicht bösartig, insbesondere wenn wir nur einen beliebigen Speicherabschnitt lesen. Das einzige Mal, dass ReadProcessMemory als Teil von etwas Verdächtigem markiert wird, ist, wenn Sie etwas lesen, das Sie nicht sollten (wie die Inhalte von LSASS). EDR-Produkte sollten nie die Tatsache markieren, dass ReadProcessMemory aufgerufen wurde, da es legitime betriebliche Verwendungen für diese Funktion gibt und es zu vielen Fehlalarmen kommen würde.
Wir können dies noch einen Schritt weiterführen, indem wir nur einen Abschnitt von Ntdll.dll lesen, in dem alle Syscalls gespeichert sind – den .text-Abschnitt, anstatt die gesamte DLL zu lesen.
Durch die Kombination dieser Elemente können wir programmatisch eine Kopie des .text-Abschnitts von Ntdll.dll erhalten, um unseren vorhandenen gehookten .text-Abschnitt vor der Ausführung des Shellcodes zu überschreiben.
ETW nutzt integrierte Syscalls, um diese Telemetrie zu generieren. Da ETW auch eine native Funktion in Windows ist, müssen Sicherheitsprodukte die ETW-Syscalls nicht "hooking", um auf die Informationen zuzugreifen. Um ETW zu verhindern, patcht Freeze.rs daher zahlreiche ETW-Syscalls, leert die Register und gibt den Ausführungsfluss an die nächste Anweisung zurück. Das Patchen von ETW ist jetzt standardmäßig in allen Loadern enthalten.
Da nur Ntdll.dll wiederhergestellt ist, müssen alle nachfolgenden Aufrufe zur Ausführung von Shellcode in Ntdll.dll liegen. Mit Rusts NTAPI-Crate (beachten Sie, dass Sie dies auch in anderen Sprachen tun können, aber in Rust ist es ziemlich einfach zu implementieren) können wir die NT-Syscalls definieren und aufrufen, die zum Allokieren, Schreiben und Schützen des Shellcodes erforderlich sind, und effektiv die Standardaufrufe in Kernel32.dll und Kernelbase.dll überspringen, da diese möglicherweise noch gehooked sind.
Mit Rusts NTAPI-Crate können Sie sehen, dass all diese Aufrufe nicht unter ntdll.dll erscheinen, jedoch existieren sie immer noch innerhalb des Prozesses.
Als Ergebnis:
Dies begann als ein spaßiges Projekt, um Rust zu lernen, und ist zu einem eigenen Framework herangewachsen.
Freeze.rs wurde in Rust entwickelt.
Wenn Rust und Rustup nicht installiert sind, installieren Sie sie bitte. Wenn Sie es von OSX oder Linux aus kompilieren, stellen Sie sicher, dass Sie das Ziel "x86_64-pc-windows-gnu" hinzugefügt haben. Führen Sie dazu den folgenden Befehl aus:
rustup target add x86_64-pc-windows-gnu
Danach können Sie Freeze.rs kompilieren, indem Sie die folgenden Befehle ausführen, oder die kompilierte Binärdatei verwenden:
cargo build --release
Die kompilierte Version befindet sich dann in target/release (beachten Sie: Wenn Sie --release nicht angeben, befindet sich die Datei in target/debug/)
___________
\_ _____/______ ____ ____ ________ ____ _______ ______
| __) \_ __ \_/ __ \_/ __ \\___ // __ \ \_ __ \/ ___/
| \ | | \/\ ___/\ ___/ / /\ ___/ | | \/\___ \
\___ / |__| \___ >\___ >_____ \\___ > /\ |__| /____ >
\/ \/ \/ \/ \/ \/ \/
(@Tyl0us)
Soon they will learn that revenge is a dish... best served COLD & Rusty...
USAGE:
Freeze-rs [FLAGS] [OPTIONS]
FLAGS:
-c, --console Nur für Binär-Payloads – Erzeugt ausführliche Konsoleninformationen, wenn der Payload ausgeführt wird. Dies deaktiviert die Funktion zum versteckten Fenster.
-h, --help Zeigt Hilfeinformationen an
-n, --noetw Deaktiviert das ETW-Patching, das verhindert, dass ETW-Ereignisse generiert werden.
-s, --sandbox Aktiviert Sandbox-Umgehung durch Überprüfung:
Ist der Endpunkt einer Domäne beigetreten?
Hat der Endpunkt mehr als 2 CPUs?
Hat der Endpunkt mehr als 4 GB RAM?
-V, --version Zeigt Versionsinformationen an
OPTIONS:
-E, --Encrypt <ENCRYPT> Verschlüsselt den Shellcode entweder mit AES 256, ELZMA oder RC4-Verschlüsselung
-I, --Input <INPUT> Pfad zum rohen 64-Bit-Shellcode.
-O, --Output <OUTPUT> Name der Ausgabedatei (z. B. loader.exe oder loader.dll). Abhängig von der angegebenen Dateierweiterung wird festgelegt, ob Freeze eine DLL oder eine EXE erstellt.
-p, --process <PROCESS> Der Name des zu erzeugenden Prozesses. Dieser Prozess muss in C:\Windows\System32\ existieren. Beispiel 'notepad.exe'
-e, --export <export> Definiert einen benutzerdefinierten Exportfunktionsnamen für jede DLL.
Freeze.rs kann entweder eine .exe- oder eine .dll-Datei erzeugen. Um dies anzugeben, stellen Sie sicher, dass die Befehlszeilenoption -O entweder mit .exe für Binärdateien oder mit .dll für DLLs endet. Andere Dateitypen werden derzeit nicht unterstützt. Im Falle von DLL-Dateien kann Freeze.rs auch zusätzliche Exportfunktionalität hinzufügen. Verwenden Sie dazu -export mit einem bestimmten Exportfunktionsnamen.
Die Verschlüsselung von Shellcode ist eine wichtige Technik, um ihn vor der Erkennung und Analyse durch EDRs und andere Sicherheitsprodukte zu schützen. Freeze.rs bietet mehrere Methoden zur Verschlüsselung von Shellcode, darunter AES, ELZMA und RC4.
AES (Advanced Encryption Standard) ist ein symmetrischer Verschlüsselungsalgorithmus, der weit verbreitet zur Verschlüsselung von Daten verwendet wird. Freeze.rs verwendet AES mit 256-Bit-Schlüssellänge, um den Shellcode zu verschlüsseln. Der Vorteil der Verwendung von AES zur Verschlüsselung von Shellcode besteht darin, dass es eine starke Verschlüsselung bietet und von kryptografischen Bibliotheken weitgehend unterstützt wird. Allerdings kann die Verwendung einer festen Blockgröße es anfällig für bestimmte Angriffe machen, wie z.B. den Padding-Oracle-Angriff.
ELZMA ist ein Komprimierungs- und Verschlüsselungsalgorithmus, der häufig in Malware verwendet wird, um den Code zu verschleiern. Um Shellcode mit ELZMA zu verschlüsseln, wird der Shellcode zunächst mit dem ELZMA-Algorithmus komprimiert. Die komprimierten Daten werden dann mit einem zufälligen Schlüssel verschlüsselt. Die verschlüsselten Daten und der Schlüssel werden dann in den Exploit-Code eingebettet. Der Vorteil der Verwendung von ELZMA zur Verschlüsselung von Shellcode besteht darin, dass es sowohl Komprimierung als auch Verschlüsselung in einem einzigen Algorithmus bietet. Dies kann dazu beitragen, die Größe des Exploit-Codes zu reduzieren und ihn schwerer erkennbar zu machen.
RC4 ist ein symmetrischer Verschlüsselungsalgorithmus, der häufig in Malware zur Verschlüsselung von Shellcode verwendet wird. Es ist eine Stromchiffre, die Schlüssel variabler Länge verwenden kann und für ihre Einfachheit und Geschwindigkeit bekannt ist.
Freeze.rs nutzt eine Technik, bei der der Prozess zuerst erstellt und dann in den Hintergrund verschoben wird. Dies bewirkt zwei Dinge – erstens hilft es, den Prozess versteckt zu halten, und zweitens vermeidet es, von einem EDR-Produkt erkannt zu werden. Das sofortige Erzeugen eines Prozesses im Hintergrund kann sehr verdächtig sein und ein Indikator für Bösartigkeit sein. Freeze.rs tut dies, indem es die Windows-Funktionen 'GetConsoleWindow' und 'ShowWindow' aufruft, nachdem der Prozess erstellt und die EDR-Hooks geladen wurden, und dann die Fensterattribute auf versteckt ändert.
Wenn die Befehlszeilenoption -console ausgewählt wird, versteckt Freeze.rs den Prozess nicht im Hintergrund. Stattdessen fügt Freeze.rs mehrere Debug-Nachrichten hinzu, die anzeigen, was der Loader tut.