O jedné zranitelnosti v…

O jedné zranitelnosti v…

Před rokem, 21. března 2019, v bug bounty program Mail.Ru velmi dobrý přišel do HackerOne hlášení chyby z maxarr. Při zavedení nulového bajtu (ASCII 0) do parametru POST jednoho z požadavků rozhraní API webové pošty, které vracely přesměrování HTTP, byly v datech přesměrování viditelné části neinicializované paměti, ve kterých byly fragmenty z parametrů GET a hlavičky jiných požadavků na stejný server.

Jedná se o kritickou zranitelnost, protože... požadavky také obsahují soubory cookie relace. O několik hodin později byla provedena dočasná oprava, která filtrovala nulový bajt (jak se později ukázalo, nestačilo to, protože stále existovala možnost injektování CRLF / ASCII 13, 10, což umožňuje manipulovat s hlavičkami a data odpovědi HTTP, je to méně kritické, ale stále nepříjemné). Zároveň byl problém přenesen na bezpečnostní analytiky a vývojáře, aby našli a odstranili příčiny chyby.

Mail.ru mail je velmi složitá aplikace, do generování odpovědi může být zapojeno velké množství různých front-end/back-end komponent, a to jak open source (velké díky všem vývojářům svobodného softwaru), tak interně vyvinutých. Podařilo se nám vyloučit všechny komponenty kromě nginx a openresty a lokalizovat problém před voláním ngx.req.set_uri() ve skriptu OpenResty, který se nechoval podle očekávání (vložení nulového bajtu nebo řádku přes parametry GET s přepsáním v modulu ngx_http_rewrite_module, který se podle dokumentace používá a zdá se, že by měl fungovat úplně stejně, nefunguje). Možné následky byly eliminovány, filtrace byla přidána co nejpřísněji a byla ověřena filtrace pro odstranění všech možných vektorů. Ale mechanismus, který vedl k úniku obsahu paměti, zůstal záhadou. O měsíc později bylo hlášení o chybě uzavřeno jako vyřešené a analýza příčin chyby byla odložena na lepší časy.

OpenResty je velmi populární plugin, který vám umožňuje psát Lua skripty uvnitř nginx a používá se v několika projektech Mail.ru, takže problém nebyl považován za vyřešený. A po nějaké době se k tomu konečně vrátili, aby pochopili skutečné důvody, možné důsledky a dali doporučení pro vývojáře. Podílel se na vykopávání zdrojového kódu Denis Denisov и Nikolaj Ermiškin. Ukázalo se že:

  • V nginx při použití přepisu s uživatelskými daty existuje v některých konfiguracích možnost procházení adresářů (a pravděpodobně SSRF), ale to je známá skutečnost a měla by být detekována statickými konfiguračními analyzátory v Nginx Amplify и gixy z Yandexu (ano, používáme to také, díky). Při používání OpenResty lze tuto funkci snadno přehlédnout, ale naši konfiguraci to neovlivnilo.

    příklad konfigurace:

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

    výsledek

    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 má chybu, která způsobuje únik paměti, pokud řádek přepisu obsahuje prázdný bajt. Když je zadáno přesměrování, nginx přidělí novou vyrovnávací paměť odpovídající celé délce řádku, ale zkopíruje tam řádek pomocí funkce řádku, ve které je nulový bajt zakončením řádku, takže řádek je zkopírován pouze do nuly. byte, zbytek vyrovnávací paměti obsahuje neinicializovaná data. Podrobnou analýzu lze nalézt zde.

    příklad konfigurace (^@ nula bajtů)

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

    výsledek
    curl localhost:8337/secret -vv
    ...
    curl localhost:8337/memleak -vv
    ...
    Location: http://localhost:8337/secret
    ...

  • Nginx chrání parametry GET před vkládáním servisních znaků a umožňuje při přepisování používat pouze parametry GET. Proto v nginx není možné využít vstřikování prostřednictvím uživatelsky řízených parametrů. Parametry POST nejsou chráněny. OpenResty umožňuje pracovat s parametry GET i POST, takže při použití parametrů POST prostřednictvím OpenResty je možné vkládat speciální znaky.

    příklad konfigurace:

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

    výsledek:

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

Další reakce

Problém byl nahlášen vývojářům nginx a OpenResty, vývojáři problém nepovažují za bezpečnostní chybu v nginx, protože v samotném nginx neexistuje způsob, jak chybu zneužít vložením speciálních znaků, oprava odhalení paměti vyšlo 16. prosince. Během 4 měsíců od této zprávy nebyly v OpenResty provedeny žádné změny, i když bylo srozuměno, že je potřeba bezpečná verze funkce ngx.req.set_uri(). 18. března 2020 jsme zveřejnili informace, 21. března vyšly OpenResty verze 1.15.8.3, který přidává ověření URI.

Portswigger napsal dobrý článek a převzal komentáře od OpenResty a Nginx (ačkoli komentář, že je vystaven pouze malý fragment paměti, je nesprávný a zavádějící, je to určeno délkou řádku následujícího po nulovém bajtu a při absenci explicitních omezení na délka, může být ovládána útočníkem).

V čem tedy byla chyba a co lze udělat, aby se tomu zabránilo?

Byla v nginx chyba? Ano, bylo, protože únik obsahu paměti je v každém případě chyba.

Vyskytla se chyba v OpenResty? Ano, alespoň otázka bezpečnosti funkčnosti nabízené OpenResty nebyla prošetřena a zdokumentována.

Došlo k chybě konfigurace/použití s ​​OpenResty? Ano, protože při absenci výslovného prohlášení byl učiněn neověřený předpoklad o bezpečnosti používané funkce.

Která z těchto chyb představuje bezpečnostní chybu s odměnou 10000 XNUMX $? Pro nás to obecně není důležité. V žádném softwaru, zejména v průsečíku několika komponent, zejména těch, které poskytují různé projekty a vývojáři, nikdo nikdy nemůže zaručit, že všechny vlastnosti jejich práce jsou známé a zdokumentované a že neexistují žádné chyby. Jakákoli zranitelnost zabezpečení se proto vyskytuje přesně tam, kde ovlivňuje zabezpečení.

V každém případě je dobrou praxí co nejvíce normalizovat nebo omezit/filtrovat vstupní data, která jdou do jakéhokoli externího modulu/API, pokud neexistují explicitní pokyny a jasné pochopení, že to není vyžadováno.

Errato

Ze zkušenosti předchozí článek, v zájmu zachování čistoty jazyka:

bug bounty — soutěž v lovu brouků
hlášení chyby - upozornění na chybu
přesměrovat - přesměrování
open source - open source
tisková chyba - pracovat na chybách

Zdroj: www.habr.com

Přidat komentář