Apie vieną pažeidžiamumą...

Apie vieną pažeidžiamumą...

Prieš metus, 21 m. kovo 2019 d., val klaidų programa Mail.Ru labai geras atėjo į HackerOne pranešimas apie klaidas nuo maxarr. Įvedant nulinį baitą (ASCII 0) į POST parametrą vienoje iš žiniatinklio pašto API užklausų, kurios grąžino HTTP peradresavimą, peradresavimo duomenyse buvo matomos neinicializuotos atminties dalys, kuriose fragmentai iš GET parametrų ir kitų užklausų antraštės tas pats serveris.

Tai yra kritinis pažeidžiamumas, nes... užklausose taip pat yra seanso slapukų. Po kelių valandų buvo atliktas laikinas pataisymas, kuris išfiltravo nulinį baitą (kaip vėliau paaiškėjo, to nepakako, nes vis dar buvo galimybė suleisti CRLF / ASCII 13, 10, leidžiančius manipuliuoti antraštėmis ir HTTP atsakymo duomenis, tai mažiau kritiška, bet vis tiek nemalonu). Tuo pačiu metu problema buvo perduota saugumo analitikams ir kūrėjams, siekiant surasti ir pašalinti klaidos priežastis.

Mail.ru paštas yra labai sudėtinga programa; generuojant atsakymą gali būti įtraukta daug skirtingų priekinių / galinių komponentų, tiek atvirojo kodo (labai ačiū visiems nemokamos programinės įrangos kūrėjams), tiek pačių sukurtų. Mums pavyko pašalinti visus komponentus, išskyrus nginx ir openresty, ir lokalizuoti problemą prieš skambinant ngx.req.set_uri() „OpenResty“ scenarijuje, kuris elgėsi ne taip, kaip tikėtasi (įterpus nulinį baitą arba eilutės tiekimą per GET parametrus su perrašymu į ngx_http_rewrite_module, kuris, remiantis dokumentacija, yra naudojamas ir, atrodo, turėtų veikti lygiai taip pat, bus neveikia). Galimos pasekmės buvo pašalintos, filtravimas buvo įtrauktas kiek įmanoma griežčiau, o filtravimas buvo patikrintas, kad būtų pašalinti visi galimi vektoriai. Tačiau mechanizmas, dėl kurio nutekėjo atminties turinys, liko paslaptis. Po mėnesio pranešimas apie klaidas buvo uždarytas kaip išspręstas, o klaidos priežasčių analizė atidėta geresniems laikams.

OpenResty yra labai populiarus įskiepis, leidžiantis rašyti Lua scenarijus nginx viduje, ir jis naudojamas keliuose Mail.ru projektuose, todėl problema nebuvo laikoma išspręsta. Ir po kurio laiko jie pagaliau prie jo grįžo, norėdami suprasti tikrąsias priežastis, galimas pasekmes ir pateikti rekomendacijas kūrėjams. Dalyvavo kasant šaltinio kodą Denisas Denisovas и Nikolajus Ermiškinas. Paaiškėjo, kad:

  • Naudojant nginx, naudojant perrašymą su vartotojo duomenimis, kai kuriose konfigūracijose yra galimybė pereiti katalogą (ir tikriausiai SSRF), tačiau tai yra žinomas faktas ir jį turėtų aptikti statiniai konfigūracijos analizatoriai Nginx sustiprinti и gixy iš „Yandex“ (taip, mes taip pat naudojame tai, ačiū). Naudojant OpenResty, šios funkcijos lengva nepastebėti, tačiau tai neturėjo įtakos mūsų konfigūracijai.

    konfigūracijos pavyzdys:

    location ~ /rewrite {
        rewrite ^.*$ $arg_x;
    }
    
    location / {
        root html;
        index index.html index.htm;
    }

    rezultatas

    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
    ...

  • „Nginx“ turi klaidą, dėl kurios nutekėja atmintis, jei perrašymo eilutėje yra nulinis baitas. Kai išduodamas peradresavimas, nginx paskiria naują atminties buferį, atitinkantį visą eilutės ilgį, bet nukopijuoja eilutę ten per eilutės funkciją, kurioje nulinis baitas yra eilutės pabaiga, todėl eilutė nukopijuojama tik iki nulio. baitas; likusioje buferio dalyje yra nepainicijuoti duomenys. Išsamią analizę galima rasti čia.

    konfigūracijos pavyzdys (^@ nulis baitas)

    
    location ~ /memleak {
        rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf";
    }
    
    location / {
        root html;
        index index.html index.htm;
    }

    rezultatas
    curl localhost:8337/secret -vv
    ...
    curl localhost:8337/memleak -vv
    ...
    Location: http://localhost:8337/secret
    ...

  • „Nginx“ apsaugo GET parametrus nuo paslaugų simbolių įvedimo ir leidžia perrašyti naudoti tik GET parametrus. Todėl nginx neįmanoma išnaudoti injekcijos naudojant vartotojo valdomus parametrus. POST parametrai nėra apsaugoti. OpenResty leidžia dirbti tiek su GET, tiek su POST parametrais, todėl naudojant POST parametrus per OpenResty, atsiranda galimybė įterpti specialiuosius simbolius.

    konfigūracijos pavyzdys:

    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;
    }
    

    rezultatas:

    curl localhost:8337 -d "url=secret" -vv
    ...
    curl localhost:8337 -d "url=%00asdfasdfasdfasdfasdfasdfasdfasdf" -vv
    ...
    Location: http://localhost:8337/{...может содержать secret...}
    ...

Tolesnė reakcija

Apie problemą buvo pranešta nginx ir OpenResty kūrėjams, kūrėjai nelaiko problemos nginx saugos klaida, nes pačiame nginx nėra būdo išnaudoti klaidą įvedant specialiuosius simbolius, pataisyti atminties atskleidimas buvo paskelbta gruodžio 16 d. Per 4 mėnesius nuo ataskaitos pateikimo nebuvo atlikta jokių OpenResty pakeitimų, nors buvo suprasta, kad reikia saugios funkcijos ngx.req.set_uri() versijos. 18 m. kovo 2020 d. paskelbėme informaciją, kovo 21 d. „OpenResty“. 1.15.8.3 versija, kuris prideda URI patvirtinimą.

Portswiggeris написал geras straipsnis ir paėmė komentarus iš „OpenResty“ ir „Nginx“ (nors komentaras, kad atskleidžiamas tik mažas atminties fragmentas, yra neteisingas ir klaidinantis, tai nulemia eilutės po nulinio baito ilgis ir, jei nėra aiškių apribojimų ilgio, gali būti kontroliuojamas užpuoliko).

Taigi, kokia buvo klaida ir ką daryti, kad jos išvengtume?

Ar buvo nginx klaida? Taip, buvo, nes nutekėjęs atminties turinys bet kuriuo atveju yra klaida.

Ar „OpenResty“ buvo klaida? Taip, bent jau OpenResty siūlomo funkcionalumo saugumo klausimas nebuvo ištirtas ir dokumentuotas.

Ar „OpenResty“ įvyko konfigūracijos / naudojimo klaida? Taip, nes nesant aiškaus pareiškimo, buvo daroma nepatikrinta prielaida apie naudojamos funkcijos saugumą.

Kuri iš šių klaidų yra saugos pažeidžiamumas su 10000 XNUMX USD premija? Mums tai apskritai nėra svarbu. Bet kurioje programinėje įrangoje, ypač kelių komponentų sankirtoje, ypač tų, kuriuos teikia skirtingi projektai ir kūrėjai, niekas niekada negali garantuoti, kad visos jų darbo ypatybės yra žinomos ir dokumentuotos ir kad nėra klaidų. Todėl bet koks saugumo pažeidžiamumas atsiranda būtent ten, kur jis turi įtakos saugumui.

Bet kuriuo atveju yra gera praktika kiek įmanoma normalizuoti arba apriboti / filtruoti įvesties duomenis, kurie patenka į bet kurį išorinį modulį / API, nebent yra aiškių nurodymų ir aiškus supratimas, kad tai nėra būtina.

Klaida

Pagal patirtį ankstesnis straipsnis, siekiant išsaugoti kalbos grynumą:

klaidų dovana — vabzdžių medžioklės varžybos
pranešimas apie klaidas - pranešimas apie klaidą
nukreipti - nukreipimas
atviro kodo - atviro kodo
klaidos - dirbti su klaidomis

Šaltinis: www.habr.com

Добавить комментарий