This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
laboratoare:laborator-09 [2015/12/09 15:14] razvan.deaconescu [[1.5p] 7. Buffer overflow cu date de la intrarea standard și fgets()] |
laboratoare:laborator-09 [2016/01/09 13:38] (current) razvan.deaconescu [[2p] Bonus: Buffer overflow pentru binar] |
||
---|---|---|---|
Line 12: | Line 12: | ||
Pentru desfășurarea acestui laborator vom folosi interfața în linia de comandă. Întrucât în exercițiile finale avem nevoie și de compilatorul de la Microsoft, este recomandat să deschideți consola de Visual Studio, care are mediul deja configurat pentru compilarea de programe. | Pentru desfășurarea acestui laborator vom folosi interfața în linia de comandă. Întrucât în exercițiile finale avem nevoie și de compilatorul de la Microsoft, este recomandat să deschideți consola de Visual Studio, care are mediul deja configurat pentru compilarea de programe. | ||
+ | |||
+ | <note> | ||
+ | Nu este nevoie să deschideti consola de Visual Studio până la exercițiul 7 inclusiv. Până acolo puteți folosi orice consolă. | ||
+ | |||
+ | Pentru a deschide consola de Visual Studio urmați pașii: | ||
+ | * Apăsați butonul ''Start''. | ||
+ | * Accesați opțiunea ''All apps''. | ||
+ | * Mergeți la litera ''V''. | ||
+ | * Deschideți meniul **de tip director** ''Visual Studio 2015''. | ||
+ | * Selectați opțiunea ''VS2015 x86 Native Tools Command Prompt''. | ||
+ | |||
+ | </note> | ||
În general, pe parcursul laboratorului, în linia de comandă, vom folosi: | În general, pe parcursul laboratorului, în linia de comandă, vom folosi: | ||
Line 64: | Line 76: | ||
Pe baza experienței de mai sus, realizați modificări pentru ca valoarea variabilei să fie ''0xDEADBEEF'' (în loc de ''0xCAFEBABE'' cum este la început) fără a modifica însă explicit valoarea variabilei. Folosiți-vă de modificarea buffer-ului și de registrul ''ebx'' în care am stocat adresa de început a buffer-ului. | Pe baza experienței de mai sus, realizați modificări pentru ca valoarea variabilei să fie ''0xDEADBEEF'' (în loc de ''0xCAFEBABE'' cum este la început) fără a modifica însă explicit valoarea variabilei. Folosiți-vă de modificarea buffer-ului și de registrul ''ebx'' în care am stocat adresa de început a buffer-ului. | ||
+ | |||
+ | <note tip> | ||
+ | Din nou, nu este ceva complicat. Trebuie să vă folosiți de valoarea ''ebx'' și un offset ca să scrieți valoarea ''0xDEADBEEF'' la acea adresă. | ||
+ | |||
+ | Realizați acest lucru după secvența de inițializare a buffer-ului din jurul label-ului ''fill_byte''. | ||
+ | </note> | ||
La o rezolvare corectă a acestui exercițiu, programul va afișa valoarea ''0xDEADBEEF'' pentru variabila locală. | La o rezolvare corectă a acestui exercițiu, programul va afișa valoarea ''0xDEADBEEF'' pentru variabila locală. | ||
Line 84: | Line 102: | ||
Pentru aceasta transmiteți șirul de intrare corespunzător pentru ca valoarea afișată pentru variabila locală să nu mai fie ''0xCAFEBABE'' ci să fie ''0x574F4C46''. | Pentru aceasta transmiteți șirul de intrare corespunzător pentru ca valoarea afișată pentru variabila locală să nu mai fie ''0xCAFEBABE'' ci să fie ''0x574F4C46''. | ||
+ | |||
+ | <note tip> | ||
+ | Ca să transmiteți șirul de intrare, e recomandat să-l scrieți într-un fișier și apoi să redirectați acel fișier către comanda aferentă programului. Puteți folosi un editor precum ''Notapad++'' pentru editarea fișierului. Avantajul ''Notepad++'' este că vă afișează și coloana pe care vă aflați și puteți să știți câte caractere ați scris în fișier. | ||
+ | |||
+ | E recomandat să numiți fișierul ''payload''. Redirectarea fișierului ''payload'' către program se face folosind o comandă precum<code> | ||
+ | .\read_stdin < payload | ||
+ | </code> | ||
+ | </note> | ||
===== [1.5p] 7. Buffer overflow cu date de la intrarea standard și fgets() ===== | ===== [1.5p] 7. Buffer overflow cu date de la intrarea standard și fgets() ===== | ||
- | Așa cum am precizat mai sus, funcția ''gets'' este interzisă în programele curente. În locul acesteia se poate folosi funcția [[http://man7.org/linux/man-pages/man3/fgets.3.html|fgets]]. Creați o copie a conținutului directorului ''read-stdin/'' în ''read-stdin-fgets/'' și schimbați apelul funcției ''gets'' cu apelul funcției ''fgets''. | + | Așa cum am precizat mai sus, funcția ''gets'' este interzisă în programele curente. În locul acesteia se poate folosi funcția [[http://man7.org/linux/man-pages/man3/fgets.3.html|fgets]]. Creați o copie a fișierului cod sursă ''read_stdin.asm'' din subdirectorul ''read-stdin/'' într-u fișier cod sursă ''read_stdin_fgets.asm'' în subdirectorul ''read-stdin-fgets/''. În fișierul cod sursă ''read_stdin.asm'' schimbați apelul funcției ''gets'' cu apelul funcției ''fgets''. |
- | Pentru apelul ''fgets'' citiți de la intrarea standard. Ca argument pentru intrarea standard folosiți construcția [[http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html|__iob]]. Va trebui să o marcați externă la modul ''%%extern __iob%%''. | + | Pentru apelul ''fgets'' citiți de la intrarea standard. Ca argument pentru al treilea parametru al ''fgets'' (de tipul ''FILE *'') veți folosi intrarea standard. Pentru a specifica intrarea standard folosiți construcția [[http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html|__iob]]. Va trebui să o marcați externă la modul ''%%extern __iob%%''. |
<note tip> | <note tip> | ||
Line 95: | Line 121: | ||
</note> | </note> | ||
- | Să păstrați posibilitatea unui buffer overflow și să demonstrați acest lucru prin afișarea valorii ''0x574F4C46'' pentru variabila locală. | + | <note tip> |
+ | Pentru apelul funcției ''fgets'' folosiți construcția<code> | ||
+ | call _fgets | ||
+ | </code> | ||
+ | De asemenea, marcați simbolul ca fiind extern folosind construcția<code> | ||
+ | extern _fgets | ||
+ | </code> | ||
+ | </note> | ||
+ | |||
+ | <note tip> | ||
+ | Întrucât funcția ''fgets'' are 3 parametri (care ocupă ''3x4=12'' octeți) va trebui ca după apelul funcției, în restaurarea stivei, să folosiți ''add esp, 12'' (în loc de ''add esp, 4'' ca în cazul programul de mai sus care folosea ''gets()''). | ||
+ | </note> | ||
+ | |||
+ | Să păstrați posibilitatea unui buffer overflow și să demonstrați acest lucru prin afișarea valorii ''0x574F4C46'' pentru variabila locală. Adică să folosiți ca al doilea argument pentru ''fgets'' (dimensiunea) o valoare suficient de mare cât să permită realizarea unui buffer overflow. | ||
+ | |||
+ | <note tip> | ||
+ | La fel ca mai sus, ca să transmiteți șirul de intrare pentru program, e recomandat să-l scrieți într-un fișier și apoi să redirectați acel fișier către comanda aferentă programului. Redirectarea fișierului ''payload'' către program se face folosind o comandă precum<code> | ||
+ | .\read_stdin < payload | ||
+ | </code> | ||
+ | </note> | ||
===== [2p] 8. Buffer overflow pentru program scris în cod C ===== | ===== [2p] 8. Buffer overflow pentru program scris în cod C ===== | ||
Line 101: | Line 146: | ||
De cele mai multe ori vom identifica vulnerabilități de tip buffer overflow în programe scrise în C. Acolo trebuie să vedem ce buffere sunt și care este distanța de la buffer la variabila dorită pentru a putea face suprascriere. | De cele mai multe ori vom identifica vulnerabilități de tip buffer overflow în programe scrise în C. Acolo trebuie să vedem ce buffere sunt și care este distanța de la buffer la variabila dorită pentru a putea face suprascriere. | ||
- | Este important de avut în vedere distanța între un buffer și o altă variabilă în C poate nu corespunde cu cea %%"din teren"%%; compilatorul poate face actualizări, reordonări etc. | + | <note important> |
+ | Este important de avut în vedere că distanța între un buffer și o altă variabilă în C poate nu corespunde cu cea %%"din teren"%%; compilatorul poate face actualizări, reordonări, poate lăsa spații libere între variabile etc. | ||
+ | </note> | ||
Pentru exercițiul curent, accesați directorul ''c-buffer-overflow/'' din arhiva de resurse a laboratorului și observați codul sursă aferent în C. Pentru cazul în care doriți să nu mai compilați voi codul aveți în arhivă și fișierul limbaj de asamblare echivalent și fișierul în cod obiect și fișierul executabil. | Pentru exercițiul curent, accesați directorul ''c-buffer-overflow/'' din arhiva de resurse a laboratorului și observați codul sursă aferent în C. Pentru cazul în care doriți să nu mai compilați voi codul aveți în arhivă și fișierul limbaj de asamblare echivalent și fișierul în cod obiect și fișierul executabil. | ||
Descoperiți diferența între adresa buffer-ului și adresa variabilei, creați un fișier de intrare (numit și ''payload'') cu care să declanșați overflow-ul și faceți în așa fel încât să fie afișat mesajul //Full of win!//. | Descoperiți diferența între adresa buffer-ului și adresa variabilei, creați un fișier de intrare (numit și ''payload'') cu care să declanșați overflow-ul și faceți în așa fel încât să fie afișat mesajul //Full of win!//. | ||
+ | |||
+ | <note tip> | ||
+ | Ca să vedeți realitatea %%"din teren"%%, adică să aflați care este diferența dintre buffer și variabila pe care dorim să o suprascriem, consultați fișierul în limbaj de asamblare echivalent (''do_overflow.asm''), obținut prin asamblarea codului C. | ||
+ | |||
+ | În acest fișier puteți afla adresa relativă a buffer-ului față de ''ebp'' și a variabilei față de ''ebp''; urmăriți secvența cuprinsă între liniile ''32'' și ''37''; aveți o mapare între numele variabilei și offset-ul relativ față de ''ebp''. Cu aceste informații puteți crea șirul pe care să îl transmiteți ca payload către intrarea standard a programului. | ||
+ | </note> | ||
<note> | <note> | ||
Line 114: | Line 167: | ||
<note tip> | <note tip> | ||
- | Ca să transmiteți fișierul de tip payload executabilului puteți folosi redirectare<code> | + | La fel ca mai sus, ca să transmiteți șirul de intrare pentru program, e recomandat să-l scrieți într-un fișier și apoi să redirectați acel fișier către comanda aferentă programului. Redirectarea fișierului ''payload'' către program se face folosind o comandă precum<code> |
.\do_overflow < payload | .\do_overflow < payload | ||
</code> | </code> | ||
Line 121: | Line 174: | ||
===== [2p] Bonus: Buffer overflow pentru binar ===== | ===== [2p] Bonus: Buffer overflow pentru binar ===== | ||
- | De multe ori nu avem șansa accesului la codul sursă și vrem să descoperim vulnerabilități în fișiere executabile. În directorul ''overflow-in-binary'' din arhiva de resurse a laboratorului, găsiți un fișier executabil și fișierul modul obiecti din care a fost obținut. Folosind ''objdump'' sau ''gdb'' pentru investigație descoperiți cum puteți exploata vulnerabilitatea de tip buffer overflow, pentru ca programul să afișeze mesajul //Great success!//. | + | De multe ori nu avem șansa accesului la codul sursă și vrem să descoperim vulnerabilități în fișiere executabile. În directorul ''overflow-in-binary'' din arhiva de resurse a laboratorului, găsiți un fișier executabil și fișierul modul obiect din care a fost obținut. Folosind ''objdump'' sau ''gdb'' pentru investigație descoperiți cum puteți exploata vulnerabilitatea de tip buffer overflow, pentru ca programul să afișeze mesajul //Great success!//. |
+ | |||
+ | <note tip> | ||
+ | Pentru a rula ''objdump'' pe fișierul obiect ''overflow_in_binary.obj'' trebuie să rulați comanda<code> | ||
+ | C:\"Program Files (x86)"\SASM\MinGW\bin\objdump.exe -M intel -d overflow_in_binary.obj | ||
+ | </code> | ||
+ | </note> | ||
+ | |||
+ | ===== Soluții ===== | ||
+ | |||
+ | [[http://elf.cs.pub.ro/asm/res/laboratoare/lab-09-sol.zip|Soluții de referință pentru exercițiile de laborator]] | ||