Kontrol-flow integritet

Den aktuelle version af siden er endnu ikke blevet gennemgået af erfarne bidragydere og kan afvige væsentligt fra den version , der blev gennemgået den 6. maj 2022; checks kræver 3 redigeringer .

Control-flow integrity ( CFI ) er en generel betegnelse for computersikkerhedsteknikker, der har til formål at begrænse de mulige stier til programafvikling inden for en forudsagt kontrolflowgraf for at øge dens sikkerhed [1] . CFI gør det sværere for en hacker at tage kontrol over udførelsen af ​​et program ved at gøre det umuligt for nogle måder at genbruge allerede eksisterende dele af maskinkoden. Lignende teknikker omfatter code-pointer separation (CPS) og code-pointer integrity (CPI) [2] [3] .

CFI-understøttelse er til stede i Clang [4] og GCC [5] kompilatorerne samt Control Flow Guard [6] og Return Flow Guard [7] fra Microsoft og Genbrug Attack Protector [8] fra PaX Team.

Historie

Opfindelsen af ​​måder at beskytte mod eksekvering af vilkårlig kode, såsom Data Execution Prevention og NX-bit , har ført til fremkomsten af ​​nye metoder, der giver dig mulighed for at få kontrol over programmet (for eksempel returorienteret programmering ) [ 8] . I 2003 udgav PaX Team et dokument, der beskrev mulige situationer, der fører til hacking af programmet, og ideer til beskyttelse mod dem [8] [9] . I 2005 formaliserede en gruppe Microsoft-forskere disse ideer og opfandt udtrykket Control-flow Integrity for at henvise til metoder til beskyttelse mod ændringer i et programs oprindelige kontrolflow. Ud over dette foreslog forfatterne en metode til instrumentering af allerede kompileret maskinkode [1] .

Efterfølgende foreslog forskere, baseret på ideen om CFI, mange forskellige måder at øge programmets modstand mod angreb. De beskrevne tilgange er ikke blevet brugt i vid udstrækning af årsager, herunder store programopbremsninger eller behovet for yderligere information (f.eks. opnået gennem profilering ) [10] .

I 2014 offentliggjorde et team af forskere fra Google et papir, der så på implementeringen af ​​CFI for industrielle compilere GCC og LLVM til instrumentering af C++-programmer. Officiel CFI-støtte blev tilføjet i 2014 i GCC 4.9.0 [5] [11] og i 2015 i Clang 3.7 [12] [13] . Microsoft udgav Control Flow Guard i 2014 til Windows 8.1 og tilføjede understøttelse fra operativsystemet til Visual Studio 2015 [6] .

Beskrivelse

Hvis der er indirekte hop i programkoden , er det potentielt muligt at overføre styringen til en hvilken som helst adresse , hvor kommandoen kan findes (f.eks. på x86 vil det være enhver mulig adresse, da den mindste kommandolængde er en byte [14] ). Hvis en angriber på en eller anden måde kan ændre den værdi, som kontrol overføres med, når han udfører en springinstruktion, så kan han genbruge den eksisterende programkode til sine egne behov.

I rigtige programmer fører ikke-lokale spring normalt til begyndelsen af ​​funktioner (f.eks. hvis en procedurekaldsinstruktion bruges) eller til instruktionen efter den kaldende instruktion (procedureretur). Den første type overgange er en direkte (engelsk fremadkant ) overgang, da den vil blive angivet med en direkte bue på kontrolflowgrafen. Den anden type kaldes tilbage (eng. back-edge ) overgang, analogt med den første - buen svarende til overgangen vil være omvendt [15] .

Direkte overgange

Ved direkte hop vil antallet af mulige adresser, som kontrol kan overføres til, svare til antallet af funktioner i programmet. Når der tages højde for typesystemet og semantikken for det programmeringssprog , som kildekoden er skrevet i, er yderligere begrænsninger mulige [16] . For eksempel, i C++ , i et korrekt program , skal en funktionsmarkør, der bruges i et indirekte kald, indeholde adressen på en funktion med samme type som selve pointeren [ 17] .

