Hvordan en bufferstrømning kan føre til ekstern kjøring av kode på 64-bits?

Jeg har følgende oppsummerte pseudokode i C89 fra et ssh-serverbibliotek som bare gir tilgang til ting som git-shell (/bin/bash er erstattet med programmet som skal kjøres, så det er ikke mulig å gjøre noe annet) :

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 hvordan kommandoen utføres senere (strengen command er uendret etter 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 gjøre memcpy(command,string.st.data,0) siden det tredje medlemmet av memcpy minimumsstørrelse på 1, og i min sammenheng bruker size_t et 64-biters heltall, jeg kan ikke utføre et bufferoverløp, siden det er len.

Alt jeg kan gjøre er å sette len til en verdi større enn den som er tildelt string.st.data. Dette er en bufferunderstrømning som gjør at jeg kan lese ikke-allokert minne.
Jeg kan lese serverminnet, men jeg kan ikke se hvilke sensitive data en offentlig ssh-server kan ha (i mitt tilfelle listen over brukere som kan utføre ssh er offentlig) .

Så gjør en bufferunderstrømning på memcpy tillat ekstern kodeutførelse?

Kommentarer

  • Hvis koden virkelig gjør command[len] = 0 så er det et bufferoverløp, siden maksindeksen for en buffer med lengde len er len-1. Alternativt, hvis den faktiske koden gjør en malloc(len+1) i stedet for en malloc(len), kan du lage et massivt bufferoverløp ved å sette len verdi til 0xFFFFFFFF.
  • @ThomasPornin: Nei dette er en feil fra min side, faktisk krever det flere funksjoner å gjøre dette. Anta at det gjenværende er sant.
  • @ThomasPornin: Jeg snakker om 64 bits, siden len er size_t, bruker den et 64 bits heltall. Så det er ingen måte for heltalloverløp.
  • @ThomasPornin De tildeler len+1 slik at innstillingen til 0 skal være gyldig.
  • @ RoraΖ: Han snakket om å sette string.st.len til −1.

Svar

Generelt, nei, en bufferunderstrømning kan ikke brukes til ekstern kjøring av kode. Siden angriperstyrte data aldri forlater plassen som er tildelt det, har den aldri muligheten til å overta programmets kjøringsflyt.

En bufferstrømning har potensial for andre typer angrep, for eksempel informasjon (hvis programmet regner med at bufferens originale innhold blir utslettet av de nye dataene).

Kommentarer

  • Eller som jeg så nylig i git, bli senere omgjort til et bufferoverløp.

Svar

Da jeg opprinnelig skrev dette svaret , det ser ut til at jeg gløste over noen misforståelser du har. Disse misforståelsene vil sannsynligvis forhindre deg i å forstå svaret mitt. For å være tydelig vil jeg gjøre denne teksten stor for å vektlegge, ikke for å være respektløs:

Mange av begrepene du bruker, betyr ikke det du ser ut til å tro at de betyr.

For eksempel:

  • «det tredje medlemmet av memcpy» er ikke-eksisterende fordi memcpy er en funksjon, ikke en struct eller union.
  • «Jeg kan ikke utføre et bufferoverløp, siden det er len» og jeg kan ikke gå tom for bensin, siden det er bensin. Ber jeg om spørsmål? Det virker som en passende analogi for meg, spesielt siden koden din kunne påberope et bufferoverløp teoretisk sett.
  • «Alt jeg kan gjøre er å sette len til en verdi større enn den som er tildelt string.st.data. Dette er en bufferunderstrømning … « Nei, det er ikke definisjonen av en bufferstrømning. En bufferstrømning oppstår når du får tilgang til en matrise utenfor grensene ved hjelp av en negativ indeks, eller en indeks som kan forårsake peker aritmetisk innpakning å skje. Det siste kan være mulig for noen konfigurasjoner (selv på «64-biters systemer», uansett hva det betyr), men jeg tviler på at det er dette du mente da du skrev disse ordene, fordi du så fulgte dem opp med:
  • «… slik at jeg kan lese ikke-allokert minne.» Jeg tror kanskje du mente «uinitialisert minne». For å være tydelig, tror jeg du mente å si at du «har tildelt et overskudd og lot det overskytende være uinitialisert , og kanskje du vil gjøre noe med det (se calloc eller memset).

La oss vurdere char *fubar = NULL; et øyeblikk … denne typen pekere har generelt null verdi.Dereferanse regnes som en nullpekereferanse , men hvis vi skriver noe sånt som 0["hello"] får vi det samme som "hello"[0] (altså "h"). Dermed kan en nullpekerdereferanse brukes i angrep når angriperen kontrollerer uttrykket mellom de firkantede seler (som de gjør i din situasjon).

Kommer tilbake til fubar ting; la oss si at vi memset(&fubar, UCHAR_MAX, sizeof fubar);, nå er fubar alle 1-bits, noe som betyr at det kan være en adresse det er den største adressen vårt system (teoretisk) kan ta imot. Hva om vi får tilgang til fubar[1]? Hvordan får du tilgang til elementet etter den største adressen? Gjør adresse og deretter vikle seg rundt? Teknisk sett er alt dette udefinert oppførsel, men hvis jeg skulle nevne det på vanlig arkitektur, ville det være:

  1. Aritmetisk overløp av en peker som fører til …
  2. Null pekereferanse, og / eller potensielt en bufferunderstrømning .

tillater en bufferunderstrømning på memcpy ekstern kjøring av kode?

En buffer understrøm kan tillate en angriper å overskrive funksjonspekere som er plassert i områdene av minnet før den aktuelle matrisen. Hvis disse funksjonspekerne er laget for å peke på skallkode, kan den utføres når de senere påkalles.

I dette noe uklare kodestykket ser det ut som en risiko for bufferunderstrømning når int har en bredere domene enn uint32_t, da ntohl(string.st.len)+1 ville føre til at uint32_t -verdien konverteres til en int type. Tenk for eksempel på at INT_MIN er -4294967296 (som er en mindre enn 0 - UINT32_MAX) og INT_MAX er 4294967295 … dette ville egentlig være en 33-bit int med polstring til pad ut til bredden på en byte; uvanlig, men mulig. I denne omstendigheten er ikke uttrykket ntohl(string.st.len)+1 uint32_t i typen; den «s int i typen, og i stedet for å pakke tilbake til 0 når usignert heltalloverløp oppstår, brytes den sannsynligvis til -4294967296 når signert heltalloverløp oppstår.

Hvis du «ser etter en garanti mot bufferunderstrømning , bruk U heltals bokstavssuffiks (dvs. ntohl(string.st.len)+1U). Så i den situasjonen vil du ende opp med at uttrykket er enten en uint32_t eller en unsigned int (avhengig av hvilken type som har størst domene).

Hvis du mener at ntohl(string.st.len) kan returnere en mindre enn maksimumsverdien for den usignerte typen (uansett hva den er), så len=ntohl(string.st.len)+1 vil føre til maksimal verdi, malloc(len+1) vil føre til usignert innpakning slik at du ender med å påkalle malloc(0) og deretter command[len]=0 vil skrive vel og virkelig utover slutten av matrisen. Så har du selvfølgelig «ll også et problem med memcpy(command,string.st.data,len); (dette er et bufferoverløp).

Bufferstrømning og overløp er ikke den eneste risikoen. Hvis du ikke «t sjekk returverdien av malloc , og malloc returnerer NULL, så kan en nullpekereferanse brukes til å forårsake vilkårlig kodeutførelse. Dette innebærer at du bør ha en metode for å kommunisere malloc feil tilbake til den som ringer. Det innebærer også at du kan bruke den samme metoden for å kontrollere og kommunisere innpakningsproblemet tilbake til den som ringer.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *