Hvordan en bufferunderstrømning kan føre til ekstern udførelse af kode på 64-bits?

Jeg har følgende opsummerede pseudokode i C89 fra et ssh-serverbibliotek, der kun giver adgang til ting som git-shell (/bin/bash erstattes med det program, der skal køres, så det er ikke muligt at gøre noget andet) :

struct _raw_uncapped_ssh_string { // no limit on the size of the string; uint32_t len; char non_null_terminated_string[]; // by protocol design it have a minimum length of 1 }; typedef struct _raw_uncapped_ssh_string raw_ssh_string; union buffer { void * uncapped_zlib_decompressed_network_data; // yes, the size is uncapped, so it’s possible to put 4Gb of // data in it that would be copied later into memory. zlib // allow easily to turn some Mb in Gb of data, but it’s not // the point of the question. raw_ssh_string st; }; get_command (compressed_network_data) { size_t len; char * command; buffer string=uncompress_to_buffer(compressed_network_data); len=ntohl(string.st.len)+1; command=malloc(len+1); command[len]=0; // here’s the point, both the string length and content as // well it’s supplied size is controlled by the attacker. memcpy(command,string.st.data,len); return command; } 

Her er hvordan kommandoen udføres senere (strengen command er uændret efter get_command()) .

const char *args[]={"/bin/bash",command,NULL}; // /bin/bash isn’t the shell, it has been replaced by git‑shell. // redirect the program output to the network. dup2(stdin, 0); dup2(stdout,1); dup2(stdout,2); close(stdin); close(stdout); //if this return execution failed and print an error message return execv(args[0],(char * const *)args); // I don’t know which is the system, so I can’t know about the libc behaviour. 

Jeg kan ikke gøre memcpy(command,string.st.data,0) da det tredje medlem af memcpy har minimumsstørrelse på 1, og i min sammenhæng bruger size_t et 64-bit heltal, jeg kan ikke udføre et bufferoverløb, da der er len.

Alt hvad jeg kan gøre er at indstille len til en værdi, der er større end den, der er allokeret til string.st.data. Dette er en bufferunderstrømning, der giver mig mulighed for at læse ikke-allokeret hukommelse.
Jeg kan læse serverhukommelsen, men jeg kan ikke se, hvilke følsomme data en offentlig ssh-server kan indeholde (i mit tilfælde listen over brugere, der kan udføre ssh er offentlig) .

Så tillader en bufferunderstrømning på memcpy fjernbetjening kodeudførelse?

Kommentarer

  • Hvis koden virkelig gør command[len] = 0 så er det et bufferoverløb, da det maksimale indeks for en buffer med længden len er len-1. Alternativt, hvis den faktiske kode gør en malloc(len+1) i stedet for en malloc(len), kan du lave et massivt bufferoverløb ved at indstille len værdi til 0xFFFFFFFF.
  • @ThomasPornin: Nej, dette er en fejl fra min side, faktisk kalder det flere funktioner at gøre det her. Antag, at det resterende er sandt.
  • @ThomasPornin: Jeg taler om 64 bit, da len er size_t, bruger det et 64-tal heltal. Så der er ingen måde for overløb af heltal.
  • @ThomasPornin De tildeler len+1, så indstillingen til 0 skal være gyldig.
  • @ RoraΖ: Han talte om at indstille string.st.len til ‑1.

Svar

Generelt nej, en bufferunderstrømning kan ikke bruges til fjernkørsel af kode. Da angriberstyrede data aldrig forlader den plads, der er afsat til det, har de aldrig evnen til at overtage programmets eksekveringsstrøm.

En bufferunderstrømning har potentialet for andre typer angreb, f.eks. videregivelse af oplysninger (hvis programmet regner med, at bufferens originale indhold udslettes af de nye data).

Kommentarer

  • Eller som jeg så for nylig i git, blive senere til et bufferoverløb.

Svar

Da jeg oprindeligt skrev dette svar , det ser ud til, at jeg glødede over nogle misforståelser, som du holder. Disse misforståelser vil sandsynligvis forhindre dig i at forstå mit svar. For at være klar vil jeg gøre denne tekst stor for at lægge vægt, ikke for at være respektløs:

Mange af de udtryk, du bruger, betyder ikke, hvad du synes at tro, de betyder.

For eksempel:

  • “det tredje medlem af memcpy findes ikke, fordi memcpy er en funktion, ikke en struct eller union.
  • “Jeg kan ikke udføre et bufferoverløb, da der er len og jeg ikke kan løbe tør for benzin, da der er benzin. Tigger jeg spørgsmål? Det virker som en passende analogi for mig, især da din kode teoretisk set kunne påberåbe et bufferoverløb.
  • “Alt hvad jeg kan gøre er at indstille len til en værdi, der er større end den, der er tildelt string.st.data. Dette er en bufferunderstrømning … “ Nej, det er ikke definitionen på en bufferunderstrømning. En bufferunderstrømning opstår, når du får adgang til en matrix uden for grænserne ved hjælp af et negativt indeks eller et indeks, der kan forårsage pointer aritmetisk indpakning skal forekomme. Sidstnævnte kan være muligt for nogle konfigurationer (selv på “64-bit systemer”, uanset hvad det betyder), men jeg tvivler på, at det var det, du mente, da du skrev disse ord, fordi du derefter fulgte dem op med:
  • “… gør det muligt for mig at læse ikke-allokeret hukommelse.” Jeg tror måske du mente “uinitialiseret hukommelse”. For at være klar tror jeg du mente at sige at du “har tildelt et overskud og efterladt det overskydende uinitialiseret , og måske vil du gøre noget ved det (se calloc eller memset).

Lad os overveje char *fubar = NULL; et øjeblik … denne type markør har generelt et nul værdi.Dereferencering betragtes som en nul pointer-afvigelse , men hvis vi skriver noget som 0["hello"] får vi det samme som "hello"[0] (dvs. "h"). Således kan en nullpegerdereference bruges i angreb, når angriberen styrer udtrykket mellem de firkantede seler (som de gør i din situation).

Kommer tilbage til fubar ting; lad os sige, at vi memset(&fubar, UCHAR_MAX, sizeof fubar);, nu er fubar alle 1-bits, hvilket betyder, at det måske er en adresse det er den største adresse, som vores system (teoretisk set) kunne rumme. Hvad hvis vi får adgang til fubar[1]? Hvordan kan du få adgang til elementet efter den største adresse? Gør adresse og derefter vikle tilbage? Teknisk set er alt dette udefineret adfærd, men hvis jeg skulle nævne det på fælles arkitektur, ville det være:

  1. Aritmetisk overløb af en markør, der fører til …
  2. Null markørafvigelse og / eller potentielt en bufferunderstrømning .

tillader en bufferunderstrømning på memcpy eksekvering af ekstern kode?

En buffer underflow kan muliggøre, at en hacker overskriver funktionspegere, der er placeret i hukommelsesregionerne før det pågældende array. Hvis disse funktionspegere er peget på shellcode, kan udføres, når de “påberåbes senere.

I dette noget uklare stykke kode ser det ud til, at der er en risiko for bufferunderstrømning, når int har en bredere domæne end uint32_t, da ntohl(string.st.len)+1 ville medføre, at uint32_t -værdien konverteres til en int type. Overvej for eksempel, hvis INT_MIN er -4294967296 (hvilket er en mindre end 0 - UINT32_MAX) og INT_MAX er 4294967295 … dette ville i det væsentlige være en 33-bit int med polstring til pad ud til bredden af en byte; ualmindeligt, men muligt. Under denne omstændighed er udtrykket ntohl(string.st.len)+1 ikke uint32_t af typen; det “s int af typen, og i stedet for at pakke tilbage til 0, når usigneret heltal overløb forekommer, brydes det sandsynligvis til -4294967296 når underskrevet heltalsoverløb opstår.

Hvis du “søger en garanti mod bufferunderstrømning , skal du bruge U helt bogstaveligt suffiks (dvs. ntohl(string.st.len)+1U). I den situation ender du med, at udtrykket enten er uint32_t eller unsigned int (afhængigt af hvilken type der har den største domæne).

Hvis du mener, at ntohl(string.st.len) muligvis returnerer en mindre end den maksimale værdi for den usignerede type (uanset hvad den er), så len=ntohl(string.st.len)+1 vil resultere i den maksimale værdi, malloc(len+1) forårsager usigneret indpakning så du ender med at påkalde malloc(0) og derefter command[len]=0 skriver godt og sandt ud over slutningen af arrayet. Så selvfølgelig har du “ll også et problem med memcpy(command,string.st.data,len); (dette er et bufferoverløb).

Bufferunderstrømning og overløb er ikke den eneste risiko. Hvis du ikke “t skal du kontrollere returværdien af malloc og malloc returnerer NULL, så kan en nul pointerdifferens bruges til at forårsage vilkårlig kodeudførelse. Dette betyder, at du skal have en metode til at kommunikere = “e8e339f7c1”>

fejler tilbage til den, der ringer op. Det betyder også, at du kan bruge den samme metode til at kontrollere og kommunikere det indpakningsproblem tilbage til den, der ringer op.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *