Om en sårbarhet i...

Om en sårbarhet i...

För ett år sedan, den 21 mars 2019, kl bug-bounty-program Mail.Ru en mycket bra kom till HackerOne buggrapport från maxarr. När en nollbyte (ASCII 0) introducerades i POST-parametern för en av webbmail-API-förfrågningarna som returnerade en HTTP-omdirigering, var delar av oinitierat minne synliga i omdirigeringsdata, i vilka fragment från GET-parametrar och rubriker för andra förfrågningar till samma server.

Detta är en kritisk sårbarhet eftersom... förfrågningar innehåller även sessionscookies. Några timmar senare gjordes en tillfällig fix som filtrerade nollbyten (som det visade sig senare var detta inte tillräckligt, eftersom det fortfarande fanns möjlighet att injicera CRLF / ASCII 13, 10, vilket gör att du kan manipulera rubrikerna och data från HTTP-svaret är detta mindre kritiskt, men fortfarande obehagligt). Samtidigt överfördes problemet till säkerhetsanalytiker och utvecklare för att hitta och eliminera orsakerna till felet.

Mail.ru mail är en mycket komplex applikation; ett stort antal olika front-end/back-end-komponenter, både öppen källkod (mycket tack till alla fri mjukvaruutvecklare) och egenutvecklade, kan vara involverade i att generera svaret. Vi lyckades utesluta alla komponenter utom nginx och openresty och lokalisera problemet innan vi ringde ngx.req.set_uri() i ett OpenResty-skript som inte betedde sig som förväntat (att infoga en nollbyte eller radmatning via GET-parametrar med rewrite i ngx_http_rewrite_module, som enligt dokumentationen används och som det verkar ska fungera på exakt samma sätt kommer inte arbete). Eventuella konsekvenser eliminerades, filtrering lades till så strikt som möjligt och filtrering verifierades för att eliminera alla möjliga vektorer. Men mekanismen som ledde till läckage av minnesinnehåll förblev ett mysterium. En månad senare stängdes felrapporten som löst, och analysen av orsakerna till felet sköts upp till bättre tider.

OpenResty är ett mycket populärt plugin som låter dig skriva Lua-skript inuti nginx, och det används i flera Mail.ru-projekt, så problemet ansågs inte vara löst. Och efter en tid återvände de äntligen till det för att förstå de verkliga orsakerna, möjliga konsekvenser och ge rekommendationer för utvecklare. Deltog i utgrävningen av källkoden Denis Denisov и Nikolay Ermishkin. Det visade sig att:

  • I nginx, när du använder omskrivning med användardata, finns det möjlighet till katalogövergång (och förmodligen SSRF) i vissa konfigurationer, men detta är ett känt faktum och bör upptäckas av statiska konfigurationsanalysatorer i Nginx Amplify и gixy från Yandex (ja, vi använder det också, tack). När du använder OpenResty är den här funktionen lätt att missa, men detta påverkade inte vår konfiguration.

    konfigurationsexempel:

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

    resultat

    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 har en bugg som gör att minne läcker om omskrivningsraden innehåller en nollbyte. När en omdirigering utfärdas, allokerar nginx en ny minnesbuffert som motsvarar radens fulla längd, men kopierar raden dit genom en linjefunktion där nollbyten är en linjeavslutning, så raden kopieras endast upp till noll byte; resten av bufferten innehåller oinitierade data. En detaljerad analys kan hittas här.

    konfigurationsexempel (^@ noll byte)

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

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

  • Nginx skyddar GET-parametrar från injicering av tjänstecken och gör det möjligt att endast använda GET-parametrar vid omskrivning. Därför är det inte möjligt att utnyttja injektion genom användarkontrollerade parametrar i nginx. POST-parametrar är inte skyddade. OpenResty låter dig arbeta med både GET- och POST-parametrar, så när du använder POST-parametrar genom OpenResty blir det möjligt att injicera specialtecken.

    konfigurationsexempel:

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

    resultat:

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

Ytterligare reaktion

Problemet rapporterades till utvecklarna av nginx och OpenResty, utvecklarna betraktar inte problemet som ett säkerhetsfel i nginx, eftersom i nginx själv finns det inget sätt att utnyttja felet genom injicering av specialtecken, fixa minnesavslöjande publicerades den 16 december. Under de fyra månaderna sedan rapporten har inga ändringar gjorts i OpenResty, även om det fanns en förståelse för att en säker version av funktionen ngx.req.set_uri() behövdes. Den 4 mars 18 publicerade vi information, den 2020 mars släpptes OpenResty version 1.15.8.3, vilket lägger till URI-validering.

Portswigger jag skrev bra artikel och tog kommentarer från OpenResty och Nginx (även om kommentaren att endast ett litet fragment av minnet exponeras är felaktig och missvisande, detta bestäms av längden på raden efter nollbyten och, i avsaknad av explicita begränsningar för längd, kan kontrolleras av angriparen).

Så vad var felet och vad kan man göra för att förhindra det?

Fanns det en bugg i nginx? Ja, det var det, eftersom läckande minnesinnehåll är ett fel i alla fall.

Fanns det en bugg i OpenResty? Ja, åtminstone frågan om säkerheten för den funktionalitet som erbjuds av OpenResty har inte undersökts och dokumenterats.

Fanns det ett konfigurations-/användningsfel med OpenResty? Ja, för i avsaknad av ett uttryckligt uttalande gjordes ett overifierat antagande om säkerheten för den funktionalitet som används.

Vilken av dessa buggar är en säkerhetsrisk med en pris på 10000 XNUMX USD? För oss är detta i allmänhet inte viktigt. I vilken programvara som helst, särskilt i skärningspunkten mellan flera komponenter, särskilt de som tillhandahålls av olika projekt och utvecklare, kan ingen någonsin garantera att alla funktioner i deras arbete är kända och dokumenterade och att det inte finns några fel. Därför uppstår varje säkerhetssårbarhet exakt där den påverkar säkerheten.

I vilket fall som helst är det god praxis att normalisera eller begränsa/filtrera så mycket som möjligt indata som går in i någon extern modul/API, såvida det inte finns explicita instruktioner och en tydlig förståelse för att detta inte krävs.

tryckfel

Av erfarenhet föregående artikel, för att bevara språkets renhet:

buggpris — insektsjakttävling
buggrapport - felmeddelande
dirigera om - omdirigering
öppen källa - öppen källa
fel - arbeta på misstag

Källa: will.com

Lägg en kommentar