Differences

This shows you the differences between two versions of the page.

Link to this comparison view

iocla:laboratoare:laborator-11 [2022/01/18 13:05]
darius.mihai [Feedback] Fix date
— (current)
Line 1: Line 1:
-====== Laborator 11: Gestiunea bufferelor. Buffer overflow ====== 
  
-Acest laborator își propune prezentarea conceptului de buffere în C și limbaj de asamblare împreună cu operațiile specifice acestora, 
-dar și vulnerabilitățile pe care acestea le au și cum pot ele să fie exploatate de un potențial atacator prin folosirea unui program 
-cu scopul de a ataca un sistem sau de a obține informații la care în mod normal nu ar avea acces. 
- 
-Obiective: 
- 
-  * Prezentarea conceptelor de buffer și buffer overflow 
-  * Exemple de atacuri de tip buffer overflow 
-  * Prezentarea unor modalități de securizare a programelor pentru evitarea atacurilor de tip buffer overflow 
- 
-===== Buffer. Buffer overflow ===== 
- 
-==== Ce este un buffer? ==== 
- 
-Un buffer este o zonă de memorie definită printr-o adresă de start și o dimensiune. Fie N dimensiunea bufferului, 
-adică numărul de elemente. Dimensiunea totală a bufferului este N x dimensiunea unui element. 
-Un șir de caractere (//​string//​) este un caz particular de buffer. 
- 
-==== Ce este un buffer overflow? ==== 
- 
-Un buffer overflow este un eveniment care se produce atunci când în parcurgerea unui buffer se depășește limita superioară,​ 
-adică poziția ultimului element (v[N - 1]). Un buffer overflow este un caz particular de //index out of bounds//, 
-în care vectorul poate fi accesat folosind și indecși negativi. Multe funcții din C nu verifică dimensiunea bufferelor cu care lucrează, 
-acestea cauzând erori de tip buffer overflow atunci când sunt apelate. Câteva exemple de astfel de funcții sunt: 
- 
-  * [[http://​www.cplusplus.com/​reference/​cstring/​memcpy/​|memcpy]] 
-  * [[https://​www.cplusplus.com/​reference/​cstring/​strcpy/​|strcpy]] 
-  * [[http://​www.cplusplus.com/​reference/​cstdio/​fgets/​|fgets]] 
- 
-Un exemplu clasic de buffer overflow este dat de următorul cod: 
- 
-<​code>​ 
-char buffer[32]; 
-fgets(buffer,​ 64, stdin); 
- 
-</​code>​ 
-În urma execuției acestui cod vom obține un buffer overflow care ar putea conduce chiar la o eroare de tip //​Segmentation Fault//, 
-însă acest lucru nu este garantat. Totul depinde de poziția bufferului pe stivă și de ceea ce se va suprascrie prin cei 32 de octeți 
-ce depășesc dimensiunea bufferului. Mai multe detalii despre ceea ce se va suprascrie, 
-dar și modalitatea prin care se va face acest lucru veți descoperi în timpul rezolvării exercițiilor. 
- 
-===== Atacuri de tip buffer overflow ===== 
- 
-==== Cum este folosit buffer overflow? ==== 
- 
-Buffer overflow poate fi exploatat de un potențial atacator pentru a suprascrie anumite date din cadrul unui program, 
-afectând fluxul de execuție și oferind anumite beneficii atacatorului. 
-Cel mai adesea, un atacator inițiază un atac de tip buffer overflow cu scopul de a obține acces la date confidențiale,​ 
-la care, în mod normal, un utilizator obișnuit nu ar avea acces. 
- 
-Atacurile de tip buffer overflow sunt folosite în general pe buffere statice, stocate la nivel de stivă. 
-Acest lucru se datorează faptului că pe stivă, pe lângă datele programului,​ se stochează și adrese de retur în urma apelurilor de funcții (vezi laboratorul 7). 
-Aceste adrese pot fi suprascrise printr-un atac de tip buffer overflow, caz în care poate fi alterat fluxul de execuție a programului. 
-Prin suprascrierea adresei de retur, odată cu încheierea execuției funcției curente nu se va mai reveni la execuția funcției apelante, 
-ci se va „sări” la o altă adresă din cadrul executabilului de unde se va continua execuția. 
-Acest eveniment poate conduce la comportament nedefinit al programului (//​undefined behaviour//​) dacă adresa la care se „sare” nu a fost calculată corect. 
- 
-Scopul unui atacator este acela de a prelua controlul unui sistem prin obținerea accesului la un shell din care să poată rula comenzi. 
-Acest lucru se poate realiza prin suprascrierea adresei de retur, folosind un apel de sistem prin intermediul căruia se poate deschide 
-un shell pe sistemul pe care executabilul rulează (mai multe detalii la cursul de SO). 
- 
-==== Cum ne protejăm de atacuri de tip buffer overflow? ==== 
- 
-Există multe modalități de a proteja un executabil de acest tip de atacuri. Pe majoritatea le veți studia în amănunt la cursul de SO anul viitor. 
-O bună practică împotriva acestui tip de atac este de a evita folosirea unor funcții nesigure, precum cele prezentate mai sus. 
-Mai multe detalii despre bune practici împotriva atacurilor de tip buffer overflow puteți găsi [[https://​security.web.cern.ch/​recommendations/​en/​codetools/​c.shtml|aici]]. 
- 
-De multe ori, bunele practici se dovedesc a fi insuficiente în „lupta” împotriva atacatorilor,​ 
-motiv pentru care au fost inventate mai multe mecanisme de protecție a executabilelor prin manipularea codului 
-și a poziției acestuia în cadrul executabilului (//Position Independent Code// - [[https://​en.wikipedia.org/​wiki/​Position-independent_code|PIC]]),​ 
-prin randomizarea adreselor (//Address Space Layout Randomization//​ - [[https://​en.wikipedia.org/​wiki/​Address_space_layout_randomization|ASLR]]) 
-sau prin introducerea unor verificări suplimentare în cod pentru a detecta eventuale atacuri. 
-Aceste verificări se realizează prin introducerea unor valori speciale, numite **canary** pe stivă, 
-între buffer și adresa de retur a funcției. Aceste valori sunt generate și plasate în cadrul executabilului de către compilator 
-și diferă la fiecare rulare a executabilului. În momentul în care un atacator vrea să suprascrie adresa de retur se va suprascrie 
-și valoarea canary și înainte de a se părăsi apelul funcției curente se va verifica dacă acea valoare a fost modificată sau nu. 
-Dacă a fost modificată înseamnă că a avut loc un buffer overflow și execuția programului va fi întreruptă. 
-Acest mecanism se numește **Stack Smashing Protection** sau **Stack Guard**. Mai multe detalii despre Stack Guard, 
-dar și despre atacuri de tip buffer overflow puteți găsi [[https://​en.wikipedia.org/​wiki/​Buffer_overflow|aici]]. 
- 
-===== Feedback ===== 
- 
-Pentru a îmbunătăți cursul de IOCLA, componentele sale și modul de desfășurare,​ ne sunt foarte utile opiniile voastre. Pentru aceasta, vă rugăm să accesați și completați formularul de feedback de pe site-ul [[https://​curs.upb.ro/​|curs.upb.ro]]. Trebuie să fiți autentificați și înrolați în cadrul cursului. 
- 
-Formularul este anonim și este activ în perioada 17 ianuarie 2022 - 28 ianuarie 2022. Rezultatele vor fi vizibile în cadrul echipei cursului doar după încheierea sesiunii. Puteți accesa formularul de feedback începând cu 17 ianuarie 2022. Este accesibil la link-ul “Formular feedback” a paginii principale a cursului de IOCLA al seriei voastre. Nu este în meta-cursul disponibil tuturor seriilor. 
- 
-Vă invităm să evaluați activitatea echipei de IOCLA și să precizați punctele tari și punctele slabe și sugestiile voastre de îmbunătățire a disciplinei. Feedback-ul vostru ne ajută să creștem calitatea materiei în anii următori și să îmbunătățim disciplinele pe care le veți face în continuare. 
- 
-Vom publica la începutul semestrului viitor analiza feedback-ului vostru. 
- 
-Ne interesează în special: 
- 
-    - Ce nu v-a plăcut și ce credeți că nu a mers bine? 
-    - De ce nu v-a plăcut și de ce credeți că nu a mers bine? 
-    - Ce ar trebui să facem ca lucrurile să fie plăcute și să meargă bine? 
- 
-===== Pregătire infrastructură ===== 
- 
-<note important>​ În cadrul laboratoarelor vom folosi repository-ul de git al materiei IOCLA - [[https://​github.com/​systems-cs-pub-ro/​iocla|https://​github.com/​systems-cs-pub-ro/​iocla]]. 
-Repository-ul este clonat pe desktop-ul mașinii virtuale. Pentru a îl actualiza, folosiți comanda git pull origin master din 
-interiorul directorului în care se află repository-ul (''​%%~/​Desktop/​iocla%%''​). Recomandarea este să îl actualizați cât mai frecvent, 
-înainte să începeți lucrul, pentru a vă asigura că aveți versiunea cea mai recentă. 
-Dacă doriți să descărcați repository-ul în altă locație, folosiți comanda ''​%%git clone [[https://​github.com/​systems-cs-pub-ro/​iocla|https://​github.com/​systems-cs-pub-ro/​iocla]] ${target}%%''​. 
-Pentru mai multe informații despre folosirea utilitarului ''​%%git%%'',​ urmați ghidul de la [[https://​gitimmersion.com/​|Git Immersion]]. </​note>​ 
- 
-Pentru desfășurarea acestui laborator vom folosi interfața în linia de comandă. 
- 
-Pe parcursul laboratorului,​ în linia de comandă, vom folosi: 
- 
-  * asamblorul ''​%%nasm%%''​ 
-  * comanda ''​%%gcc%%''​ pe post de linker 
-  * ''​%%objdump%%''​ și ''​%%ghidra%%''​ pentru dezasamblarea fișierelor obiect și executabile 
-  * ''​%%gdb%%''​ pentru analiza dinamică, investigație și debugging 
- 
-În general nu va fi nevoie să dați comenzi de compilare. Fiecare director cuprinde un Makefile pe care îl puteți rula 
-pentru a compila în mod automat fișierele cod sursă limbaj de asamblare sau C. 
- 
-Înainte de a începe laboratorul,​ alocați-vă 1-2 minute să reparcurgeți diagrama de mai jos ce arată structura stivei în cazul unui apel de funcție. 
- 
-{{https://​ocw.cs.pub.ro/​courses/​_media/​iocla/​laboratoare/​stack-in-function-call.png?​width=750|Image}} 
- 
-===== 0. Stay a while and listen ===== 
- 
-Ați sărit direct la exerciții? Știm cum este. Totuși, vă rugăm să ne oferiți feedback și să ne ajutați să îmbunătățim materia. Mergeți la secțiunea [[#​feedback|feedback]] pentru detalii. 
- 
-===== 1. Tutorial: Folosirea unui buffer în zona de date ===== 
- 
-Accesați, în linia de comandă, directorul ''​%%1-data-buffer/​%%''​ din arhiva de resurse a laboratorului și consultați fișierul ''​%%data_buffer.asm%%''​. 
-În acest fișier se găsește un program care populează un buffer cu informații și apoi le afișează. 
- 
-Consultați cu atenție programul, apoi compilați-l folosind comanda: 
- 
-<​code>​ 
-make 
- 
-</​code>​ 
-Observați că în urma comenzii de compilare de mai sus au rezultat un fișier obiect și un fișier executabil, prin rularea comenzii: 
- 
-<​code>​ 
-ls 
- 
-</​code>​ 
-Rulați programul prin intermediul fișierului executabil, adică folosind comanda: 
- 
-<​code>​ 
-./​data_buffer 
- 
-</​code>​ 
-Observați comportamentul programului în funcție de codul său. 
- 
-===== 2. Tutorial: Folosirea unui buffer pe stivă ===== 
- 
-Accesați directorul ''​%%2-3-4-stack-buffer/​%%''​ din arhiva de resurse a laboratorului și consultați fișierul ''​%%stack_buffer.asm%%''​. 
-În acest fișier se găsește un program care populează un buffer cu informații și apoi le afișează. 
-Este similar celui de mai sus doar că acum buffer-ul este alocat pe stivă. 
- 
-Consultați cu atenție programul, apoi compilați-l folosind comanda: 
- 
-<​code>​ 
-make 
- 
-</​code>​ 
-apoi rulați-l folosind comanda: 
- 
-<​code>​ 
-./​stack_buffer 
- 
-</​code>​ 
-Observați comportamentul programului în funcție de codul său. 
- 
-Pe lângă buffer am mai alocat o variabilă locală pe 4 octeți, accesibilă la adresa ''​%%ebp-4%%''​. 
-Este inițializată la valoarea ''​%%0xCAFEBABE%%''​. Această variabilă va fi importantă mai târziu. 
-Ce este relevant acum este să știm că această variabilă este în memorie **imediat după buffer**: când se trece de limita buffer-ului se ajunge la această variabilă. 
- 
-Care este diferenta intre cele 2 programe inspectate pana acum? 
- 
-===== 3. Citirea de date dincolo de dimensiunea buffer-ului ===== 
- 
-Acum că am văzut cum arată buffer-ul în memorie și unde este plasată variabila, 
-actualizați programul ''​%%stack_buffer.asm%%''​ pentru ca secvența de afișare a buffer-ului 
-(cea din jurul etichetei ''​%%print_byte%%''​) să ducă și la afișarea octeților variabilei. 
-Adică trebuie să citiți date dincolo de dimensiunea buffer-ului (și să le afișați). 
-Este un caz de buffer overflow de citire, cu obiectiv de **information leak**: aflarea de informații din memorie. 
- 
-<note tip> Nu e ceva complicat, trebuie doar să "​instruiți"​ secvența de afișare să folosească altă limită pentru afișare, 
-nu limita curentă de 64 de octeți. </​note>​ 
- 
-Afișați și alte informații dincolo chiar de variabila locală. 
-Ce informație vine pe stivă după variabila locală (următorii 4 octeți)? Dar următorii 4 octeți după? 
- 
-===== 4. Scrierea de date dincolo de dimensiunea 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ă. 
-Adică folosiți o construcție de forma: 
- 
-<​code>​ 
-mov byte [ebx+TODO], TODO 
- 
-</​code>​ 
-Realizați acest lucru după secvența de inițializare a buffer-ului (după instrucțiunea ''​%%jl fill_byte%%''​). 
-</​note>​ 
-La o rezolvare corectă a acestui exercițiu, programul va afișa valoarea ''​%%0xDEADBEEF%%''​ pentru variabila locală. 
- 
-===== 5. Tutorial: Citirea de date de la intrarea standard ===== 
- 
-Accesați directorul ''​%%5-6-read-stdin/​%%''​ din arhiva de resurse a laboratorului și consultați fișierul ''​%%read_stdin.asm%%''​. 
-În acest fișier se găsește un program care folosește apelul ''​%%gets%%''​ ca să citească informații de la intrarea standard 
-într-un buffer de pe stivă. La fel ca în cazul precedent am alocat o variabilă locală pe 4 octeți imediat după buffer-ul de pe stivă. 
- 
-Consultați cu atenție programul, apoi compilați-l folosind comanda: 
- 
-<​code>​ 
-make 
- 
-</​code>​ 
-apoi rulați-l folosind comanda: 
- 
-<​code>​ 
-./​read_stdin 
- 
-</​code>​ 
-Observați comportamentul programului funcție de input-ul primit. 
- 
-===== 6. Buffer overflow cu date de la intrarea standard ===== 
- 
-Funcția [[https://​man7.org/​linux/​man-pages/​man3/​gets.3.html|gets]] este o funcție care este practic interzisă în programele C 
-din cauza vulnerabilității mari a acesteia: nu verifică limitele buffer-ului în care se face citirea, 
-putând fi ușor folosită pentru buffer overflow. 
- 
-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%%''​ (valorile ASCII în hexazecimal pentru ''​%%FLOW%%''​). 
- 
-<note important>​ Nu modificați codul în limbaj de asamblare. 
-Transmiteți șirul de intrare în format corespunzător la intrarea standard pentru a genera un buffer overflow și pentru a obține rezultatul cerut. </​note>​ 
- 
-<note warning> Nu scrieți șirul ''​%%"​574F4C46"​%%''​. Acesta e un șir care ocupă ''​%%8%%''​ octeți. 
-Trebuie să scrieți reprezentarea ASCII a numărului ''​%%0x574F4C46%%''​ adică ''​%%FLOW%%'':​ 
-''​%%0x57%%''​ este ''​%%W%%'',​ ''​%%0x4F%%''​ este ''​%%O%%'',​ ''​%%0x4C%%''​ este ''​%%L%%''​ iar ''​%%0x46%%''​ este ''​%%F%%''​. </​note>​ 
- 
-<note tip> x86 este o arhitectură little endian. Adică șirul ''​%%"​FLOW"​%%'',​ având corespondența caracter-cod ASCII 
-''​%%F%%'':​ ''​%%0x46%%'',​ ''​%%L%%'':​ ''​%%0x4C%%'',​ ''​%%O%%'':​ ''​%%0x4F%%'',​ ''​%%W%%'':​ ''​%%0x57%%''​ va fi stocat în memorie pe ''​%%4%%''​ octeți ca ''​%%0x574F4C46%%''​. 
-**Ce trebuie să faceți**: Va trebui ca, în cadrul buffer overflow-ului,​ să obțineți valoarea în memorie ''​%%0x574F4C46%%''​. 
-Obțineți șirul ASCII corespondent valorii în memorie ''​%%0x574F4C46%%''​ pe care trebuie să îl furnizați la intrarea standard a programului vulnerabil. </​note>​ 
- 
-<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 ''​%%gedit%%''​ sau ''​%%vim%%''​ pentru editarea fișierului. 
-Avantajul acestora 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. 
-Alternativ, puteți folosi python pentru a vă genera mai ușor payload-ul. 
-De exemplu, pentru a genera un payload care să suprascrie o valoare în cod cu valoarea ''​%%0xDEADBEEF%%'',​ puteți executa următoarea comandă: 
- 
-<code python> 
-python -c 'print "​A"​*32 + "​\xEF\xBE\xAD\xDE"'​ > payload 
- 
-</​code>​ 
-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>​ 
-===== 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 [[https://​man7.org/​linux/​man-pages/​man3/​fgets.3.html|fgets]]. 
-Creați o copie a fișierului cod sursă ''​%%read_stdin.asm%%''​ din subdirectorul ''​%%5-6-read-stdin/​%%''​ într-un fișier 
-cod sursă ''​%%read_stdin_fgets.asm%%''​ în subdirectorul ''​%%7-read-stdin-fgets/​%%''​. 
-În fișierul cod sursă ''​%%read_stdin_fgets.asm%%''​ schimbați apelul funcției ''​%%gets()%%''​ cu apelul funcției ''​%%fgets%%''​. 
- 
-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 stream-ul [[https://​linux.die.net/​man/​3/​stdin|stdin]]. 
-Va trebui să îl marcați ca extern folosind, la începutul fișierului în limbaj de asamblare, construcția:​ 
- 
-<​code>​ 
-extern stdin 
- 
-</​code>​ 
-''​%%stdin%%''​ este o adresă; pentru a apela ''​%%fgets()%%''​ cu intrarea standard, 
-este suficient să transmitem pe stivă valoarea de la adresa ''​%%stdin%%'',​ adică folosind construcția:​ 
- 
-<​code>​ 
-push dword [stdin] 
- 
-</​code>​ 
-<note tip> Urmăriți pagina de manual a funcției [[https://​man7.org/​linux/​man-pages/​man3/​fgets.3.html|fgets]] pentru a afla ce parametri primește. </​note>​ 
- 
-<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ă ''​%%3×4=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_fgets < payload 
- 
-</​code>​ 
-</​note>​ 
-<note important>​ Nu modificați codul în limbaj de asamblare. Transmiteți șirul de intrare în format corespunzător la intrarea standard 
-pentru a genera un buffer overflow și pentru a obține rezultatul cerut. </​note>​ 
- 
-===== 8. Buffer overflow pentru program scris în cod C ===== 
- 
-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 suprascrierea. 
- 
-<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 ''​%%8-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!//. 
- 
-<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 ''​%%41%%'';​ 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>​ Dacă doriți să recompilați fișierele rulați: 
- 
-<​code>​ 
-make clean && make 
- 
-</​code></​note>​ 
-<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>​ 
-./​do_overflow < payload 
- 
-</​code></​note>​ 
-===== 9. Bonus: Stack canary ===== 
- 
-Pornind de la resursele exercițiului anterior din directorul ''​%%8-9-c-buffer-overflow%%''​ inspectați fișierul ''​%%Makefile%%''​. 
- 
-<​code>​ 
-cat Makefile 
- 
-</​code>​ 
-Analizați atent opțiunile de compilare. Ce observați? 
- 
-Așa cum ați observat în cadrul exercițiului anterior, deși am depășit dimensiunea buffer-ului 
-și am suprascris o altă variabilă din program, acesta și-a încheiat execuția în mod normal. 
-Acest lucru este nedorit atunci când lucrăm cu buffere, deoarece sunt o sursă de la care poate porni foarte ușor un atac. 
-Folosind ''​%%objdump%%''​ inspectați funcția ''​%%main%%''​ a executabilului. 
- 
-<note tip> Pentru a inspecta sursa, folosiți următoarea comandă: 
- 
-<​code>​ 
-objdump -M intel -d do_overflow 
- 
-</​code></​note>​ 
-Acum intrați în fișierul ''​%%Makefile%%''​ și modificați parametrii ''​%%CFLAGS%%''​ înlocuind ''​%%-fno-stack-protector%%''​ cu ''​%%-fstack-protector%%''​. 
-Recompilați programul și rulați-l. Ce observați? 
- 
-<​note>​ Prin opțiunea sau flag-ul ''​%%-fstack-protector%%''​ i-am cerut compilatorului să activeze opțiunea de 
-//Stack Smashing Protection//​ pentru executabilul nostru. Astfel, orice atac de tip buffer overflow 
-va fi detectat în cod și execuția programului se va încheia cu eroare. </​note>​ 
- 
-Inspectați din nou executabilul recompilat cu noul flag folosind ''​%%objdump%%''​. Ce s-a schimbat? 
- 
-<​note>​ Compilatorul a introdus pe stivă o valoare generată aleator, numită **canary**, 
-pe care o verifică înainte de a părăsi execuția funcției curente. Prin buffer overflow, 
-aceasta a fost suprascrisă odată cu depășirea dimensiunii buffer-ului,​ 
-ceea ce a determinat o neconcordanță între valoarea inițială a canary-ului și cea de la finalul execuției funcției. </​note>​ 
- 
-===== 10. 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 ''​%%10-overflow-in-binary%%''​ din arhiva de resurse a laboratorului,​ găsiți un fișier executabil. 
-Folosind ''​%%ghidra%%''​ 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 important>​ Pentru a rula ''​%%ghidra%%''​ pe fișierul executabil ''​%%overflow_in_binary%%''​ trebuie să vă creați un proiect nou în care să importați fișierul executabil. 
-Ghidra va detecta automat formatul fișierului. Rulați analiza executabilului după care căutați în Symbol Tree după funcția main. </​note>​ 
- 
-<note tip> Identificați în codul dezasamblat cum se transmite intrarea către program. 
-Identificați unde este buffer overflow-ul. Identificați condiția de comparație pe care doriți să o declanșați. 
-Apoi construiți payload-ul corespunzător și transmiteți-l în forma adecvată programului. </​note>​ 
- 
-===== Soluții ===== 
- 
-Soluțiile pentru exerciții sunt disponibile [[https://​elf.cs.pub.ro/​asm/​res/​laboratoare/​lab-11-sol.zip|aici]]. 
- 
-===== Resurse ===== 
- 
-Dacă laboratorul v-a impresionat într-un mod plăcut, puteți afla mai multe despre acest tip de atac, dar și despre securitate cibernetică în general, de pe acest [[https://​www.youtube.com/​c/​LiveOverflow|canal]]. 
iocla/laboratoare/laborator-11.1642503942.txt.gz · Last modified: 2022/01/18 13:05 by darius.mihai
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0