Et bufferoverløb er et fænomen , der opstår, når et computerprogram skriver data uden for en buffer, der er allokeret i hukommelsen .
Bufferoverløb skyldes normalt ukorrekt håndtering af eksternt modtagne data og hukommelse, i mangel af stærk beskyttelse fra programmeringsundersystemet ( kompiler eller fortolker ) og operativsystemet . Som et resultat af et overløb kan data placeret efter bufferen (eller før den) [1] blive beskadiget .
Bufferoverløb er en af de mest populære måder at hacke computersystemer på [2] , da de fleste sprog på højt niveau bruger stack frame- teknologi - placere data på processtakken , blande programdata med kontroldata (inklusive startadressen for stackramme og returadressen fra den eksekverbare funktion).
Et bufferoverløb kan få et program til at gå ned eller hænge, hvilket fører til et lammelsesangreb ( DoS ). Visse typer overløb, såsom et stackframe-overløb, tillader en hacker at indlæse og udføre vilkårlig maskinkode på vegne af programmet og med rettighederne til den konto, hvorfra det kører [3] .
Eksempler er kendt, når bufferoverløb bevidst bruges af systemprogrammer til at omgå begrænsninger i eksisterende software eller firmware. For eksempel brugte iS-DOS- operativsystemet (til ZX Spectrum-computere ) bufferoverløbsfunktionen i den indbyggede TR-DOS til at starte sin bootloader i maskinkoder (hvilket er umuligt at gøre med standard TR-DOS-værktøjer).
Et program, der bruger en sårbarhed til at bryde beskyttelsen af et andet program, kaldes en udnyttelse . De farligste er udnyttelser designet til at få adgang til superbruger -niveauet, eller med andre ord privilegie-eskalering . Bufferoverløbsudnyttelsen opnår dette ved at sende specialfremstillede input til programmet. Sådanne data flyder over den tildelte buffer og ændrer de data, der følger efter bufferen i hukommelsen . [fire]
Forestil dig et hypotetisk systemadministrationsprogram , der kører med superbrugerrettigheder - for eksempel ændring af brugeradgangskoder . Hvis programmet ikke kontrollerer længden af den indtastede nye adgangskode, vil alle data, der overstiger størrelsen af bufferen, der er allokeret til deres opbevaring, simpelthen blive skrevet over det, der var efter bufferen. En angriber kan indsætte maskinsprogsinstruktioner i dette hukommelsesområde , for eksempel shellcode , udføre enhver handling med superbrugerrettigheder - tilføje og slette brugerkonti, ændre adgangskoder, ændre eller slette filer osv. Hvis det udføres i dette hukommelsesområde tilladt, og i i fremtiden vil programmet overføre kontrol til det, vil systemet udføre hackerens maskinkode, der er placeret der.
Velskrevne programmer bør kontrollere længden af inputdataene for at sikre, at de ikke er større end den tildelte databuffer. Men programmører glemmer det ofte. Hvis bufferen er placeret på stakken, og stakken "vokser ned" (for eksempel i x86 -arkitekturen ), kan du ved hjælp af et bufferoverløb ændre returadressen for den udførte funktion , da returadressen er placeret efter buffer tildelt af den udførte funktion. Det er således muligt at udføre en vilkårlig sektion af maskinkode i processens adresserum. Det er muligt at bruge et bufferoverløb til at ødelægge returadressen, selvom stakken "vokser op" (i hvilket tilfælde returadressen normalt er før bufferen). [5]
Selv erfarne programmører har svært ved at afgøre, om et givet bufferoverløb kan være en sårbarhed. Dette kræver dybt kendskab til computerarkitekturen og målprogrammet. Det har vist sig, at selv så små overløb som at skrive en enkelt byte ud af bufferen kan repræsentere sårbarheder. [6]
Bufferoverløb er almindelige i programmer skrevet på relativt lavt niveau programmeringssprog, såsom assemblersprog , C og C++ , som kræver, at programmøren kontrollerer størrelsen af den tildelte hukommelse. Bufferoverløbsfejlfinding er stadig en dårligt automatiseret proces. Formelle programverifikationssystemer er ikke særlig effektive med moderne programmeringssprog. [7]
Mange programmeringssprog, såsom Perl , Python , Java og Ada , administrerer hukommelsesallokering automatisk, hvilket gør bufferoverløbsfejl usandsynlige eller umulige. [8] Perl giver automatisk ændring af størrelsen af arrays for at undgå bufferoverløb . Runtime-systemer og biblioteker for sådanne sprog kan dog stadig være modtagelige for bufferoverløb på grund af mulige interne fejl i implementeringen af disse valideringssystemer. Adskillige software- og firmwareløsninger er tilgængelige på Windows , der forhindrer kode i at køre uden for en overløbsbuffer, hvis et sådant overløb opstår. Disse løsninger omfatter DEP i Windows XP SP2 , [9] OSsurance og Anti-Execute .
I Harvard-arkitekturen holdes den eksekverbare kode adskilt fra dataene, hvilket gør sådanne angreb næsten umulige. [ti]
Overvej et eksempel på et sårbart C -program :
#include <string.h> int main ( int argc , char * argv []) { charbuf [ 100 ] ; strcpy ( buf , argv [ 1 ]); returnere 0 ; }Den bruger den usikre strcpy -funktion , som giver dig mulighed for at skrive flere data, end der er plads til i det array, der er allokeret til dem. Hvis du kører dette program på et Windows -system med et argument, der er længere end 100 bytes, vil programmet højst sandsynligt gå ned, og brugeren vil modtage en fejlmeddelelse.
Følgende program er ikke påvirket af denne sårbarhed:
#include <string.h> int main ( int argc , char * argv []) { charbuf [ 100 ] ; strncpy ( buf , argv [ 1 ], sizeof ( buf )); returnere 0 ; }Her er strcpy blevet erstattet med strncpy , hvor det maksimale antal tegn, der skal kopieres, er begrænset af størrelsen på bufferen. [elleve]
Diagrammerne nedenfor viser, hvordan et sårbart program kan beskadige stakstrukturen .
Illustration af at skrive forskellige data til en buffer, der er allokeret på stakkenA. - Før du kopierer data.
B. - Strengen "hej" er blevet skrevet til bufferen.
C. - Bufferen er løbet over, hvilket medfører, at returadressen bliver overskrevet.
I x86 -arkitekturen vokser stakken fra større adresser til mindre, det vil sige, at nye data placeres før dem, der allerede er på stakken.
Ved at skrive data til bufferen kan du skrive ud over dens grænser og ændre dataene der, især ændre returadressen .
Hvis programmet har særlige privilegier (såsom at køre som root ), kan en angriber ændre returadressen til en shellcode -adresse , hvilket giver ham mulighed for at udføre kommandoer på målsystemet med forhøjede rettigheder . [12]
Bufferoverløbsteknikker varierer efter arkitektur, operativsystem og hukommelsesområde. For eksempel er tilfældet med et bufferoverløb på heapen (brugt til dynamisk hukommelsesallokering) væsentligt anderledes end på opkaldsstakken .
Også kendt som Stack smashing . En teknisk kyndig bruger kan bruge et stackbufferoverløb til at manipulere programmet til deres fordel på følgende måder:
Hvis adressen på brugerdata er ukendt, men den er gemt i et register, kan trampolinmetoden bruges : returadressen kan overskrives med adressen på opkoden , som vil overføre kontrol til hukommelsesområdet med brugerdata. Hvis adressen er gemt i R-registret, vil spring til en kommando, der overfører kontrol til den adresse (f.eks. opkald R), få den brugerspecificerede kode til at blive udført. Adresser på passende opkoder eller hukommelsesbytes kan findes i DLL'en eller i selve den eksekverbare. Dog kan adresser normalt ikke indeholde null-tegn, og placeringen af disse opkoder varierer afhængigt af applikationen og operativsystemet. Metasploit-projektet vedligeholdt for eksempel en database med passende opkoder til Windows-systemer (som i øjeblikket ikke er tilgængelig). [femten]
Et bufferoverløb på stakken skal ikke forveksles med et stackoverløb .
Det er også værd at bemærke, at sådanne sårbarheder normalt findes ved hjælp af den uklare testteknik .
Et bufferoverløb i et heapdataområde kaldes et heapoverløb og udnyttes på en anden måde end et bufferoverløb i stakken. Heap-hukommelse tildeles dynamisk af en applikation under kørsel og indeholder normalt programdata. Udnyttelse sker ved at korrumpere disse data på særlige måder for at tvinge applikationen til at overskrive interne strukturer såsom pointere i linkede lister. En almindelig udnyttelsesteknik for heap-bufferoverløb er at overskrive dynamiske hukommelsesreferencer (såsom malloc - funktionsmetadata ) og bruge den resulterende modificerede pointer til at overskrive programfunktionsmarkøren.
En sårbarhed i Microsofts GDI+ -produkt i håndteringen af JPEG -billeder er et eksempel på den fare, et heap-bufferoverløb kan udgøre. [16]
Manipulering af bufferen før læsning eller eksekvering kan forhindre vellykket udnyttelse af sårbarheden. De kan reducere truslen om et vellykket angreb, men ikke helt eliminere det. Handlinger kan omfatte konvertering af en streng til store eller små bogstaver, fjernelse af specialtegn eller frafiltrering af alle undtagen alfanumeriske tegn. Der er dog tricks til at omgå disse foranstaltninger: alfanumeriske skalkoder, [17] polymorfe koder , [ 18 ] selvforandrende koder og bibliotekets returangreb . [19] De samme teknikker kan bruges til at skjule sig fra indtrængningsdetektionssystemer . I nogle tilfælde, herunder tilfælde af konvertering af tegn til Unicode , forveksles sårbarheden med at tillade et DoS-angreb , mens fjernudførelse af vilkårlig kode faktisk er mulig. [tyve]
Forskellige tricks bruges til at gøre bufferoverløb mindre sandsynlige.
Intrusion detection-systemer (IDS) kan detektere og forhindre forsøg på at fjernudnytte bufferoverløb. Da data, der er bestemt til et bufferoverløb, i de fleste tilfælde indeholder lange arrays af No Operation ( eller ) instruktioner , blokerer IDS simpelthen alle indkommende pakker , der indeholder et stort antal på hinanden følgende NOP'er. Denne metode er generelt ineffektiv, da sådanne arrays kan skrives ved hjælp af en række forskellige assemblersprogsinstruktioner . For nylig er crackere begyndt at bruge shell -koder med kryptering , selvmodificerende kode , polymorf kode og alfanumerisk kode , såvel som fallback-angreb til standardbiblioteket for at trænge ind i IDS. [21]NOPNOOP
Beskyttelse mod stakkorruption bruges til at opdage de mest almindelige bufferoverløbsfejl. Dette kontrollerer, at opkaldsstakken ikke er blevet ændret, før den vender tilbage fra funktionen. Hvis det er blevet ændret, slutter programmet med en segmenteringsfejl .
Der er to systemer, StackGuard og Stack-Smashing Protector (tidligere ProPolice), begge udvidelser af gcc - kompileren . Siden gcc -4.1-stage2 er SSP blevet integreret i den primære compilerdistribution . Gentoo Linux og OpenBSD inkluderer SSP med deres gcc-distributioner. [22]
Placering af returadressen på datastakken gør det lettere at implementere et bufferoverløb, der fører til vilkårlig kodeudførelse. Teoretisk set kunne der foretages ændringer i gcc for at tillade, at adressen placeres på en speciel returstak , der er fuldstændig adskilt fra datastakken, på samme måde som den er implementeret i Forth-sproget . Dette er dog ikke en komplet løsning på bufferoverløbsproblemet, da andre stakdata også skal beskyttes.
Beskyttelse af eksekverbar kodes plads kan afbøde virkningerne af bufferoverløb, hvilket gør de fleste ondsindede handlinger umulige. Dette opnås ved adresserumsrandomisering ( ASLR ) og/eller forbud mod samtidig hukommelsesadgang til skrivning og udførelse. Den ikke-eksekverbare stak forhindrer de fleste shell- kodeudnyttelser .
Der er to Linux-kerne- patches , der giver denne beskyttelse - PaX og exec-shield . Ingen af disse er endnu inkluderet i hovedkernedistributionen. OpenBSD siden version 3.3 har inkluderet et system kaldet W^X , der også giver runtime kontrol.
Bemærk, at denne beskyttelsesmetode ikke forhindrer stakkorruption. Det forhindrer dog ofte udnyttelsen af "nyttelasten" i at blive eksekveret. Programmet vil ikke være i stand til at indsætte shell-kode i skrivebeskyttet hukommelse, såsom eksisterende segmenter af eksekverbar kode. Det vil heller ikke være muligt at udføre instruktioner på ikke-eksekverbar hukommelse, såsom stakken eller heapen .
ASLR gør det svært for en angriber at bestemme adresserne på funktioner i et programs kode, som han kunne udføre et vellykket angreb med, og gør angreb som ret2libc meget vanskelige, selvom de stadig er mulige i et kontrolleret miljø, eller hvis angriberen er korrekt gætter den rigtige adresse.
Nogle processorer , såsom Sun 's Sparc , Transmeta 's Efficeon og de nyeste 64-bit processorer fra AMD og Intel, forhindrer eksekvering af kode placeret i områder af hukommelsen markeret med den specielle NX bit . AMD kalder sin løsning NX (fra engelsk No eXecute ), og Intel kalder sin XD (fra engelsk eXecute Disabled ). [23]
Der findes nu flere forskellige løsninger til beskyttelse af eksekverbar kode på Windows -systemer , både fra Microsoft og tredjeparter.
Microsoft tilbød sin løsning, kaldet DEP (fra engelsk. Data Execution Prevention - "data execution prevention"), inklusive den i servicepakker til Windows XP og Windows Server 2003 . DEP drager fordel af nyere Intel- og AMD - processorer , der er designet til at overvinde grænsen på 4 GB adresserbar hukommelse på 32-bit-processorer. Til disse formål er nogle servicestrukturer blevet øget. Disse strukturer indeholder nu den reserverede NX-bit. DEP bruger denne bit til at forhindre angreb, der involverer ændring af adressen på en undtagelsesbehandler (den såkaldte SEH-udnyttelse ). DEP giver kun beskyttelse mod SEH -udnyttelsen, den beskytter ikke hukommelsessider med eksekverbar kode. [9]
Derudover har Microsoft udviklet en stackbeskyttelsesmekanisme designet til Windows Server. Stakken markeres ved hjælp af de såkaldte "informanter" ( English canary ), hvis integritet derefter kontrolleres. Hvis "informeren" er blevet ændret, så er stakken ødelagt. [24]
Der er også tredjepartsløsninger, der forhindrer udførelse af kode placeret i hukommelsesområder beregnet til data eller implementering af ASLR-mekanismen.
Problemet med bufferoverløb er fælles for programmeringssprogene C og C++, fordi de ikke skjuler detaljerne i lavniveaurepræsentationen af buffere som containere for datatyper . For at undgå bufferoverskridelser skal der således opretholdes et højt niveau af kontrol over oprettelsen og ændringen af den kode, der styrer buffere. Brugen af abstrakte datatypebiblioteker , der udfører centraliseret automatisk bufferstyring og inkluderer overløbskontrol, er en teknisk tilgang til forebyggelse af bufferoverløb. [25]
De to hoveddatatyper, der tillader bufferoverløb på disse sprog, er strenge og arrays . Således undgår brugen af biblioteker til strenge og listedatastrukturer, der er udviklet til at forhindre og/eller opdage bufferoverløb, mange sårbarheder. Prisen på sådanne løsninger er et fald i ydeevnen på grund af unødvendige kontroller og andre handlinger udført af bibliotekskoden, da den er skrevet "til alle lejligheder", og i hvert enkelt tilfælde kan nogle af de handlinger, den udfører, være overflødige.
Bufferoverløbet blev forstået og delvist dokumenteret allerede i 1972 i Computer Security Technology Planning Study. [26] Den tidligste dokumenterede ondsindede brug af et bufferoverløb fandt sted i 1988. Den var baseret på en af flere udnyttelser, som Morris -ormen brugte til at udbrede sig selv over internettet. Programmet udnyttede en sårbarhed i Unix finger - tjenesten . [27] Senere, i 1995, genopdagede Thomas Lopatik uafhængigt bufferoverløbet og listede resultaterne på Bagtrak- listen . [28] Et år senere udgav Elias Levy en trin-for-trin introduktion til brug af bufferoverløb med stakken, Smashing the Stack for Fun and Profit, i Phrack magazine . [12]
Siden da har mindst to kendte netværksorme brugt bufferoverløb til at inficere et stort antal systemer. I 2001 udnyttede Code Red- ormen denne sårbarhed i Microsofts Internet Information Services (IIS) 5.0 - produkt [29] , og i 2003 inficerede SQL Slammer maskiner, der kører Microsoft SQL Server 2000 . [tredive]
I 2003 tillod udnyttelse af et bufferoverløb i licenserede Xbox -spil ulicenseret software til at køre på konsollen uden hardwaremodifikation ved hjælp af såkaldte modchips . [31] PS2 Independence Exploit brugte også et bufferoverløb for at opnå det samme resultat for PlayStation 2 . En lignende udnyttelse af Wii Twilight udnyttede denne sårbarhed i The Legend of Zelda: Twilight Princess .