Debord de tampon

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare
Notă despre dezambiguizare.svg Dezambiguizare - Dacă sunteți în căutarea depășirii bufferului legate de telecomunicații, consultați Debordarea bufferului (telecom) .

1leftarrow blue.svg Element principal: tampon .

Depășirea bufferului (sau depășirea bufferului ), în informatică , este o condiție de eroare care apare în timpul rulării atunci când sunt scrise date mai mari într-un buffer de o dimensiune dată.

Istorie

Debursurile de tampon au devenit cunoscute și au fost parțial documentate publicului încă din 1972, când Studiul de planificare a tehnologiei de securitate a computerului a identificat un exploit capabil să exploateze vulnerabilitatea: „Codul care efectuează această funcție nu verifică în mod corespunzător adresele sursă și destinație, permițând porțiuni monitorului să fie suprapus de utilizator. Acesta poate fi folosit pentru a injecta cod în monitor care îi va permite utilizatorului să preia controlul mașinii. ", unde se intenționa să monitorizeze ceea ce este acum nucleul . [1]

Primul exemplu clar al unui atac de depășire a bufferului a fost Morris Worm (cunoscut și sub numele de Worm Internet), care în 1988 a prăbușit peste 6.000 de sisteme conectate la Internet în câteva ore prin exploatarea depășirii bufferului în procesul de demoni deget UNIX. în întreaga rețea. [2]

Mai târziu, în 1995, Thomas Lopatic a postat pe lista de discuții Bugtraq un exploit bazat pe spargerea stivei pe serverul web NCSA HTTPD pe sistemul de operare HP-UX și, un an mai târziu, în 1996, Elias Levy (cunoscut și sub numele de Aleph One) a publicat un articol intitulat „Smashing the Stack for Fun and Profit” pe revista Phrack , un ghid pas cu pas pentru exploatarea revărsărilor de tampon de stivă. [3] [4]

Mai târziu, deversările tamponului au fost exploatate de doi viermi de internet importanți: în 2001 viermele Code Red , care a exploatat depășirea bufferului în serverele Microsoft Internet Information Services (IIS) 5.0 [5] , și în 2003 viermele SQL Slammer , care a compromis mașinile care rulează Microsoft SQL Server 2000 . [6]

În ciuda faptului că este una dintre cele mai lungi vulnerabilități cunoscute, depășirea bufferului este încă o defecțiune de securitate larg răspândită și extrem de actuală: organizații precum CERT / CC și SANS încă publică recomandări privind securitatea cibernetică care includ un număr semnificativ de exploatări bazate pe buffer. în plus, mai multe elemente din lista „CWE / SANS Top 25 Most Dangerous Software Error” sunt variante ale depășirii bufferului. [7]

În februarie 2016, cercetătorii de la Google și Red Hat au descoperit o vulnerabilitate de depășire a bufferului stivei în funcția getaddrinfo a bibliotecii glibc (toate versiunile începând cu 2.9). Această bibliotecă este utilizată de sute de aplicații și de majoritatea distribuțiilor Linux (inclusiv cele instalate în routere și alte tipuri de hardware): funcția în cauză este cea care se ocupă cu căutarea DNS (rezoluția numelor de gazdă și a adreselor IP) și vulnerabilitatea ar putea permite unui atacator să trimită domenii rău intenționate sau servere DNS, precum și atacuri om-în-mijloc până la executarea unui cod arbitrar pe mașina victimei. [8] [9]

Descriere

Când, din greșeală sau prin răutate, sunt trimise mai multe date decât capacitatea tamponului destinat să le conțină (care din greșeală, răutate sau superficialitate nu a fost concepută corect), datele suplimentare suprascriu variabilele interne ale programului sau aceleași stiva ; ca o consecință a acestui lucru, în funcție de ceea ce a fost suprascris și cu ce valori, programul poate da rezultate eronate sau imprevizibile, poate bloca sau (dacă este un driver de sistem sau sistemul de operare în sine) poate bloca computerul . Cunoscând foarte bine programul în cauză, sistemul de operare și tipul de computer pe care rulează, este posibil să calculați în prealabil o serie de date rău intenționate care trimise pentru a provoca o depășire a tamponului permite unui atacator să preia controlul programului ( și uneori, prin aceasta, a întregului computer).

Nu toate programele sunt vulnerabile la acest tip de dezavantaje. Pentru limbajele de nivel scăzut, cum ar fi asamblarea, datele sunt tablouri simple de octeți, stocate în registre sau în memoria centrală: interpretarea corectă a acestor date (adrese, numere întregi, caractere, instrucțiuni etc.) este încredințată funcțiilor și instrucțiunile care le accesează și le manipulează; folosind limbaje de nivel scăzut există, prin urmare, un control mai mare al resurselor mașinii, dar este necesară o atenție mai mare în faza de programare pentru a asigura integritatea datelor (și, prin urmare, pentru a evita fenomene precum depășirea bufferului). Limbajele de nivel superior, cum ar fi Java și Python (și multe altele), care în schimb definesc conceptul de tip al unei variabile și care definesc un set de operații permise în funcție de tip, nu suferă de vulnerabilități precum depășirea bufferului, deoarece acestea nu vă permit să memorați mai multe date decât dimensiunea sa. Între aceste două extreme se află limbajul C, care prezintă unele dintre abstracțiile tipice limbajelor de nivel înalt, împreună cu elemente tipice limbajelor de nivel scăzut, cum ar fi capacitatea de a accesa și manipula adresele de memorie: acest lucru face ca limbajul să fie susceptibil de a fi inadecvat. utilizări ale memoriei; dacă adăugăm la aceasta faptul că unele biblioteci de funcții foarte populare (în special pentru introducerea și manipularea șirurilor, cum ar fi get ) nu efectuează un control corect al dimensiunii bufferelor la care lucrează și că C a fost folosit în anii '70 pentru a scrie sistemul de operare UNIX (și din acesta sunt apoi derivate sisteme precum Linux) și multe dintre aplicațiile concepute pentru a rula pe el, rezultă că o cantitate mare de cod de tampon vulnerabil este încă prezent și circulă astăzi. [10]

Nu toate programele sunt vulnerabile la acest tip de inconveniente, de fapt, pentru ca un anumit program să fie expus riscului, este necesar ca:

  • Programul prevede introducerea datelor de dimensiuni variabile și le stochează într-un buffer;
  • Limbajul de programare folosit nu oferă verificarea automată a limitelor bufferului (timp de compilare sau timp de execuție), iar programatorul nu introduce aceste verificări în cod.

Urmări

Când se întâmplă acest lucru, o parte din zona de memorie imediat adiacentă bufferului în cauză este suprascrisă, cu diferite efecte posibile în funcție de locul în care este localizat buffer-ul și de modul în care memoria este organizată în acea platformă software specială; în unele programe software acest lucru cauzează vulnerabilități de securitate . Limbajele gestionate , adică bazate pe un model de memorie gestionat în timp de execuție, cum ar fi Java, ar trebui, în teorie, să fie imune la acest tip de eroare, dar în practică posibilitatea rămâne prezentă în cazul apelurilor către codul nativ sau din cauza unor erori în modulul manager. (JVM în cazul Java) sau compilatorul JIT.

Depășirea bufferului poate fi indicată prin nume diferite, în funcție de poziția ocupată de buffer în memoria alocată procesului. Poziția bufferului este importantă, deoarece efectele depășirii bufferului sunt legate în principal de:

  • ce este lângă buffer
  • care date suprascrie zonele de memorie adiacente buffer-ului

Vulnerabilitate

Memoria virtuală a unui proces

Când se execută un program, sistemul de operare generează în mod normal un nou proces și alocă un spațiu de memorie virtuală rezervat procesului însuși în memoria principală.

Acest spațiu de memorie, în general, are o structură dată de (începând de sus în jos):

  • Nucleu
  • Stiva (crește în jos)
  • Memorie libera
  • Heap (crește în sus)
  • Date globale
  • Codul programului

Execuția programului la rândul său constă în mai multe apeluri către funcții: fiecare apel generează un cadru de stivă în cadrul stivei (care crește treptat în jos în structura descrisă mai sus, cu politica LIFO ); în cadrul funcției apelate stochează variabilele locale, adresa instrucțiunii funcției apelante la care trebuie să returneze controlul (adresa de retur) și indicatorul în cadrul funcției apelante; ultimii doi, în special, joacă un rol fundamental în asigurarea fluxului corect de execuție a programului între un apel de funcție și următorul, de fapt:

  • Adresa de returnare spune funcției apelate la ce instrucțiune a funcției de apelare trebuie să returneze controlul;
  • Pointerul cadru al funcției de apelare vă permite să restaurați contextul de execuție înainte de a reveni asupra acestuia;

