
Një vit më parë, më 21 mars 2019, në në HackerOne erdhi një raport shumë i mirë nga . Në integrimin e byte-zero (ASCII 0) në parametrin POST të një prej API kërkesave të web-mail, e cila kthente një HTTP-redirect, në të dhënat e redirect kishin pjesë të kujtesës të pa inicializuar, ku shpesh shfaqeshin fragmente nga parametrat GET dhe kokat e kërkesave të tjera për të njëjtin server.
Kjo është një dobësi kritike, pasi kërkesat përfshijnë gjithashtu cookie-t e sesionit. Pas disa orësh, u bë një rregullim provisional, i cili filtroi byte-zero (siç u zbulua më vonë, kjo ishte e pamjaftueshme, pasi mbetej mundësia e injeksionit CRLF / ASCII 13, 10, e cila lejonte manipulimin e kokave dhe të dhënave të përgjigjeve HTTP, kjo është më pak kritike, por akoma e pakëndshme). Njëkohësisht, problemi iu kalua analistëve të sigurisë dhe zhvilluesve për të kërkuar dhe zgjidhur shkakun e shfaqjes së defektit.
Mail.ru është një aplikacion shumë kompleks, në formimin e përgjigjes mund të përfshihen një numër i madh komponentësh të ndryshëm frontend/backend, si komponentë open-source (faleminderit shumë të gjithë zhvilluesve të softuerit të lirë), ashtu edhe zhvillime të brendshme. Mundëm të përjashtojmë të gjithë komponentët përveç nginx dhe openresty dhe të lokalizojmë problemin deri te thirrja në skriptin OpenResty, i cili vepronte ndryshe nga sa pritej (nuk është e mundur të vendosësh byte-zero ose ndërrim rreshti përmes parametrave GET me rewrite në ngx_http_rewrite_module, i cili, sipas dokumentacionit, përdoret dhe, duket se, duhet të funksionojë absolutisht në mënyrë të ngjashme). U eliminuan pasojat e mundshme, u shtua filtrimi më i ashpër dhe u verifikua që filtrimi eliminon të gjitha vektorët e mundshëm. Por mekanizmi që çonte në rrjedhjen e përmbajtjes së memorieve ka mbetur enigmë. Pas një muaji, raporti i defektit u mbyll si i zgjidhur, ndërsa analiza e shkakut të shfaqjes së defektit u shty për kohë më të mira.
OpenResty është një plugin shumë popullor që lejon shkruarjen e skripteve Lua brenda nginx, dhe ai përdoret në disa projekte të Mail.ru, kështu që problemi nuk u konsiderua i zgjidhur. Dhe pas një kohe, ata u kthyen përsëri për ta kuptuar shkakun e vërtetë, pasojat e mundshme dhe për të përgatitur rekomandime për zhvilluesit. Në gërmadhat e kodit burimor morën pjesë dhe U zbulua se:
- Në nginx, kur përdoret rewrite me të dhëna të personalizuara, ka mundësinë për directory traversal (dhe ndoshta SSRF) në disa konfigurime, por kjo është një fakt i njohur dhe duhet të zbulohet nga analizatorët statikë të konfigurimeve në dhe nga Yandex (po, ne gjithashtu e përdorim atë, faleminderit). Kur përdoret OpenResty, kjo mundësi mund të kalojë lehtë, por konfigurimi ynë nuk ishte prekur.
shembulli i konfigurimit:
location ~ /rewrite { rewrite ^.*$ $arg_x; } location / { root html; index index.html index.htm; }rezultatin
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
... - Në nginx ka një gabim që çon në rrjedhjen e përmbajtjes së memories nëse stringu rewrite përmban një byte zero. Kur nginx jep një redirect, ai alokon një tampon të ri memory që i përgjigjet gjatësi totale të stringut, por e kopjon atë përmes një funksioni string, në të cilin byte zero është terminatori i stringut, kështu që stringu kopjohet vetëm deri në byte zero, pjesa tjetër e tamponit përmban të dhëna të pa inicializuara. Mund të gjeni një analizë të detajuar .
shembulli i konfigurimit (^@ byte zero)
location ~ /memleak { rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf"; } location / { root html; index index.html index.htm; }rezultatin
curl localhost:8337/secret -vv
...
curl localhost:8337/memleak -vv
...
Location: http://localhost:8337/secret
...
- Nginx mbron parametrat GET nga injeksioni i simboleve të veçanta dhe jep mundësinë për të përdorur në rewrite vetëm parametrat GET. Prandaj, nuk është e mundur të shfrytëzohet injeksioni përmes parametrave të kontrolluar nga përdoruesi në nginx. Parametrat POST, nga ana tjetër, nuk janë të mbrojtur. OpenResty lejon punën me parametrat si GET ashtu edhe POST, kështu që kur përdoren parametrat POST përmes OpenResty, krijohet mundësia për injeksion të simboleve të veçanta.
shembulli i konfigurimit:
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; }rezultati:
curl localhost:8337 -d "url=secret" -vv
...
curl localhost:8337 -d "url=asdfasdfasdfasdfasdfasdfasdfasdf" -vv
...
Location: http://localhost:8337/{...mund mund të përmbajë secret...}
...
Reagimi i mëtejshëm
Problemi iu raportua zhvilluesve të nginx dhe OpenResty, dhe zhvilluesit nuk e konsiderojnë problemin si një gabim sigurie në nginx, pasi në vetë nginx nuk ka mundësi për shfrytëzimin e gabimit përmes injeksionit të simboleve speciale, rregullimi u publikua më 16 dhjetor. Për 4 muaj që nga raportimi në OpenResty nuk ishin bërë asnjë ndryshim, edhe pse kishte një kuptim se ishte e nevojshme një variant i sigurt i funksionit ngx.req.set_uri(). Në 18 mars 2020, ne publikuan informacionin, më 21 mars OpenResty lëshoi , i cili shton një kontroll të URI.
Portswigger Një artikull të mirë dhe mora komente nga OpenResty dhe Nginx (pavarësisht se komenti për faktin se zbulon vetëm një fragment të vogël të memories është i pasaktë dhe i shpif, kjo përcaktohet nga gjatësi e vargut që vjen pas bajtit të zeros dhe, në mungesë të kufizimeve të qarta për gjatësi, mund të kontrollohet nga sulmuesi).
Cila ishte gabimi dhe çfarë duhet bërë për ta parandaluar atë?
A ishte gabimi në nginx? Po, ishte, sepse rrjedhja e përmbajtjes së memories është një gabim në çdo rast.
A kishte gabim në OpenResty? Po, së paku nuk ishte hetuar dhe dokumentuar çështja e sigurisë së funksionalitetit që ofron OpenResty.
A ishte bërë një gabim konfigurimi / përdorimi të OpenResty? Po, sepse në mungesë të një tregimi të qartë, ishte bërë një supozim i pandërprerë mbi sigurinë e funksionalitetit të përdorur.
Cila nga këto gabime është një vulnerabilitet i sigurisë me bounty prej $10000? Për ne, në përgjithësi, nuk ka rëndësi. Në çdo program të softuerit, veçanërisht në kufirin e disa komponentëve, veçanërisht të ofruara nga projekte dhe zhvillues të ndryshëm, askush dhe kurrë nuk mund të garantojë se të gjitha veçoritë e funksionimit të tyre janë të njohura dhe të dokumentuara dhe se nuk ka gabime. Prandaj, çdo vulnerabilitet i sigurisë lind pikërisht aty ku ndikon në siguri.
Në çdo rast, një praktikë e mirë do të ishte të normalizosh ose të kufizosh / filtrosh sa më shumë që të jetë e mundur të dhënat hyrëse që shkojnë në çdo modul / API të jashtëm, nëse nuk ka tregime të qarta dhe një kuptim të qartë se kjo nuk është e nevojshme.
Errata
Nga eksperienca , për ruajtjen e pastërtisë së gjuhës:
bug bounty â njĂ« garĂ« pĂ«r gjetjen e gabimeve
raportin e gabimit â njoftim pĂ«r gabim
redirect â ridrejtim
me burim tĂ« hapur â me kod tĂ« hapur
errata â punĂ« mbi gabime
Burimi: habr.com