En måde at implementere kontrol-flow-integritet for direkte spring er, at du kan analysere programmet og bestemme sættet af juridiske adresser for forskellige greninstruktioner [1] . For at bygge et sådant sæt bruges statisk kodeanalyse sædvanligvis på et eller andet abstraktionsniveau (på niveau med kildekode , intern repræsentation af analysatoren eller maskinkode [1] [10] ). Derefter, ved hjælp af den modtagne information, indsættes koden ved siden af ​​instruktionerne fra den indirekte gren for at kontrollere, om den adresse, der modtages ved kørsel, matcher den statisk beregnede. Ved divergens går programmet normalt ned, selvom implementeringer giver dig mulighed for at tilpasse adfærden i tilfælde af en overtrædelse af det forudsagte kontrolflow [18] [19] . Således er kontrolflowgrafen begrænset til kun de kanter (funktionskald) og toppunkter (funktionsindgangspunkter) [1] [16] [20] , der evalueres under statisk analyse, så når man forsøger at ændre den pointer, der bruges til indirekte spring , vil angriberen mislykkes.

Denne metode giver dig mulighed for at forhindre springorienteret programmering [21] og opkaldsorienteret programmering [22] , da sidstnævnte aktivt anvender direkte indirekte spring.

Omvendt overgange

For tilbagegående overgange er flere tilgange til implementering af CFI mulige [8] .

Den første tilgang er baseret på de samme antagelser som CFI for direkte spring, det vil sige evnen til at beregne returadresser fra en funktion [23] .

Den anden tilgang er at behandle returadressen specifikt. Udover blot at gemme det på stakken , gemmes det også, muligvis med nogle ændringer, til et sted, der er specielt tildelt det (for eksempel til et af processorregistrene). Før returinstruktionen tilføjes også kode, der gendanner returadressen og kontrollerer den mod den på stakken [8] .

Den tredje tilgang kræver yderligere support fra hardwaren. Sammen med CFI anvendes en skyggestak - et særligt hukommelsesområde, der er utilgængeligt for en angriber, hvori der gemmes returadresser, når funktioner kaldes [24] .

Ved implementering af CFI-skemaer for tilbagespring er det muligt at forhindre et retur -til-bibliotek-angreb og retur - orienteret programmering baseret på ændring af returadressen på stakken [ 23] .

Eksempler

I dette afsnit vil eksempler på kontrol-flow-integritetsimplementeringer blive overvejet.

Clang Indirekte funktion Opkaldskontrol

Indirect Function Call Checking (IFCC) omfatter kontrol for indirekte hop i et program, med undtagelse af nogle "særlige" hop, såsom virtuelle funktionskald. Når der konstrueres et sæt adresser, hvortil der kan ske en overgang, tages der hensyn til funktionens type. Takket være dette er det muligt at forhindre ikke kun brugen af ​​forkerte værdier, der ikke peger på begyndelsen af ​​funktionen, men også forkert type casting i kildekoden. For at aktivere kontrol i compileren er der en mulighed -fsanitize=cfi-icall[4] .

// clang-ifcc.c #include <stdio.h> int sum ( int x , int y ) { returner x + y _ } int dbl ( int x ) { returnere x + x ; } void call_fn ( int ( * fn )( int )) { printf ( "Resultatværdi: %d \n " , ( * fn )( 42 )); } void erase_type ( void * fn ) { // Opførsel er udefineret, hvis den dynamiske type af fn ikke er den samme som int (*)(int). call_fn ( fn ); } int main () { // Når du kalder erase_type, går statisk typeinformation tabt. slette_type ( sum ); returnere 0 ; }

Et program uden kontrol kompilerer uden nogen fejlmeddelelser og udføres med et udefineret resultat, der varierer fra kørsel til kørsel:

$ clang -Wall -Wextra clang-ifcc.c $ ./a.ud Resultatværdi: 1388327490

Sammensat med følgende muligheder får du et program, der afbryder, når call_fn kaldes.

$ clang -flto -fvisibility=skjult -fsanitize=cfi -fno-sanitize-trap=alle clang-ifcc.c $ ./a.ud clang-ifcc.c:12:32: runtime error: kontrol flow integritetskontrol for typen 'int (int)' mislykkedes under indirekte funktionskald (./a.out+0x427a20): bemærk: (ukendt) defineret her

Clang Forward-Edge CFI til virtuelle opkald

Denne metode er rettet mod at kontrollere integriteten af ​​virtuelle opkald i C++-sproget. For hvert klassehierarki, der indeholder virtuelle funktioner , er der bygget bitmaps, der viser, hvilke funktioner der kan kaldes for hver statisk type. Hvis tabellen over virtuelle funktioner for ethvert objekt er beskadiget under udførelse i programmet (f.eks. forkert type, der kaster hierarkiet ned eller blot hukommelseskorruption af en angriber), vil den dynamiske type af objektet ikke matche nogen af ​​de forudsagte statisk [10] [25] .

// virtual-calls.cpp #include <cstdio> struktur B { virtual void foo () = 0 ; virtuel ~ B () {} }; struct D : public B { void foo () tilsidesætte { printf ( "Højre funktion \n " ); } }; struct Bad : public B { void foo () tilsidesætte { printf ( "Forkert funktion \n " ); } }; int main () { Dårlig dårlig ; // C++-standarden tillader casting som denne: B & b = static_cast < B &> ( bad ); // Afledt1 -> Base -> Afledt2. D & normal = statisk_kast < D &> ( b ); // Som et resultat er objektets dynamiske type normal normal . foo (); // vil være dårlig, og den forkerte funktion vil blive kaldt. returnere 0 ; }

Efter kompilering uden kontrol aktiveret:

$ clang++ -std=c++11 virtual-calls.cpp $ ./a.ud Forkert funktion

I programmet kaldes fooklasseimplementeringen fra . Dette problem vil blive fanget, hvis du kompilerer programmet med : DfooBad-fsanitize=cfi-vcall

$ clang++ -std=c++11 -Væg -flto -fvisibility=skjult -fsanitize=cfi-vcall -fno-sanitize-trap=alle virtuelle-opkald.cpp $ ./a.ud virtual-calls.cpp:24:3: runtime error: kontrolflowintegritetskontrol for type 'D' mislykkedes under virtuelt opkald (vtable-adresse 0x000000431ce0) 0x000000431ce0: bemærk: vtable er af typen 'Dårlig' 00 00 00 00 30 a2 42 00 00 00 00 00 e0 a1 42 00 00 00 00 00 60 a2 42 00 00 00 00 00 00 00 00 00 ^

