Buffer overflow for dummies in perl

Pěkný článek pro začátečníky, kde mají praktické ukázky buffer overflow v PERLu a rady jak se této zranitelnosti při psaní vyhnout.

0x00: Intro
0x01: O cem to je
0x02: Ukazka + provedeni
0x03: Finalni verze
0x04: Bezpecne psani
0x05: Outro

==== 0x00: Intro ====

Mno, takze uz tolikrat ohrany tema buffer overflows, na ktery uz tolik lidi
napsalo tolik clanku, treba jako ventYl na bhole, ale ja nemam ani jeden :]
takze tady neco malo.

==== 0x01: O cem to je ====

Preteceni bufferu je, jak uz sam nazev pripomina, vlozeni vice dat nez je
buffer schopny unest, tedy pokud pouzijeme v c kodu `char buffer[1024]`
tak mame nejspis zadelano na problemy, protoze pokud vlozime vice dat jak
1024, stane se nec nepekneho ;], dojde k poruseni pameti a bude mozne vlozit
vlastni kod. K ukazce bezpecneho kodu se dostanu pozdeji. V kazdem pripade
se budeme snazit prepsat ebp a eip, dva dulezite registry. Pro vice
informaci o nich google.

==== 0x02: Ukazka + provedeni ====

Jako prvni vec nejdriv musime vypnout kernel patch randomize_va_space:

 

Pak pouzijeme nebezpecny kod tu:

 

zkompilujeme:
 

a zkusime spustit bez parametru. Vysledek by mel byt `Segmentation fault`, coz je spravne.
Zkuste ale spustit s nejakymy daty, tedy
 

Vysledek bude jen `Hotovo...` protoze jsme vlozili min znaku ja 1024. Co se
ale stane pokud zkusime spustit s vice znaky, treba 1030? Ano, objevi se
segmentation fault, takze nastartujme nas oblibeny debugger gdb na bofvuln:

 

Jak muzeme videt, eip jsme prepsali na 0x41414141 a ebp na 0x424242, pricemz
41 je hodnota `A` a 42 je hodnota `B`. Je tedy jasne, jak lze buffer
overflow zneuzit. Ted tedy prakticka ukazka s opravdovou exploitaci.
Nebudeme pouzivat command line buffer overflow, tedy preteceni z prikazove
radky [ shellu ], ale remotni, se kterym se setkate mnohem, mnohem casteji.
Takze znovu, tu je nebezpecny c fajl:

 

Ok, zkompilujeme a zkusime spustit, program zacne naslouchat na portu
definovanej v LISTENPORT, defaultne tedy 31337. Kdyz se telnetneme na tento
port, dostaneme zpravu, a jeji odpoved od nas se pote odesle na server a
zobrazi. V tom je prave chyba, v tom, ze buffer pro odpoved je staticky
definovany na 256. Takze stejny postup, az na to, ze tentokrat vse pujde
pres sit, nejdriv si tedy musime zkusit poslat tolik, aby jsme buffer
overflow flaw opravdu overili, napiseme si tedy jednoduchy perl script.:

 

Ok, spustime remvuln a pote i sendit.pl a vidime neco jako:
Segmentation fault(core dumped)
pote pres
gdb -c core remvuln
zjistime, ze jsme uspesne prepsali ebp i eip, hura! :D. Pokud se vam
nezobrazi core dumped, muzete a) spustit remvuln v gdb, nebo zadat prikaz:

 

====0x03: Finalni verze====

Ok, ted k samotnemu exploitu, budeme potrebovat prepsat eip aby ukazovalo na
nas shellkod, a ke zvyseni presnosti, prece jenom ne kazdy system je stejny,
pouzijeme NOPsled. NOP vlastne znamena NO Process, a posouva vykonavani k
dalsimu registru, takze timto se opravdu sledneme k shellkodu. Konstrukce
naseho payload k odeslani bude vypadat asi takto:

[ NOPSLED 220 ] + [ SHELLCODE 40 ] + [ EIP 4 ] = 264

Ok, a jak zjistit kde bude NOPsled? Jednoduse. eip prepiseme znovu Acky, a
pak si nechame vyjet oblast pameti a zkusime najit nas NOPsled. Jen pro
informaci, NOP vypada takto: \x90 nebo take 0x90, takze vite co hledat :]
Takze nas exploit bude vypadat takto:

Poznamka: Zkousejte dokud se vam eip nepodari prepsat uplne presne. Mente
velikost payload v sendit.pl.

 

Ok, tentokrat uz byste meli mit krasne EIP prepsane na 0x41414141, ted v gdb
zadejte prikaz:
x/1000xb $esp
To by vam melo hodit primo na nas NOPsled. Super, uz tam skoro jsme :]
Jedine co nam jeste schazi je poradne prepsat eip, takze vezmeme nejakou
adresu uprostred nopsledu, u me je to napriklad 0xbf91eb70, zmenime to na
little endian escaped: \xbf\x91\xeb\x70, a na to pote zmenime eip v
exploit.pl, ale nesmime zapomenout ze se vse bere z leva do prava, takze eip
bude \x70\xeb\x91\xbf :] A tra-daa mela by se nam otevrit cdromka, tedy me
alespon ano ;]

====0x04: Bezpecne psani====

Pouzivejte ochranu stacku, at uz v unixu nebo windows, za kazdou cenu se
vyhnete urcovani velikosti bufferu natvrdo, vzdy jeho velikost dynamicky
pocitejte. Snazte se co nejvice validovat vstup, at uz z HTTP aplikaci ci
primo pres strlen(). Pro vice info se muzete podivat na OWASP.

====0x05: Outro<===

Hoo, tak uz to mame za sebou, vas prvni exploit. Omlouvam se vsem ktere
tento clanek nejak urazi, a zaroven vas vsechny zadam: Pokud tu mam nekde
chybu, neco spatne napsanyho, spatne vysvetlenyho, postnete nebo mailujte,
budu jen vdecny, protoze a) psat neumim dobre, a za b) nesoustredim se na psani, pisu to po autobusech a prestavkach. Thanks you for reading!

~Tomas "Nostur" Kroupa
~nostur.security-portal.cz
[email protected]