Po drátě 6: Řešení úlohy č. 14
Nevinně vyhlížející formulářík vybízí k vyplnění Céčkového zdrojáku. Tak mu nějaký syntakticky korektní zadáme (kdo by odolal zkusit nejdřív tradiční Hello world?) a z překladače vypadne staticky slinkovaná binárka pro Linux/i386, která dělá přesně to, co jsme napsali.
Opravdu přesně? Ne tak docela... Například strace odhalí, že než program spustí main, zapíše do file deskriptoru 99 heslo k vedlejší úloze.
No dobře, ale kde je hlavní heslo? Pokud se na program podíváme nějakým
disassemblerem, zjistíme, že před spuštěním mainu prozkoumá argumenty a byl-li
spuštěn s parametrem --passwd
, vypíše do standardního výstupu heslo.
Co asi do programů vkládá váš domácí překladač? ;-)
Zajímavosti
Tato úloha je tichou vzpomínkou na Dennise Ritchieho (1941-2011), jenž spolu s Brianem Kernighanem vymyslel jazyk C.
Také nás k ní inspirovala přednáška Ritchieho kolegy a spoluautora UNIXu Kena Thompsona jménem Reflections on Trusting Trust, v níž moc hezky předvedl, že i když máte k dispozici zdrojáky celého operačního systému včetně překladače, nemusí to ještě znamenat, že si do něj autoři nezabudovali zadní vrátka. Příjemnou vlastností Linuxu, který kompilují lidé po celém světě různými překladači, je, že by útoky tohoto typu byly pravděpodobně snadno odhalitelné.
Samotný webový překladač je triviálním obalem okolo GCC a také cvičením
na použití přepínače --wrap
GNU linkeru. Místo GNU libc ale používáme
diet libc, přeci jenom půlmegovým hello
worldem jsme vás trápit nechtěli.
Mimochodem, to byste nevěřili, čím vším autor, testeři i hráči zkoušeli překladač
potrápit. Například #include "/dev/zero"
, #include "/dev/random"
,
nebo třeba __asm__(".incbin \"/etc/passwd\"");
.
Úlohu vytvořil Medvěd.
Ale aspon jsem se dozvedel o __kernel_vsyscall. Zaujalo me, ze se v tom zdrojaku vyskytuje int 80, ale vubec se nepouziva (mi prijde).
> zkousel davat "si 100", ale to nejak padalo..
Nejefektivnější ochranou před laděním je neuvěřitelné množství bugů v gdb :-)
Docela dlouho jsem se snažil gdb přimět k tomu, aby mi program začalo
krokovat, ale se staticky slinkovanou binárkou bez debug infa si alespoň
ta verze, kterou jsem zkoušel, neporadila. Breakpoint na začátek programu
si nastavit nechala, ale pak ho prostě neprovedla :)
A nebude to jediný bug report, který po hře pošlu ;)
jako obvykle. Hned jak se mi podařilo trochu zkrotit gdb, našel jsem
syscall (ten nešlo přehlédnout) a pod ním celkem snadno rozeznatelné
strcmp(). Tak jsem se podíval, odkud se volá, dal si tam breakpoint a
podíval se, co se s čím porovnává.
prezeral v IDAe. Povodne som si myslel, ze sa to riesi cez #include "" a
navratove chybove hlasky, ale prislo mi to nezrealizovatelne a zistil som
maximalne par bajtov zo spustaneho perl CGI skriptu.
Prvni, co me napadlo bylo nejake pouziti #pragma a jsem rad, ze to v tom nebylo...
> Cim jste to disasemblovali? Pod linuxem sice existuje par
> disassembleru, ale zatim jsem nenarazil na zadny co by byl aspon
> trochu kvalitni ...
gdb