Noter

  1. ↑ 1 2 3 4 5 Martín Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti. Kontrol-flow-integritet  // Proceedings of the 12th ACM Conference on Computer and Communications Security. - New York, NY, USA: ACM, 2005. - S. 340-353 . — ISBN 1595932267 . - doi : 10.1145/1102120.1102165 .
  2. Volodymyr Kuznetsov, László Szekeres, Mathias Payer, George Candea, R. Sekar. Code-pointer Integrity  // Proceedings of the 11th USENIX Conference on Operating Systems Design and Implementation. - Berkeley, CA, USA: USENIX Association, 2014. - S. 147-163 . — ISBN 9781931971164 .
  3. ↑ Om forskelle mellem CFI-, CPS- og CPI-egenskaberne  . nebelwelt.net. Hentet 22. december 2017. Arkiveret fra originalen 22. december 2017.
  4. ↑ 1 2 Control Flow Integrity - Clang 5 dokumentation . releases.llvm.org. Hentet 22. december 2017. Arkiveret fra originalen 23. december 2017.
  5. ↑ 1 2 vtv - GCC Wiki . gcc.gnu.org. Hentet 22. december 2017. Arkiveret fra originalen 11. juli 2017.
  6. 1 2 Kontrol af flowvagt (Windows  ) . msdn.microsoft.com. Hentet 22. december 2017. Arkiveret fra originalen 22. december 2017.
  7. ↑ Return Flow Guard - Tencents Xuanwu Lab  . xlab.tencent.com. Hentet 22. december 2017. Arkiveret fra originalen 23. december 2017.
  8. ↑ 1 2 3 4 5 grsikkerhed  . _ www.grsecurity.net. Hentet 22. december 2017. Arkiveret fra originalen 17. februar 2018.
  9. [1] Arkiveret 5. august 2017 på Wayback Machine PaX future
  10. ↑ 1 2 3 Caroline Tice, Tom Roeder, Peter Collingbourne, Stephen Checkoway, Úlfar Erlingsson. Håndhævelse af fremadrettet kontrolflowintegritet i GCC & LLVM  // Proceedings of the 23rd USENIX Conference on Security Symposium. - Berkeley, CA, USA: USENIX Association, 2014. - S. 941-955 . — ISBN 9781931971157 .
  11. GCC 4.9 Release Series - GNU Project - Free Software Foundation (FSF  ) . gcc.gnu.org. Hentet 22. december 2017. Arkiveret fra originalen 15. januar 2018.
  12. Clang 3.7 Release Notes — Clang 3.7 dokumentation . releases.llvm.org. Hentet 22. december 2017. Arkiveret fra originalen 26. november 2017.
  13. LLVM-udgivelser . releases.llvm.org. Hentet 22. december 2017. Arkiveret fra originalen 15. december 2017.
  14. Softwareudviklermanualer til Intel® 64 og IA-32 Architectures | Intel®-  software . software.intel.com. Hentet 22. december 2017. Arkiveret fra originalen 25. december 2017.
  15. Sikkerhed - WebAssembly . webassembly.org. Hentet 22. december 2017. Arkiveret fra originalen 23. december 2017.
  16. ↑ 1 2 Aho, Alfred W.; Seti, Ravi; Ullman, Jeffrey D. Compilers - Principles, Technologies, Tools, 2. udg . - Williams. - 2008. - S.  1062 -1066. - ISBN 978-5-8459-1349-4 .
  17. ISO/IEC 14882:2014 - Informationsteknologi - Programmeringssprog - C++ . - ISO . - 2014. - S. 105. Arkivkopi dateret 29. april 2016 på Wayback Machine
  18. Vtable Verification - User's Guide . docs.google.com. Hentet 22. december 2017. Arkiveret fra originalen 12. juni 2019.
  19. Control Flow Integrity - Clang 5 dokumentation . releases.llvm.org. Hentet 22. december 2017. Arkiveret fra originalen 23. december 2017.
  20. Muchnick, Steven S. Advanced Compiler Design and Implementation . - Morgan Kaufmann Publishers , 1997. - S.  609 -618. - ISBN 1-55860-320-4 .
  21. Tyler Bletsch, Xuxian Jiang, Vince W. Freeh, Zhenkai Liang. Hop-orienteret programmering: En ny klasse af kodegenbrugsangreb  // Proceedings of the 6th ACM Symposium on Information, Computer and Communications Security. - New York, NY, USA: ACM, 2011. - S. 30-40 . — ISBN 9781450305648 . - doi : 10.1145/1966913.1966919 .
  22. AliAkbar Sadeghi, Salman Niksefat, Maryam Rostamipour. Pure-Call Oriented Programming (PCOP): kæde gadgets ved hjælp af opkaldsinstruktioner  //  Journal of Computer Virology and Hacking Techniques. — 2017-05-15. - S. 1-18 . — ISSN 2263-8733 . - doi : 10.1007/s11416-017-0299-1 . Arkiveret fra originalen den 22. december 2017.
  23. ↑ 1 2 RAP: RIP ROP - Genbrug angrebsbeskytter (downlink) . PaX Team . Hentet 22. december 2017. Arkiveret fra originalen 20. maj 2020. 
  24. Forhåndsvisning af kontrol-flow håndhævelsesteknologi . Intel Developer Zone . Hentet 22. december 2017. Arkiveret fra originalen 14. august 2017.
  25. Control Flow Integrity Design Documentation - Clang 5 dokumentation . releases.llvm.org. Hentet 22. december 2017. Arkiveret fra originalen 23. december 2017.

Litteratur

Bøger Artikler
  • Martín Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti. Kontrol-flow-integritet  // Proceedings of the 12th ACM Conference on Computer and Communications Security. - New York, NY, USA: ACM, 2005. - S. 340-353 . — ISBN 1595932267 . - doi : 10.1145/1102120.1102165 .
  • Caroline Tice, Tom Roeder, Peter Collingbourne, Stephen Checkoway, Úlfar Erlingsson. Håndhævelse af fremadrettet kontrolflowintegritet i GCC & LLVM  // Proceedings of the 23rd USENIX Conference on Security Symposium. - Berkeley, CA, USA: USENIX Association, 2014. - S. 941-955 . — ISBN 9781931971157 .

Links