
Një vit më parë, më 21 mars 2019, në në HackerOne erdhi një raport shumë i mirë nga . Gjatë implementimit të bajtit zero (ASCII 0) në parametrin POST të një nga API-kërkesave të web-mailit, që ktheu një HTTP-redirect, në të dhënat e redirektimit u dukën fragmente të memories të pa inicializuara, ku shpesh shfaqeshin fragmentet nga parametrat GET dhe kreurat e kërkesave të tjera ndaj të njëjtit server.
Kjo është një vulnerabilitet kritik, pasi kërkesat përfshijnë gjithashtu cookie-t e sesionit. Pas disa orësh, u bë një rregullim temporary, që filtronte bajtin zero (siç u zbulua më pas, kjo ishte e pamjaftueshme, pasi mbeti mundësia e injektimit CRLF /ASCII 13, 10, e cila lejon manipulimin e të dhënave dhe kreuarve të HTTP- përgjigjeve, kjo është më pak kritike, por ende e pakëndshme). Në të njëjtën kohë, problemi iu transferua analistëve të sigurisë dhe zhvilluesve për të gjetur dhe eliminuar shkaqet e shfaqjes së gabimit.
Mail.ru është një aplikacion shumë kompleks, në formimin e përgjigjes mund të marrë pjesë një numër të madh komponentësh të ndryshëm frontend/backend, si komponentë open-source (falë shumë zhvilluesve të softuerit të lirë), ashtu edhe ata të zhvilluar vetë. Arriti të përjashtohet të gjithë komponentët përveç nginx dhe openresty dhe lokalizoi problemin deri në thirrjen në skriptin OpenResty, i cili nuk u comportua siç pritej (nuk mund të futni bajtin zero ose vijën e re përmes parametrave GET me rewrite në ngx_http_rewrite_module, i cili, sipas dokumentacionit, përdoret dhe, duke u dukur, duhet të funksiononte njëlloj, nuk do të ndodhte). U eliminuan pasojat e mundshme, u shtua filtrimi më i rreptë dhe u kontrollua që filtrimi eliminon të gjitha vektoret e mundshëm. Por mekanizmi që çonte në rrjedhjen e përmbajtjes së memories mbeti një mister. Pas një muaji, raporti i gabimeve u mbyll si i zgjidhur, ndërsa analiza e shkaqeve të shfaqjes së gabimit u shty për më vonë.
OpenResty është një plugin shumë i njohur, që lejon të shkruhen skripta Lua brenda nginx, dhe ai përdoret në disa projekte të Mail.ru, prandaj problemi nuk konsiderohej i zgjidhur. Dhe pas një kohë, ata u kthyen përsëri në të për të kuptuar shkaqet e vërteta, pasojat e mundshme dhe për të përgatitur rekomandime për zhvilluesit. Në kërkimet e kodit burimor morën pjesë dhe . U zbulua se:
- Në nginx, kur përdoren rewrite me të dhëna të personalizuara, ekziston mundësia për kalimin e drejtpërdrejtë të drejtorive (dhe ndoshta SSRF) në disa konfiguracione, por kjo është një fakt i njohur, dhe duhet të zbulohet nga analizat statike të konfiguracioneve në dhe nga Yandex (po, ne e përdorim edhe atë, faleminderit). Kur përdoret OpenResty, mundësia lehtë mund të shpërfillët, por konfigurimi ynë nuk e prekte këtë.
shembuj konfigurimi:
location ~ /rewrite { rewrite ^.*$ $arg_x; } location / { root html; index index.html index.htm; }rezultati
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 vargu rewrite përmban bajtin zero. Kur jep një redirect, nginx alokuar një buffer të ri memorie, që i përgjigjet gjatësi të plotë të vargut, por kopjon aty vargun përmes një funksioni të vargut, në të cilin bajti zero është terminator i vargut, prandaj vargu kopjohet vetëm deri në bajtin zero, pjesa tjetër e bufferit përmban të dhëna të pa inicializuara. Një analizë të detajuar mund të gjendet .
shembuj konfigurimi (^@ bajti zero)
location ~ /memleak { rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf"; } location / { root html; index index.html index.htm; }rezultati
curl localhost:8337/secret -vv
...
curl localhost:8337/memleak -vv
...
Location: http://localhost:8337/secret
...
- Nginx mbron parametrat GET nga injeksioni i simboleve speciale dhe lejon përdorimin në rewrite vetëm të parametrave GET. Prandaj, shfrytëzimi i injeksionit përmes parametrave të kontrolluar nga përdoruesit në nginx nuk është i mundur. Parametrat POST nuk janë të mbrojtur. OpenResty lejon të punoni me të dy parametrat GET dhe POST, prandaj, duke përdorur parametrat POST përmes OpenResty, ekziston mundësia për injeksionin e simboleve speciale.
shembuj konfigurimi:
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 mundore secret...}
...
Reagimi i mëtejshëm
U njoftuan zhvilluesit e nginx dhe OpenResty për problemin, zhvilluesit nuk e konsiderojnë këtë problem si një gabim sigurie në nginx, pasi në vetë nginx nuk ka mundësi për të shfrytëzuar gabimin përmes injeksionit të simboleve speciale, rregullimi u publikua më 16 dhjetor. Pas 4 muajve nga raportimi, në OpenResty gjithashtu nuk ishin bërë ndonjë ndryshim, megjithëse ishte e kuptueshme se nevojitet një variant i sigurt i funksionit ngx.req.set_uri(). Më 18 mars 2020, publikuan informacionin, më 21 mars OpenResty publikoi , i cili shton kontrollin e URI.
Portswigger artikull të mirë dhe kam marrë komentet nga OpenResty dhe Nginx (përndryshe, komenti që tregohet vetëm një fragment i vogël i memories është i pasaktë dhe i mashtron, kjo përcaktohet nga gjatësia e vargut që ndjek byte-in zero dhe, në mungesë të kufizimeve të qarta mbi gjatësi, mund të kontrollohet nga sulmuesi).
Pra, ku qëndronte gabimi dhe çfarë të bëjmë për ta parandaluar atë?
A kishte gabim në nginx? Po, kishte, sepse rrjedhja e përmbajtjes së memories është në çdo rast një gabim.
A kishin gabim në OpenResty? Po, të paktën çështja e sigurisë së funksionalitetit të ofruar nga OpenResty nuk ishte hetuar dhe dokumentuar.
A ishte bërë një gabim konfigurimi / përdorimi në OpenResty? Po, sepse në mungesë të një indikacioni të qartë, ishte bërë një supozim i pa verifikuar mbi sigurinë e funksionalitetit të përdorur.
Cila nga këto gabime përbën një vulnerabilitet sigurie me një shpërblim prej $10000? Për ne, në thelb, kjo nuk ka rëndësi. Në çdo software, veçanërisht në ndërveprimin e disa komponenteve, sidomos të ofruara nga projekte dhe zhvillues të ndryshëm, askush nuk mund të garantojë se të gjitha karakteristikat e operimit të tyre janë të njohura dhe të dokumentuara dhe se nuk ka gabime. Prandaj, çdo vulnerabilitet sigurie shfaqet atje ku ndikon në siguri.
Në çdo rast, një praktikë e mirë do të ishte normalizimi ose maksimumi kufizimi / filtrimi i të dhënave hyrëse që dërgohen në çdo modul / API të jashtëm, nëse nuk ka indikacione të qarta dhe një kuptim të qartë se kjo nuk është e nevojshme.
Errata
Nga përvoja , për të ruajtur pastërtinë e gjuhës:
bug bounty â garĂ« e gjetjes sĂ« gabimeve
raporti i defekteve â njoftimi pĂ«r njĂ« gabim
redirect â ridrejtim
open source â me kod burimi tĂ« hapur
errata â puna mbi gabimet
Burimi: habr.com
