
For et år siden, den 21. marts 2019, kom der til HackerOne, som indeholdt en meget god fra . Ved indsættelse af et nul-byte (ASCII 0) i POST-parameteren for én af API-anmodningerne fra webmailen, som returnerede en HTTP-omdirigering, kunne man se fragmenter af uinitialiseret hukommelse i omdirigeringsdataene, hvor der oftest afslørede fragmenter fra GET-parametre og headers fra andre anmodninger til den samme server.
Dette er en kritisk sårbarhed, da anmodningerne også indeholder sessionscookies. Et par timer senere blev der lavet en midlertidig løsning, der filtrerede nul-byte (som det senere viste sig, ikke var tilstrækkeligt, da der stadig var mulighed for at indsprøjte CRLF /ASCII 13, 10, hvilket tillader manipulation af headers og data i HTTP-svaret, det er mindre kritisk, men stadig ubehageligt). Samtidig blev problemet overdraget til sikkerhedsanalyseholdet og udviklerne til at finde og udbedre årsagerne til fejlrapporten.
Mail.ru er en meget kompleks applikation, hvor mange forskellige frontend/backend-komponenter kan være involveret i dannelsen af svaret, både open source (en stor tak til alle udviklere af fri software) og egen udvikling. Det lykkedes at udelukke alle komponenter undtagen nginx og openresty og lokalisere problemet til kaldet i OpenResty-scriptet, som opførte sig anderledes end forventet (det var ikke muligt at indsætte nul-byte eller linjeskift via GET-parametre med rewrite i ngx_http_rewrite_module, som ifølge dokumentationen bruges og, tilsyneladende, burde fungere helt på samme måde). Mulige konsekvenser blev elimineret, der blev tilføjet strengest mulig filtrering, og det blev kontroleret, at filtreringen eliminerede alle mulige vektorer. Men mekanismen, der førte til lækage af indhold fra hukommelsen, forblev en gåde. En måned senere blev fejlrapporten lukket som løst, mens undersøgelsen af årsagerne til fejlrapporten blev udsat til bedre tider.
OpenResty er en meget populær plugin, der gør det muligt at skrive Lua-scripts inde i nginx, og den bruges i flere Mail.ru-projekter, så problemet blev ikke anset for løst. Og efter noget tid vendte man tilbage til det for at forstå de reelle årsager, mulige konsekvenser og lave anbefalinger til udviklerne. Der blev deltaget i udgravninger af kildekoden og . Det viste sig, at:
- I nginx er der mulighed for directory traversal (og sandsynligvis SSRF) ved brug af rewrite med brugerdata i nogle konfigurationer, men det er et kendt faktum, og det bør opdages af statiske konfigurationsanalysatorer i og fra Yandex (ja, vi bruger det også, tak). Når man bruger OpenResty, kan man let overse denne mulighed, men vores konfiguration blev ikke berørt.
eksempel på konfiguration:
location ~ /rewrite { rewrite ^.*$ $arg_x; } location / { root html; index index.html index.htm; }resultatet
curl localhost:8337/rewrite?x=/../../../../../../../../etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
... - I nginx er der en fejl, der fører til hukommelseslækage, hvis rewrite-strengen indeholder et nulbyte. Når nginx returnerer en omdirigering, tildeler den en ny hukommelsesbuffer, der svarer til den fulde længde af strengen, men kopierer den til bufferet gennem en str-funktion, hvor nulbyte er terminator for strengen, så strengen kun kopieres op til nulbyte, mens resten af bufferet indeholder ikke-initialiserede data. En detaljeret gennemgang kan findes .
eksempel på konfiguration (^@ nulbyte)
location ~ /memleak { rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf"; } location / { root html; index index.html index.htm; }resultatet
curl localhost:8337/secret -vv
...
curl localhost:8337/memleak -vv
...
Location: http://localhost:8337/secret
...
- Nginx beskytter GET-parametre mod injektion af specialtegn og giver kun mulighed for at bruge GET-parametre i rewrite. Derfor er det ikke muligt at udnytte injektion gennem brugerdefinerede parametre i nginx. POST-parametre er ikke beskyttede. OpenResty tillader både GET- og POST-parametre, så ved brug af POST-parametre gennem OpenResty åbnes der mulighed for injektion af specialtegn.
eksempel på konfiguration:
location ~ /memleak { rewrite_by_lua_block { ngx.req.read_body(); local args, err = ngx.req.get_post_args(); ngx.req.set_uri(args["url"], true); } } location / { root html; index index.html index.htm; }resultat:
curl localhost:8337 -d "url=hemmelig" -vv
...
curl localhost:8337 -d "url=asdfasdfasdfasdfasdfasdfasdfasdf" -vv
...
Placering: http://localhost:8337/{...måske indeholder hemmelighed...}
...
Yderligere reaktion
Problemet blev meldt til udviklerne af nginx og OpenResty. Udviklerne betragter ikke problemet som en sikkerhedsfejl i nginx, da der i selve nginx ikke er mulighed for at udnytte fejlen gennem indsprøjtning af specielle tegn, fix blev offentliggjort den 16. december. I 4 måneder siden rapporten til OpenResty er der heller ikke lavet nogen ændringer, selvom der var en forståelse af, at en sikker version af funktionen ngx.req.set_uri() var nødvendig. Den 18. marts 2020 offentliggjorde vi information, den 21. marts udgav OpenResty , som tilføjer URI-kontrol.
Portswigger en god artikel og tog kommentarer fra OpenResty og Nginx (dog er kommentaren om, at der kun afsløres et lille fragment af hukommelsen, urimelig og misvisende, da det bestemmes af længden af strengen efter nul-byte, og uden klare begrænsninger på længden kan det kontrolleres af angriberen).
Så hvad var fejlen, og hvad kan gøres for at forhindre den?
Var der en fejl i nginx? Ja, det var der, da lækage af hukommelsesindhold i enhver henseende er en fejl.
Var der fejl i OpenResty? Ja, i det mindste blev spørgsmålet om sikkerhed i den funktionalitet, der tilbys af OpenResty, ikke undersøgt eller dokumenteret.
Var der sikringsfejl / brug af OpenResty? Ja, fordi der i mangel af klare angivelser blev der gjort en ubegrundet antagelse om sikkerheden af den anvendte funktionalitet.
Hvilken af disse fejl er en sikkerhedsrisiko med en bounty på $10000? For os er det egentlig ikke vigtigt. I enhver software, især ved krydset mellem flere komponenter, især leveret af forskellige projekter og udviklere, kan ingen og aldrig garantere, at alle funktioner i deres arbejde er kendte og dokumenterede, og at der ikke er fejl. Derfor opstår enhver sikkerhedsrisiko netop der, hvor den påvirker sikkerheden.
I enhver situation vil det være en god praksis at normalisere eller maksimalt begrænse/filtere de inddata, der går til enhver ekstern modul/API, hvis der ikke er klare indikeringer og entydig forståelse af, at dette ikke er nødvendigt.
Errata
Fra erfaringen , for at opretholde sprogets renhed:
bug bounty — fejltestkonkurrence
bugrapport — fejlanmeldelse
redirect — omdirigering
open source — med åbent kildesyn
errata — arbejde med fejlretning
Kilde: habr.com