Stiva crește cu fiecare apel de funcție și, prin urmare, fiecare cadru generat are o structură ca aceasta (întotdeauna de sus în jos):

Adresa expeditorului
Un indicator către cadrul funcției de apelare
Variabila locală 1
Variabila locală 2
...

[10]

Stiva depășirea bufferului

Când bufferul este alocat pe stivă, adică este o variabilă locală a unei funcții, orice intrare în buffer a unei cantități de date mai mari decât capacitatea sa se numește overflow de tampon de stivă (sau stricare de stivă sau bazată pe stivă depășire tampon ).

În acest caz, datele adiacente buffer-ului care ar putea fi suprascrise de datele suplimentare sunt adresa de returnare și indicatorul cadru.

Dacă excesul de date suprascrie pointerul cadru și adresa de retur, la sfârșitul execuției funcția ar încerca să returneze controlul la instrucțiunea indicată de adresa de retur care ar putea conține:

  • Adresa unei zone de memorie inaccesibile: datele în exces sunt aleatorii, programul se blochează returnând de obicei o eroare de segmentare . Este un exemplu al modului în care depășirea bufferului stivei poate fi utilizată ca un atac de refuz de serviciu (DoS), compromitând disponibilitatea serviciului afectat.
  • O adresă specifică de memorie: excesul de date este calculat în așa fel încât să suprascrie adresa de retur cu adresa unei zone de memorie la care atacatorul dorește să aibă acces sau cu adresa la care se află codul pe care atacatorul dorește să a executa.

Acest al doilea caz include atacuri bazate pe injecția shellcode ; datele inserate în buffer conțin cod executabil în limbajul mașinii ( asamblare ), iar suprascrierea adresei de returnare se face în așa fel încât să se refere la codul injectat în buffer. Sarcina acestui cod este în mod normal să invoce o interfață de linie de comandă, adică un shell , motiv pentru care acest cod este numit shellcode (un apel la funcția execve care execută shell-ul Bourne pentru sistemele UNIX, un apel la sistem („Command .exe ") pe sistemele Windows). În orice caz, programul care rulează este înlocuit de shell, pe care îl va executa cu aceleași privilegii ca și programul de pornire.

Există o variantă a acestui tip de atac care se bazează doar pe înlocuirea indicatorului cadru și care poate fi utilizată atunci când depășirea permisă este limitată și nu permite suprascrierea adresei de returnare. Atacul constă în exploatarea revărsării pentru a înlocui indicatorul cadrului stocat astfel încât să indice un cadru fals de stivă, injectat în buffer împreună cu shellcode-ul; în acest cadru fals de stivă atacatorul a introdus un pointer către shellcode ca adresă de returnare: atunci când funcția afectată își termină execuția, prin urmare, returnează corect controlul la funcția de apelare (adresa de returnare nu a fost modificată), dar acest lucru va fi reluați execuția cu un context fals, iar când se termină și executarea, controlul va fi în cele din urmă trecut la shellcode (deoarece RA a fost modificat în acest cadru de stivă pentru a indica codul rău intenționat). Atacurile off-by-one se bazează tocmai pe acest principiu: dacă, din cauza unei erori de scriere, programatorul permite introducerea chiar și a unui octet mai mult decât este necesar într-un buffer (de exemplu, folosind un <= în loc de < în testare o condiție de control), acest octet suplimentar simplu ar putea fi folosit de un atacator pentru a modifica indicatorul de cadru stocat suficient pentru a-l îndrepta către un cadru fals de stivă și, astfel, a obține indirect transferul controlului către codul rău intenționat injectat. [10]

În cele din urmă, trebuie amintit că depășirea stivei și depășirea bufferului stivei nu sunt sinonime: prima indică o situație pentru care este necesară prea multă memorie în stivă, a doua o situație în care (din diverse motive) este inserată într-un buffer în stivă o cantitate de date mai mare decât capacitatea tamponului în sine. [11]

Heap overflow

Un program poate solicita sistemului de operare să aloce dinamic o anumită cantitate de memorie în zona heap , utilizând apeluri de sistem precum malloc () și free () în C / UNIX. Aceste buffere pot fi, de asemenea, susceptibile la probleme de depășire atunci când pot fi introduse mai multe date decât memoria alocată, iar aceste date ar suprascrie, ca de obicei, zonele de memorie adiacente bufferului.

În aceste cazuri vorbim de depășire de heap , dar spre deosebire de stivă, nici adresele de returnare, nici indicii de cadru nu sunt stocate în zona heap, care poate fi modificată de un atacator pentru a transfera controlul execuției în cod arbitrar. Cu toate acestea, acest lucru nu înseamnă că aceste anomalii nu constituie vulnerabilități periculoase: în 2002 a fost găsită o vulnerabilitate de depășire a heap-ului într-o extensie Microsoft IIS care ar putea fi exploatată pentru a executa cod arbitrar pe acest tip de server. [12]

Când un program are mai multe funcții care efectuează aceeași operație, dar în moduri diferite (de exemplu, sortare ), și doriți să determinați în timpul rulării pe care să îl utilizați pentru a procesa datele de intrare, este adesea folosit pentru a stoca pointerele funcționale în zona heap : aceste indicatoare conțin adresele de pornire ale funcțiilor și sunt utilizate pentru a apela ulterior execuția lor. Într-un astfel de scenariu, un atacator ar putea exploata depășirea unui buffer alocat pe heap pentru a suprascrie acești indicatori, înlocuindu-i cu un pointer către shellcode-ul injectat prin overflow: următorul apel către una dintre funcții ar avea ca rezultat transferul control la shellcode.în locul funcției așteptate. [13]

Contramăsuri

Există diverse tehnici de prevenire sau detectare a fenomenului de depășire a tamponului, cu diverse compromisuri. În general, aceste apărări pot fi adoptate la diferite niveluri: [14]

  • La nivel de limbă
  • La nivel de cod sursă
  • La nivel de compilator
  • La nivel de sistem de operare

Apărări la nivel de limbă

Cea mai bună apărare împotriva atacurilor de depășire a bufferului este alegerea unui limbaj de programare care să ofere verificări automate ale dimensiunii bufferului (fie timpul de compilare, fie timpul de execuție ), cum ar fi Java, Python sau Perl. Deși această opțiune poate fi luată în considerare pentru dezvoltarea de noi programe, rămâne dificil de aplicat în cazul proiectelor existente, unde aceasta ar presupune rescrierea codului în noua limbă. [14]

O alternativă este utilizarea bibliotecilor sigure , adică a bibliotecilor de funcții care implementează protecții împotriva depășirii bufferului: în C reprezintă funcții vulnerabile strcat , strcpy , gets , sprintf (și altele ...) dintre care există omologi „siguri”, cum ar fi strncpy , strncat , snprintf . Exemple de biblioteci sigure sunt „libsafe”, „libparanoia” și „libverify”. [15] Libsafe, de exemplu, implementează o tehnică de protecție a depășirii bufferului stivei bazată pe verificarea modificărilor stivei atunci când o funcție se oprește din executare: dacă stiva este modificată, procesul se termină cu o eroare de segmentare . [16]

Apărări la nivelul codului sursă

Există instrumente capabile să detecteze vulnerabilitățile la depășirea bufferului în cadrul codului sursă prin efectuarea unor analize mai mult sau mai puțin complexe pe același, atât static, cât și dinamic.

„Its4” este un exemplu foarte simplu de analizor static care caută orice apeluri de funcții vulnerabile cunoscute (cum ar fi strcpy sau popen ), conceput ca un înlocuitor pentru căutarea prin grep : având în vedere simplitatea sa și analiza rudimentară a codului pe care îl transportă în afară , este foarte ușor să dai peste pozitive false și negative. [17]

Alternativ, există instrumente mai complexe capabile să efectueze analize dinamice ale programului, cum ar fi „Rational Purify”, un depanator de memorie realizat de IBM capabil să identifice orice anomalii în gestionarea memoriei în timpul execuției programului (acces la neinicializat, depășirea bufferului , necorespunzătoare repartizarea memoriei etc ...). [18]

Aparare la nivel de compilator

Limbajele de nivel mediu / scăzut, cum ar fi C, oferă performanțe ridicate tocmai pentru că „economisesc” pe anumite controale care nu sunt gestionate automat la nivelul limbii, lăsând această responsabilitate în sarcina programatorului și punând astfel bazele vulnerabilităților, cum ar fi bufferul depășire în caz de lipsă a controalelor asupra dimensiunii bufferelor în timpul conectării.

Una dintre tehnicile de apărare împotriva acestor anomalii este de a prevedea că compilatorul este cel care introduce verificările dimensiunii tuturor tampoanelor din codul compilat fără a necesita modificări în codul sursă, dar numai în compilator, dar pe cheltuială de ori care poate crește și cu peste 200%. [14] Aceasta a fost direcția luată de două proiecte diferite de compilare a compilatorului gcc scrise de Herman ten Brugge și Greg McGary. [19]

O abordare diferită este în schimb cea a „StackShield”, o extensie a compilatorului gcc pentru protecția împotriva spargerii stivei în sistemele Linux; în loc să insereze limitele bufferului verificând controalele la momentul compilării, obiectivul StackShield este de a preveni suprascrierea adreselor de retur prin stocarea unei copii într-o zonă sigură care nu poate fi suprascrisă (la începutul segmentului de date) la începutul fiecărui apel funcțional, copie care este apoi comparat la sfârșitul executării funcției cu valoarea stocată în stivă: dacă valorile nu se potrivesc StackShield poate termina execuția programului sau poate încerca să continue ignorând atacul și riscând blocarea maximă a programului. [20]

O altă extensie a compilatorului gcc , „StackGuard”, permite atât detectarea oricăror deborduri de tampon de stivă, cât și prevenirea acestora: prima apărare este totuși mult mai eficientă și mai portabilă decât a doua, care este în general mai puțin fiabilă și mai sigură. Revelația se bazează pe scrierea în cadrul stivei a unui cuvânt canar între variabilele locale și adresa de returnare stocată și pe presupunerea că nu este posibil să suprascrie RA fără a modifica cuvântul canar , care, prin urmare, ia acest nume tocmai în analogie cu utilizarea canarilor în minele de cărbune ca prim sistem de avertizare. Înainte de a readuce controlul la instrucțiunile indicate de RA, se verifică dacă cuvântul canar a suferit modificări: orice modificări sunt considerate ca o posibilă încercare de a modifica controlul execuției programului și, prin urmare, a unui atac. Tehnica adoptată de StackGuard este eficientă numai dacă atacatorul nu este în măsură să prezică cuvântul canar , în acest caz el ar fi capabil să proiecteze depășirea pentru a suprascrie cuvântul canar cu valoarea sa originală: StackGuard a acest scop efectuează randomizarea canarul . [21]

Apărări la nivelul sistemului de operare

Multe sisteme de operare au încercat să soluționeze problema depășirii bufferului prin impunerea de restricții asupra utilizării memoriei și prin aceasta făcând atacurile mai complexe.

Un mecanism de apărare pe scară largă la nivelul sistemului de operare se bazează pe faptul că anumite pagini de memorie, cum ar fi cele care conțin stive și grămezi , nu pot fi executate: orice încercare de a transfera controlul execuției în cod în aceste zone ridică, prin urmare, o excepție, împiedicând executarea acestuia. Acest lucru poate fi realizat prin exploatarea anumitor caracteristici hardware ale procesoarelor cunoscute sub numele de bitul " NX " ("Fără eXecute") sau bitul "XD" ("eXecute Disabled") sau prin tehnici software care imită această operațiune.

Unele sisteme de operare bazate pe UNIX precum OpenBSD și OS X acceptă direct protecția spațiului executabil , pentru alte sisteme de operare este disponibil prin extensii opționale, cum ar fi:

Versiunile mai noi ale Microsoft Windows îl acceptă sub numele de Data Execution Prevention (DEP) (sau Data Execution Prevention). [25]

O altă tehnică de apărare la nivelul sistemului de operare este randomizarea aspectului spațiului de adresare (ASLR) care constă în a face parțial aleatorie adresa celor mai importante funcții de bibliotecă și zone de memorie; acest lucru face mai complexă (dar nu imposibilă) executarea codului prin exploatări, deoarece obligă atacatorul să caute adresa codului care trebuie executat printr-o serie de încercări detectabile atât de către victimă, cât și de orice SW de protecție. [26]

Notă

  1. ^ "Studiu de planificare a tehnologiei securității computerelor" - Pagina 61 ( PDF ), pe csrc.nist.gov . Adus la 5 septembrie 2016 (arhivat din original la 21 iulie 2011) .
  2. ^ În interiorul Buffer Overflow Attack: Mechanism, Method, & Prevention , pe sans.org .
  3. ^ De ce exploatarea depășirii bufferului a durat atât de mult până la maturitate , pe rdist , 3 mai 2010. Adus pe 5 septembrie 2016 .
  4. ^ Thomas Lopatic, Bugtraq: Vulnerability in NCSA HTTPD 1.3 , at seclists.org . Accesat la 5 septembrie 2016 .
  5. ^ Ce este Code Red Worm? , pe sans.org .
  6. ^ Vierme SQL Slammer , la pen-testing.sans.org .
  7. ^ CWE - 2011 CWE / SANS Top 25 Cele mai periculoase erori de software , la cwe.mitre.org . Adus la 17 august 2016 .
  8. ^ (RO) CVE-2015-7547: glibc getaddrinfo overflow tampon bazat pe stivă , pe security.googleblog.com. Adus la 6 septembrie 2016 .
  9. ^ Defecțiune de securitate critică: depășirea bufferului pe bază de stivă glibc în getaddrinfo () (CVE-2015-7547) - Portalul clienților Red Hat , la access.redhat.com . Adus la 6 septembrie 2016 .
  10. ^ a b c William Stallings, Lawrie Brown, Computer Security - Principles and Practice , Pearson, 2015, ISBN 978-0-13-377392-7 .
  11. ^ Jon Erickson, Hacking - The Art of Exploitation , No Starch Press, 2008, ISBN 978-1-59327-144-2 .
  12. ^ Vulnerability Note VU # 363715 - Microsoft Internet Information Server (IIS) vulnerabil la depășirea heap-ului în timpul procesării cererii ".htr" realizate de filtrul ISAPI "ISM.DLL" , la www.kb.cert.org . Adus pe 19 august 2016 .
  13. ^ Buffer Overflows for Dummies - SANS Institute , la sans.org .
  14. ^ a b c RSA Laboratories - Contramăsuri împotriva atacurilor de depășire a tamponului , la www.preserve-it-all.org . Adus la 31 august 2016 .
  15. ^ 3.3. Buffer Overflows , la www.freebsd.org . Adus la 31 august 2016 .
  16. ^ Libsafe - Free Software Directory , la directory.fsf.org . Accesat la 4 septembrie 2016 .
  17. ^ Its4 , pe seclab.cs.ucdavis.edu .
  18. ^ Rational Purify , la www-01.ibm.com .
  19. ^ Extensii vechi Gcc [ link rupt ] , pe ftp.tuwien.ac.at .
  20. ^ StackShield , la angelfire.com .
  21. ^ StackGuard: Detecție automată adaptivă și prevenirea atacurilor de depășire a tamponului ( PDF ), la usenix.org .
  22. ^ Pagina de pornire a PaX , la pax.grsecurity.net . Accesat la 4 septembrie 2016 (arhivat din original la 27 octombrie 2016) .
  23. ^ "Exec Shield", noua caracteristică de securitate Linux [LWN.net] , pe lwn.net . Accesat la 4 septembrie 2016 .
  24. ^ Openwall - aducerea securității în medii de calcul deschise , la www.openwall.com . Accesat la 4 septembrie 2016 .
  25. ^ McAfee KnowledgeBase - Prevenirea executării programului și protecția împotriva depășirii bufferului , la kc.mcafee.com . Accesat la 4 septembrie 2016 .
  26. ^ Randomizarea aspectului spațiului de adrese ( PDF ), pe symantec.com . Adus la 30 aprilie 2019 (arhivat din original la 15 iulie 2019) .

Bibliografie

Elemente conexe

linkuri externe

Controlul autorității GND ( DE ) 4752450-9
Securitate IT Portal de securitate IT : accesați intrările Wikipedia care se ocupă cu securitatea IT