O jedné zranitelnosti v…

O jedné zranitelnosti v…

Před rokem, 21. března 2019, došlo k programu bug bounty Mail.Ru na HackerOne přišel velmi kvalitní bug report od maxarr. Při vkládání nulového bajtu (ASCII 0) do POST parametru jednoho z API požadavků webové pošty, který vracel HTTP přesměrování, se v datech přesměrování objevovaly útržky neinicializované paměti, v nichž se nejčastěji objevovaly fragmenty z GET parametrů a hlaviček jiných požadavků na stejný server.

Jedná se o kritickou zranitelnost, protože požadavky obsahují mimo jiné i session cookies. Po několika hodinách byl proveden dočasný fix, který filtroval nulový bajt (jak se později ukázalo, to bylo nedostatečné, protože zůstala možnost injekce CRLF / ASCII 13, 10, což umožňuje manipulaci s hlavičkami a daty HTTP odpovědi, což je méně kritické, ale stále nepříjemné). Současně byla problém předán analytikům bezpečnosti a vývojářům kvůli hledání a odstranění příčin vzniku chyby.

Mail.ru pošta je velmi složitá aplikace, na formaci odpovědi se může podílet velké množství různých frontend/backend komponent, jak open source (velké díky všem vývojářům svobodného softwaru), tak i vlastního vývoje. Podařilo se vyloučit všechny komponenty kromě nginx a openresty a lokalizovat problém na vyvolání ngx.req.set_uri() v OpenResty skriptu, který se choval jinak, než se očekávalo (vložit nulový bajt nebo nový řádek prostřednictvím GET parametrů s přepsáním v ngx_http_rewrite_module, který podle dokumentace je používán a měl by fungovat zcela analogicky, se nepodaří). Byla odstraněna možná zkreslení, přidána maximálně přísná filtrace a ověřeno, že filtrace eliminuje všechny možné vektory. Ale mechanismus, který vedl k úniku obsahu paměti, zůstával záhadou. Po měsíci byl bug report uzavřen jako vyřešený, a analýza příčin vzniku chyby byla odložena na lepší časy.

OpenResty je velmi populární plugin, který umožňuje psát Lua skripty uvnitř nginx a používá se v několika projektech Mail.ru, proto problém nebyl považován za vyřešený. A po nějaké době se k tomu stále vrátili, aby pochopili skutečné příčiny, možné důsledky a formulovali doporučení pro vývojáře. V hloubkových analýzách zdrojového kódu se účastnili Denis Denisov a Nikolaj Ermiškin. Ukázalo se, že:

  • V nginx při použití přepisu s uživatelskými daty existuje možnost průchodu adresářem (a pravděpodobně SSRF) v některých konfiguracích, ale to je známý fakt, který by měli zjistit statické analyzátory konfigurací v Nginx Amplify a Gixy od Yandexu (ano, také ho používáme, děkujeme). Při použití OpenResty je tuto možnost snadno přehlédnout, ale naše konfigurace 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
    ...

  • V nginx je chyba, která způsobuje únik obsahu paměti, pokud řetězec přepisu obsahuje nulový bajt. Při provádění přesměrování nginx alokuje nový paměťový buffer odpovídající plné délce řetězce, ale kopíruje sem řetězec pomocí funkce pro řetězce, kde je nulový bajt terminátorem řetězce, takže řetězec je zkopírován pouze do nulového bajtu, zbytek bufferu obsahuje neinitializovaná data. Podrobnou analýzu lze nalézt zde.

    příklad konfigurace (^@ nulový 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
    ...
    Umístění: http://localhost:8337/secret
    ...

  • Nginx chrání GET parametry před injekcí speciálních znaků a umožňuje použít v přepisu pouze GET parametry. Proto nelze v nginx provádět injekci prostřednictvím řízených uživatelských parametrů. POST parametry jsou přitom nechráněné. OpenResty umožňuje práci jak s GET, tak s POST parametry, takže při použití POST parametrů prostřednictvím OpenResty je možné injikovat 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=asdfasdfasdfasdfasdfasdfasdfasdf" -vv
    ...
    Location: http://localhost:8337/{...může obsahovat secret...}
    ...

Další reakce

O problému byli informováni vývojáři nginx a OpenResty, vývojáři nezařazují problém jako bezpečnostní chybu v nginx, protože v samotném nginx neexistuje možnost zneužití chyby přes injekci speciálních znaků, oprava úniku obsahu paměti byla zveřejněna 16. prosince. Za 4 měsíce od oznámení v OpenResty také nebyly provedeny žádné změny, i když bylo pochopení, že je potřebná bezpečná verze funkce ngx.req.set_uri(). 18. března 2020 jsme zveřejnili informace, 21. března OpenResty vydala verzi 1.15.8.3, která přidává kontrolu URI.

Portswigger napsal dobrý článek a vzal komentáře od OpenResty a Nginxu (pravda, že komentář o tom, že se odhaluje pouze malý fragment paměti, je nepřesný a zavádějící, určuje ho délka řetězce následujícího za nulovým bajtem a, v případě absence jasných omezení na délku, může být řízena útočníkem).

V čem byla chyba a co dělat, aby se předešlo jejímu vzniku?

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

Byly chyby v OpenResty? Ano, minimálně otázka bezpečnosti poskytované funkcionality OpenResty nebyla zkoumána a dokumentována.

Došlo k chybě v konfiguraci / používání OpenResty? Ano, protože při absenci jasného pokynu byla učiněna neověřená domněnka o bezpečnosti používané funkcionality.

Která z těchto chyb představuje bezpečnostní zranitelnost s odměnou $10000? Pro nás to ve skutečnosti není důležité. V jakémkoli software, zvlášť na pomezí několika komponent, které jsou poskytovány různými projekty nebo vývojáři, nikdo a nikdy nemůže zaručit, že jsou známy a dokumentovány všechny rysy jejich fungování a že neexistují chyby. Proto jakákoli bezpečnostní zranitelnost vzniká tam, kde ovlivňuje bezpečnost.

V každém případě bude dobrou praxí normalizovat nebo maximálně omezit/filterovat vstupní data, která odcházejí do jakéhokoli externího modulu/API, pokud nejsou jasné pokyny a jednoznačné porozumění, že to není vyžadováno.

Errata

Na základě zkušenosti předchozího článku, pro zachování čistoty jazyka:

bug bounty — soutěž v hledání chyb
bug report — oznámení o chybě
redirect — přesměrování
open source — s otevřeným kódem
errata — práce na chybách

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster