Programare orientată spre returnare

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită la 28 iulie 2015; verificările necesită 7 modificări .

Programarea orientată pe returnare ( ROP ) este o  metodă de exploatare a vulnerabilităților din software , prin care un atacator poate executa codul de care are nevoie dacă în sistem există tehnologii de protecție, de exemplu, o tehnologie care interzice execuția codului din anumite pagini de memorie . 1] . Metoda constă în faptul că atacatorul poate câștiga controlul asupra stivei de apeluri , poate găsi în cod secvențe de instrucțiuni care efectuează acțiunile necesare și se numesc „gadgets”, executa „gadget-uri” în secvența dorită [2]. Un „gadget” se termină de obicei cu o instrucțiune de returnare și se află în memoria principală în codul existent (în codul programului sau codul bibliotecii partajate ). Atacatorul realizează execuția secvențială a gadget-urilor folosind instrucțiuni de returnare, aranjează o secvență de gadget-uri în așa fel încât să efectueze operațiunile dorite. Atacul este fezabil chiar și pe sistemele care au mecanisme de prevenire a atacurilor mai simple.

Istorie

Atacul de depășire a tamponului

Programarea orientată pe returnare este o versiune avansată a atacului de buffer overflow . În acest atac, atacatorul folosește un bug în program atunci când funcția nu verifică (sau verifică incorect) limitele atunci când scrie în memoria tampon de date primite de la utilizator. Dacă utilizatorul trimite mai multe date decât dimensiunea bufferului, atunci datele suplimentare intră în zona de memorie destinată altor variabile locale și, de asemenea, pot suprascrie adresa de retur. Dacă adresa de retur este suprascrisă, atunci când funcția revine, controlul va fi transferat către noua adresă scrisă.

În cea mai simplă versiune a unui atac de buffer overflow, atacatorul împinge codul („încărcare utilă”) în stivă și apoi suprascrie adresa de retur cu adresa instrucțiunilor pe care tocmai le-a scris. Până la sfârșitul anilor 1990, majoritatea sistemelor de operare nu au oferit nicio protecție împotriva acestor atacuri. Sistemele Windows nu au avut protecție împotriva atacurilor de buffer overflow până în 2004. [3] În cele din urmă, sistemele de operare au început să se ocupe de exploatarea vulnerabilităților de depășire a memoriei tampon prin marcarea anumitor pagini de memorie ca neexecutabile (o tehnică numită „Prevenirea executării datelor”). Cu prevenirea execuției datelor activată, aparatul va refuza să execute cod pe paginile de memorie marcate „numai date”, inclusiv paginile care conțin o stivă. Acest lucru vă împiedică să împingeți sarcina utilă pe stivă și apoi să săriți la ea, suprascriind adresa de retur. Mai târziu, suportul hardware pentru Data Execution Prevention a părut să îmbunătățească protecția .

Atacul înapoi la bibliotecă

Data Execution Prevention previne atacul prin metoda descrisă mai sus. Atacatorul este limitat la codul deja din programul atacat și bibliotecile partajate. Cu toate acestea, bibliotecile partajate, cum ar fi libc , conțin adesea funcții pentru a efectua apeluri de sistem și alte funcții utile pentru un atacator, ceea ce permite ca aceste funcții să fie utilizate într-un atac.

Atacul de returnare a bibliotecii exploatează, de asemenea, o depășire a tamponului. Adresa de retur este suprascrisă de punctul de intrare al funcției de bibliotecă dorită. Celulele de deasupra adresei de retur sunt, de asemenea, suprascrise pentru a trece parametrii funcției sau a înlănțui apeluri multiple. Această tehnică a fost introdusă pentru prima dată de Alexander Peslyak (cunoscut sub numele de Solar Designer) în 1997, [4] și de atunci a fost extinsă pentru a permite un lanț nelimitat de apeluri de funcție. [5]

Împrumutarea fragmentelor de cod

Odată cu răspândirea hardware-ului și a sistemelor de operare pe 64 de biți, a devenit mai dificil să se efectueze un atac de returnare a bibliotecii: în convențiile de apelare utilizate în sistemele pe 64 de biți, primii parametri sunt trecuți funcției nu pe stivă, ci în registre. Acest lucru complică pregătirea parametrilor care urmează să fie apelați în timpul atacului. În plus, dezvoltatorii de biblioteci partajate au început să elimine sau să restricționeze funcțiile „periculoase”, cum ar fi pachetele de apeluri de sistem, din biblioteci.

Următoarea rundă de dezvoltare a atacului a fost utilizarea unor părți ale funcțiilor bibliotecii în loc de funcții întregi. [6] Această tehnică caută părți ale funcțiilor care împing datele din stivă în registre. Selectarea atentă a acestor părți vă permite să pregătiți parametrii necesari în registre pentru apelarea funcției conform noii convenții. Mai mult, atacul este efectuat în același mod ca și atacul de întoarcere a bibliotecii.

Atacul prin programare orientată spre întoarcere

Programarea orientată spre returnare extinde abordarea de împrumut de cod, oferind atacatorului funcționalitate completă Turing , inclusiv bucle și ramuri . [7] Cu alte cuvinte, programarea orientată spre întoarcere oferă unui atacator capacitatea de a efectua orice operațiune. Hovav Shaham a publicat o descriere a metodei în 2007 [8] și a demonstrat-o pe un program care folosește biblioteca standard C și conține o vulnerabilitate de depășire a tamponului. Programarea orientată spre întoarcere este superioară celorlalte tipuri de atacuri descrise mai sus atât în ​​ceea ce privește puterea expresivă, cât și rezistența la măsurile defensive. Niciuna dintre metodele de mai sus de contracarare a atacurilor, inclusiv eliminarea funcțiilor periculoase din bibliotecile partajate, nu este eficientă împotriva programării orientate spre returnare.

Spre deosebire de atacul return-to-library, care folosește funcții întregi, programarea orientată spre returnare folosește secvențe mici de instrucțiuni care se termină cu o instrucțiune de returnare, așa-numitele „gadgets”. Gadget-urile sunt, de exemplu, terminații ale funcțiilor existente. Cu toate acestea, pe unele platforme, în special x86 , gadgeturile pot apărea „între linii”, adică atunci când se decodează de la mijlocul unei instrucțiuni existente. De exemplu, următoarea secvență de instrucțiuni: [8]

test edi , 7 ; f7 c7 07 00 00 00 setnz byte [ ebp-61 ] ; 0f 95 45 c3

când decodificarea începe cu un octet mai târziu, dă

mov dword [ edi ], 0 f000000h ; c7 07 00 00 00 0f xchg ebp , eax ; 95 inc ebp ; 45 ret ; c3

Gadget-urile pot fi, de asemenea, în date, dintr-un motiv sau altul situat în secțiunea de cod. Acest lucru se datorează faptului că setul de instrucțiuni x86 este destul de dens, ceea ce înseamnă că există șanse mari ca un flux arbitrar de octeți să fie interpretat ca un flux de instrucțiuni reale. Pe de altă parte, în arhitectura MIPS , toate instrucțiunile au o lungime de 4 octeți și pot fi executate numai instrucțiunile aliniate la adrese care sunt multipli de 4 octeți. Prin urmare, nu există nicio modalitate de a obține o nouă secvență „prin citirea între rânduri”.

Atacul exploatează o vulnerabilitate de depășire a tamponului. Adresa de retur din funcția curentă este suprascrisă cu adresa primului gadget. Pozițiile ulterioare din stivă conțin adresele următoarelor gadgeturi și datele utilizate de gadgeturi.

Exemple

Extensii

În versiunea sa originală pentru platforma x86, gadget-urile sunt lanțuri de instrucțiuni aranjate secvențial, fără sărituri, care se termină cu o instrucțiune aproape de întoarcere. În versiunile extinse ale atacului, instrucțiunile în lanț pot să nu fie neapărat secvențiale, dar sunt conectate prin instrucțiuni directe de salt. De asemenea, rolul instrucțiunii finale poate fi îndeplinit de o altă instrucțiune de returnare (în x86 există și o instrucțiune de returnare departe, instrucțiuni de returnare aproape și departe cu ștergere stivă), o instrucțiune de salt indirect sau chiar o instrucțiune de apel indirect. Acest lucru complică lupta împotriva acestei metode de atac.

Generare automată

Există instrumente pentru găsirea automată a gadgeturilor și proiectarea unui atac. Un exemplu de astfel de instrument este ROPgadget. [9]

Protecție împotriva programării orientate spre întoarcere

Există mai multe metode de protejare împotriva programării orientate pe întoarcere. [10] Majoritatea se bazează pe locația codului programului și a bibliotecilor la o adresă relativ arbitrară, astfel încât un atacator nu poate prezice cu exactitate locația instrucțiunilor care ar putea fi utile în gadget-uri și, prin urmare, nu poate construi un lanț de gadget-uri pentru a ataca. O implementare a acestei metode, ASLR , încarcă biblioteci partajate la o adresă diferită de fiecare dată când programul este rulat. Cu toate acestea, deși această tehnologie este utilizată pe scară largă în sistemele de operare moderne, este vulnerabilă la atacurile de scurgere de informații și alte atacuri care permit determinarea poziției unei funcții de bibliotecă cunoscute. Dacă un atacator poate determina locația unei funcții, el poate determina locația tuturor instrucțiunilor din bibliotecă și poate efectua un atac de programare orientat spre întoarcere.

Puteți rearanja nu numai biblioteci întregi, ci și instrucțiuni individuale ale programelor și bibliotecilor. [11] Cu toate acestea, acest lucru necesită asistență extinsă în timpul execuției, cum ar fi traducerea dinamică, pentru a pune instrucțiunile permutate înapoi în ordinea corectă pentru execuție. Această metodă face mai dificilă găsirea și utilizarea gadgeturilor, dar are o suprasolicitare mare.

Abordarea kBouncer [12] este de a verifica dacă instrucțiunea de returnare transferă controlul instrucțiunii imediat după instrucțiunea de apel. Acest lucru reduce foarte mult setul de gadgeturi posibile, dar provoacă și un impact semnificativ de performanță. [12] În plus, într-o versiune extinsă de programare orientată spre întoarcere, gadgeturile pot fi conectate nu numai cu o instrucțiune de returnare, ci și cu o instrucțiune indirectă de salt sau apel. Împotriva unui astfel de atac extins, kBouncer va fi ineficient.

Note

  1. Shacham, Hovav; Buchanan, Eric; Romer, Ryan; Savage, Stefan Programare orientată spre returnare: Exploits fără injectare de cod . Preluat la 12 august 2009. Arhivat din original la 1 iunie 2010.
  2. Erik Buchanan, Ryan Roemer, Hovav Shacham și Stefan Savage; When Good Instructions Go Bad: Generalizing Return-Oriented Programming to RISC Arhivat 11 august 2017 la Wayback Machine , în Proceedings of CCS 2008 , ACM Press, octombrie 2008.
  3. Prevenirea execuției datelor Microsoft Windows XP SP2 . Consultat la 10 aprilie 2014. Arhivat din original pe 14 aprilie 2018.
  4. Solar Designer, Return-into-lib(c) exploits Arhivat 23 februarie 2018 la Wayback Machine , Bugtraq
  5. Nergal, Phrack 58 Articolul 4, return-into-lib(c) exploits Arhivat 25 aprilie 2013 la Wayback Machine
  6. Sebastian Krahmer, x86-64 buffer overflow exploits și tehnica de exploatare a bucăților de cod împrumutate Arhivat la 22 decembrie 2018 la Wayback Machine , 28 septembrie 2005
  7. Martín Abadi, Mihai Budiu, Úlfar Erlingsson și Jay Ligatti. Integritatea fluxului de control: principii, implementări și aplicații . În Catherine Meadows și Ari Juels, editori, Proceedings of CCS 2005 . ACM. octombrie 2005
  8. 1 2 Hovav Shacham. Geometria cărnii nevinovate pe os: return-in-libc fără apeluri de funcție (pe x86) . În Proceedings of the 14th ACM Conference on Computer and Communications Security (CCS '07) . ACM 2007
  9. Jonathan Salwan și Allan Wirth, ROPgadget - Căutare de gadgeturi și auto-roper Arhivat la 18 aprilie 2014 la Wayback Machine
  10. Richard Skowyra, Kelly Casteel, Hamed Okhravi și William Streilein; Analiza sistematică a apărărilor împotriva programării orientate spre întoarcere Arhivată la 22 februarie 2014 la Wayback Machine , În Proceedings of RAID 2013 , Lecture Notes in Computer Science (LNCS), Vol. 8145, pp. 82-102, 2013.
  11. Jason Hiser, Anh Nguyen-Tuong, Michele Co, Matthew Hall, JackW. Davidson, ILR: Unde au ajuns gadgeturile mele? Proceedings of the IEEE Symposium on Security and Privacy, mai 2012, San Francisco, CA
  12. 1 2 Vasilis Pappas. kBouncer: Efficient and Transparent ROP Mitigation Arhivat 30 august 2017 la Wayback Machine . aprilie 2012.