====String format==== Format string read napad iskorištava dinamiku funkcija s formatiranim stringovima i načina na koji se argumenti dodjeljuju tim funkcijama. Uzmimo naprimjer funkciju printf: printf(„Hello %s, nice to meet you!”, username); %s označava „placeholder” koji će printf ispuniti zadanim argumentom username i zatim ispisati rezultat. Interno, printf prati svaki format (npr. %s, %d, %x, %p ...) i očekuje da je svaki potkrijepljen dodatnim argumentom kako bi ga popunio. Npr. printf(„%s %s\n”, first_name, last_name) mora sadržavati 2 dodatna argumenta uz početni string (dakle first_name i last_name) kako bi ispravno radio. Ranjivost: Ako programer definira ispis varijable uz pomoć formatirane funkcije bez da zada ispravan broj argumenta, formatirana funkcija ne može razaznati radi li se o grešci ili ne zbog čega uzima argumente registara sačuvane na stogu ispod base pointera ili sa stoga iznad base pointera (argumenti 7 itd...) kako bi popunila zadane formate. Primjer: printf(„%p %p”); Ispisat će se sadržaji argumenata 2 i 3 (koji zapravo ne postoje, već će se uzeti s tih pozicija u memoriji: x64 konvencija, sami format string je sadržan unutar 1. argumenta) u formatu pointera: printf(format); //gdje je format definiran kao char *format = „%p %p” Ekvivalent gornjem primjeru, ispisat će se sadržaj u memoriji koji bi sadržavao argumente na 2 i 3 u formatu pointera. X64 konvencija na linuxu definira da se argumenti za funkcije nalaze redom: rdi, rsi, rdx, rcx, r8, r9 zatim stog (ako je potrebno više od 6 argumenata) prije poziva. Unutar funkcije registri koji sadrže argumente pushaju se na stog nakon lokalnih varijabli. Zbog toga format string read napad omogućava napadaču da čita proizvoljan broj podataka sa stoga ako je korisniku dopušteno definiranje format stringa. Maksimalan broj argumenata koje registri mogu sadržavati jest 6. RDI (prvi registar) sadrži sami format stringa („%p.%p....”). To znači da ako se unese veći broj formata od 5, formatirana funkcija uzme 5 argumenata iz preostalih pozicija u memoriji namijenjene za argumente te ostale argumente sa stoga koji prethode base pointeru. ====Kupon==== ===Opis zadatka:=== [[https://platforma.hacknite.hr/challenges#Kupon-115]] Jakov je napravio program za rezervaciju mjesta u svom restoranu. U programu je zapisao i kupon kod za besplatnu večeru. Jakov tvrdi da je trenutno nemoguće doći do njega, ali ako uspiješ smiješ ga iskoristiti. Spoji se na program uz pomoć naredbe telnet (ako koristiš Windows) ili naredbe netcat (ako koristiš Linux): telnet chal.platforma.hacknite.hr 12012 netcat chal.platforma.hacknite.hr 12012 ===Rješenje:=== Na liniji koja sadrži: printf(input) nalazi se ranjivost string format reada. Unutar polja kupon veličine 48 bajtova nalazi se flag. Dakle potrebno je ispisati vrijednost flag-a sa stoga uz pomoć string format reada. Zbog poretka definiranja varijabli kupon pa input, na samom stogu će na nižoj adresi biti polje kupon, a zatim polje input (ovo ponekad nije istina zbog optimizacije stoga, no u ovom slučaju poredak je sačuvan, za provjeru uvijek je moguće ručno pregledati stog uz pomoć gdb-a). To znači da će se nakon poziva nove funkcije polje kupon nalaziti na adresama iznad postavljenje return adrese te nove funkcije. Ta područja su u x64 calling konvenciji namijenjena argumentima 7 pa nadalje. Dakle, ako u polje input upišemo "%p.%p.%p.%p.%p.%p.%p.%p.%p.%p.%p" prvih 5 %p će ispisati memorije unutar printf funkcije namijenjene za argumente 2-6, a preostalih 6 %p će ispisati sadržaj cijelog polja kupon (jer mu je veličina 48 bajtova, a jedan pointer je veličine 8 bajtova). Nakon ispisa danih adresa od 6. pointera pa nadalje jest sadržaj polja kupon. Taj sadržaj je potrebno provući kroz hex converter u tekst i time će se dobiti sadržaj polja kupon. ----- Napomena 1: Zbog little endian zapisa, %p format očekuje da su na nižim adresama bajtovi manjih potencija, a sami zapis stringa je poredan od niže adrese prema višoj zbog čega je svaki bajt stringa unutar pointera ispisan obrnutim redoslijedom. Posljedično tome završetak stringa (opisan s newline \n tj. \x0a u hex formatu) proguta 0 u ispisu pointera. Recimo da je ispis nekog pointer 0xa414141. Provlačenjem kroz konverter konvertirale bi se vrijednosti \xa4 \x14 \x14 \x10 što nije ispravno. Potrebno je nadodati 0 na početak danog pointera kako bi se ispisale ispravne vrijednosti: \x0a \x41 \x41 \x41. Primjer lokalnog ispisa rješenja: {{kupon.png}}