Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Nächste Überarbeitung
Vorhergehende Überarbeitung
it-security:blog:shellcode_injection-4 [2024/09/01 22:27] – angelegt psycoreit-security:blog:shellcode_injection-4 [2024/09/01 23:03] (aktuell) psycore
Zeile 8: Zeile 8:
 Folgende Anforderungen sollten hierbei erfüllt sein: Folgende Anforderungen sollten hierbei erfüllt sein:
  
-  * Start von ''%%calc.exe%%'' auf einem Windows Rechner+  * Start von ''calc.exe'' auf einem Windows Rechner
   * 64-Bit Code   * 64-Bit Code
   * Vermeiden von Null-Bytes   * Vermeiden von Null-Bytes
Zeile 16: Zeile 16:
 ==== Shellcode? Nichts leichter als das! ==== ==== Shellcode? Nichts leichter als das! ====
  
-Das dachte ich zumindest. Tatsächlich hat es einiges an Zeit gekostet die Funktionsweise zu verstehen. Dies lag zum Teil auch an fehlenden ''%%x64dbg%%'' Kenntnissen. Gerade das Live-Debugging hat sehr viel Zeit gekostet, da ich viele nützliche Befehle noch nicht kannte.+Das dachte ich zumindest. Tatsächlich hat es einiges an Zeit gekostet die Funktionsweise zu verstehen. Dies lag zum Teil auch an fehlenden ''x64dbg'' Kenntnissen. Gerade das Live-Debugging hat sehr viel Zeit gekostet, da ich viele nützliche Befehle noch nicht kannte.
  
-Zum Glück gibt es eine hilfreiche Webseite, welche ich gerne als Referenz genutzt habe.((https:%%//%%help.x64dbg.com/en/latest/commands/index.html+Zum Glück gibt es eine hilfreiche Webseite, welche ich gerne als Referenz genutzt habe.((https://help.x64dbg.com/en/latest/commands/index.html
 )) ))
  
 ==== Hilfreiche Tools ==== ==== Hilfreiche Tools ====
  
-  * Microsoft Visual Studio((https:%%//%%visualstudio.microsoft.com/de/downloads/)) +  * Microsoft Visual Studio((https://visualstudio.microsoft.com/de/downloads/)) 
-  * x64dbg((https:%%//%%x64dbg.com/)) +  * x64dbg((https://x64dbg.com/)) 
-  * PEView((http:%%//%%wjradburn.com/software/)) +  * PEView((http://wjradburn.com/software/)) 
-  * ShenCode((https:%%//%%github.com/psycore8/shencode))+  * ShenCode((https://github.com/psycore8/shencode))
  
 ==== Hilfreiche Webseiten ==== ==== Hilfreiche Webseiten ====
Zeile 38: Zeile 38:
 Den kompletten Code findet ihr auch auf [[https://github.com/psycore8/nosoc-shellcode/tree/main/nosoc-shellcode-4|Github]]. Den kompletten Code findet ihr auch auf [[https://github.com/psycore8/nosoc-shellcode/tree/main/nosoc-shellcode-4|Github]].
  
-Welche Schritte sind nun nötig, um ''%%calc.exe%%'' aus einem Shellcode zu starten?+Welche Schritte sind nun nötig, um ''calc.exe'' aus einem Shellcode zu starten?
  
-  - ''%%kernel32.dll%%'' Basis Adresse finden +  - ''kernel32.dll'' Basis Adresse finden 
-  - ''%%WinAPI%%'' im Speicher ermitteln +  - ''WinAPI'' im Speicher ermitteln 
-  - Funktion ''%%WinExec%%'' finden+  - Funktion ''WinExec'' finden
  
 ==== Variablen und Stack ==== ==== Variablen und Stack ====
Zeile 60: Zeile 60:
 </code> </code>
  
-Für den späteren Suchdurchlauf müssen wir den String ''%%WinExec\n%%'' auf den Stack pushen und die Zeigeradresse speichern.+Für den späteren Suchdurchlauf müssen wir den String ''WinExec\n'' auf den Stack pushen und die Zeigeradresse speichern.
  
 <code gdb> <code gdb>
Zeile 71: Zeile 71:
 ==== kernel32.dll Basis Adresse ==== ==== kernel32.dll Basis Adresse ====
  
-Mit jedem Start eines Prozesses in Windows, werden Module in diesen Prozess geladen. Eines dieser Module ist unsere ''%%kernel32.dll%%''. Im Arbeitsspeicher werden durch Windows Datenstrukturen angelegt, welche alle für uns nötigen Informationen bereit halten.+Mit jedem Start eines Prozesses in Windows, werden Module in diesen Prozess geladen. Eines dieser Module ist unsere ''kernel32.dll''. Im Arbeitsspeicher werden durch Windows Datenstrukturen angelegt, welche alle für uns nötigen Informationen bereit halten.
  
 Ähnlich wie in einem Buch, rufen wir ein Inhaltsverzeichnis (Pointer) auf, welches auf die richtige Seitenzahl (relevanter Speicherbereich) zeigt. Ähnlich wie in einem Buch, rufen wir ein Inhaltsverzeichnis (Pointer) auf, welches auf die richtige Seitenzahl (relevanter Speicherbereich) zeigt.
  
-Die erste dieser Strukturen ist der ''%%TEB%%'' (Thread Environment Block). Dieser beinhaltet einen Zeiger auf den ''%%PEB%%'' (Process Environment Block), welcher uns Auskunft über die geladenen Module gibt.+Die erste dieser Strukturen ist der ''TEB'' (Thread Environment Block). Dieser beinhaltet einen Zeiger auf den ''PEB'' (Process Environment Block), welcher uns Auskunft über die geladenen Module gibt.
  
-Den Zeiger zur ''%%PEB%%'' finden wir über das Register ''%%gs%%'' am Offset ''%%0x60%%'', sprich ab Byte 60. Wir laden nun die Speicheradresse in das Register ''%%rax%%''.+Den Zeiger zur ''PEB'' finden wir über das Register ''gs'' am Offset ''0x60'', sprich ab Byte 60. Wir laden nun die Speicheradresse in das Register ''rax''.
  
 <code gdb> <code gdb>
Zeile 83: Zeile 83:
 </code> </code>
  
-Jetzt befinden wir uns im ''%%PEB%%'' und navigieren durch den Speicherbereich:+Jetzt befinden wir uns im ''PEB'' und navigieren durch den Speicherbereich:
  
 <code> <code>
Zeile 106: Zeile 106:
 ==== WinAPI ==== ==== WinAPI ====
  
-Mit der ''%%kernel32%%'' Basis Adresse können wir die WinAPI suchen. Hierzu benötigen wir erneut ein paar Adressen:+Mit der ''kernel32'' Basis Adresse können wir die WinAPI suchen. Hierzu benötigen wir erneut ein paar Adressen:
  
 <code> <code>
Zeile 117: Zeile 117:
 </code> </code>
  
-Setzen wir dies nun in ''%%ASM%%'' um:+Setzen wir dies nun in ''ASM'' um:
  
 <code gdb> <code gdb>
Zeile 138: Zeile 138:
 </code> </code>
  
-[!NOTE] Tipp Öffnet die Datei ''%%%windir%\syswow64\kernel32.dll%%'' in PEView. So könnt ihr die gesuchten Speicherbereiche besser nachvollziehen.+<callout type="info" icon="true"> 
 +Öffnet die Datei ''windir\syswow64\kernel32.dll'' in PEView. So könnt ihr die gesuchten Speicherbereiche besser nachvollziehen. 
 +</callout>
  
 ==== WinExec ==== ==== WinExec ====
Zeile 144: Zeile 146:
 === Iteration === === Iteration ===
  
-Nun folgt eine Iteration, welche die Export-Funktionen solange abfragt, bis ''%%WinExec%%'' gefunden wurde oder die Anzahl der Funktionen durchlaufen ist:+Nun folgt eine Iteration, welche die Export-Funktionen solange abfragt, bis ''WinExec'' gefunden wurde oder die Anzahl der Funktionen durchlaufen ist:
  
 <code gdb> <code gdb>
Zeile 166: Zeile 168:
 === Funktion gefunden === === Funktion gefunden ===
  
-Wurde die Funktion gefunden, springt der Code zur ''%%WinExecFound%%''-Marke. Hier wird die reale, virtuelle Adresse der Funktion berechnet. Mit dieser sind wir schließlich in der Lage ''%%WinExec%%'' zu adressieren. Der Vorgang wird von [[https://www.ired.team/offensive-security/code-injection-process-injection/finding-kernel32-base-and-function-addresses-in-shellcode#finding-winexec-ordinal-number-1|Red Team Notes]] genauer beleuchtet.+Wurde die Funktion gefunden, springt der Code zur ''WinExecFound''-Marke. Hier wird die reale, virtuelle Adresse der Funktion berechnet. Mit dieser sind wir schließlich in der Lage ''WinExec'' zu adressieren. Der Vorgang wird von [[https://www.ired.team/offensive-security/code-injection-process-injection/finding-kernel32-base-and-function-addresses-in-shellcode#finding-winexec-ordinal-number-1|Red Team Notes]] genauer beleuchtet.
  
 <code gdb> <code gdb>
Zeile 180: Zeile 182:
 === WinExec ausführen === === WinExec ausführen ===
  
-Nun übergeben wir alle wichtigen Parameter an ''%%WinExec%%'' und rufen die Funktion anschließend auf. Ein Blick in die Funktionsdokumentation ist hierbei hilfreich.((https:%%//%%learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-winexec +Nun übergeben wir alle wichtigen Parameter an ''WinExec'' und rufen die Funktion anschließend auf. Ein Blick in die Funktionsdokumentation ist hierbei hilfreich.((https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-winexec))
-))+
  
 <code gdb> <code gdb>
Zeile 192: Zeile 193:
 Wir benötigen einen String für die Kommandozeile und einen Integer für die Anzeige des Fensters. Wir benötigen einen String für die Kommandozeile und einen Integer für die Anzeige des Fensters.
  
-Es gibt jedoch noch mehr Dinge zu beachten, wenn wir die WinAPI aufrufen.<sup>[https:%%//%%learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170]</sup>[https:%%//%%print3m.github.io/blog/x64-winapi-shellcoding#execute-winexec-function]+Es gibt jedoch noch mehr Dinge zu beachten, wenn wir die WinAPI aufrufen.((https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170))((https://print3m.github.io/blog/x64-winapi-shellcoding#execute-winexec-function))
  
-  * Argument Register (von links nach rechts): ''%%RCX (lpCmdLine), RDX (uCmdShow), R8, R9, Stack%%'' +  * Argument Register (von links nach rechts): ''RCX (lpCmdLine), RDX (uCmdShow), R8, R9, Stack'' 
-  * Der Stack muss auf 16 Bytes ausgerichtet werden: ''%%and rsp, -16%%'' +  * Der Stack muss auf 16 Bytes ausgerichtet werden: ''and rsp, -16'' 
-  * Shadow Space, ein leeres 32 Bytes Segment auf dem Stack, welches für interne WinAPI Zwecke benötigt wird: ''%%sub rsp, 32%%''+  * Shadow Space, ein leeres 32 Bytes Segment auf dem Stack, welches für interne WinAPI Zwecke benötigt wird: ''sub rsp, 32''
  
-Unseren string ''%%calc.exe%%'' übergeben wir wieder in umgekehrter Schreibweise an den Stack und anschließend füllen wir das untere Byte-Segment des ''%%RDX%%'' Registers mit dem Wert ''%%0x1%%'', was dem Wert ''%%SW_SHOWDEFAULT%%'' entspricht.+Unseren string ''calc.exe'' übergeben wir wieder in umgekehrter Schreibweise an den Stack und anschließend füllen wir das untere Byte-Segment des ''RDX'' Registers mit dem Wert ''0x1'', was dem Wert ''SW_SHOWDEFAULT'' entspricht.
  
-Dann erfüllen wir noch die WinAPI Aufrufkonventionen, wie oben beschrieben und können ''%%WinExec%%'' mit dem Befehl ''%%call rax%%'' aufrufen.+Dann erfüllen wir noch die WinAPI Aufrufkonventionen, wie oben beschrieben und können ''WinExec'' mit dem Befehl ''call rax'' aufrufen.
  
 <code gdb> <code gdb>
Zeile 238: Zeile 239:
 ==== WinExec Push ==== ==== WinExec Push ====
  
-Wir pushen ''%%WinExec\n%%'' auf den Stack. ''%%\n%%'' entspricht 0-Byte und wir müssen unseren Code anpassen. Wir ändern ''%%00%%'' im String auf ''%%11%%''. Nun können wir mit ''%%shl, shr%%'' den Inhalt des Registers nach Links bzw. Rechts verschieben. Alle Werte außerhalb werden gelöscht.+Wir pushen ''WinExec\n'' auf den Stack. ''\n'' entspricht 0-Byte und wir müssen unseren Code anpassen. Wir ändern ''00'' im String auf ''11''. Nun können wir mit ''shl, shr'' den Inhalt des Registers nach Links bzw. Rechts verschieben. Alle Werte außerhalb werden gelöscht.
  
 <code gdb> <code gdb>
Zeile 250: Zeile 251:
 ==== GS Register + 0x60 ==== ==== GS Register + 0x60 ====
  
-Die Anweisung ''%%mov rax, gs:[0x60]%%'' erzeugt ebenfalls 0-Bytes. Dies können wir umgehen, indem wir ''%%0x60%%'' einem niedrigerem Register zuordnen. Anschließend werden die Register addiert.+Die Anweisung ''mov rax, gs:[0x60]'' erzeugt ebenfalls 0-Bytes. Dies können wir umgehen, indem wir ''0x60'' einem niedrigerem Register zuordnen. Anschließend werden die Register addiert.
  
 <code gdb> <code gdb>
Zeile 280: Zeile 281:
 </code> </code>
  
-Der Befehl liefert uns die Datei in C-Format Syntax. Wir wissen, unser Shellcode beginnt mit den Opcodes ''%%55 48%%''. Diese finden sich ab Offset 60. Die letzten Anweisungen sind ''%%5D C3%%'' und dann befinden wir uns an Offset 310.+Der Befehl liefert uns die Datei in C-Format Syntax. Wir wissen, unser Shellcode beginnt mit den Opcodes ''55 48''. Diese finden sich ab Offset 60. Die letzten Anweisungen sind ''5D C3'' und dann befinden wir uns an Offset 310.
  
 <code shell> <code shell>