Al voltant d'una vulnerabilitat a...

Al voltant d'una vulnerabilitat a...

Fa un any, 21 de març de 2019, a les programa de recompensa d'errors Mail.Ru un molt bo va arribar a HackerOne informe d'error d' maxarr. Quan s'introduïa un byte zero (ASCII 0) al paràmetre POST d'una de les sol·licituds de l'API de correu web que retornava una redirecció HTTP, eren visibles trossos de memòria no inicialitzada a les dades de redirecció, en què fragments dels paràmetres GET i les capçaleres d'altres peticions a la mateix servidor.

Aquesta és una vulnerabilitat crítica perquè... les sol·licituds també contenen galetes de sessió. Unes hores més tard, es va fer una correcció temporal que filtrava el byte zero (com va resultar després, això no era suficient, perquè encara hi havia la possibilitat d'injectar CRLF/ASCII 13, 10, que permet manipular les capçaleres i dades de la resposta HTTP, això és menys crític, però encara desagradable). Al mateix temps, el problema es va traslladar als analistes de seguretat i desenvolupadors per trobar i eliminar les causes de l'error.

El correu Mail.ru és una aplicació molt complexa; un gran nombre de components front-end/back-end diferents, tant de codi obert (moltes gràcies a tots els desenvolupadors de programari lliure) com desenvolupats internament, poden participar en la generació de la resposta. Hem aconseguit excloure tots els components excepte nginx i openresty i localitzar el problema abans de trucar ngx.req.set_uri() en un script d'OpenResty que no es va comportar com s'esperava (inserir un byte nul o un avanç de línia mitjançant paràmetres GET amb reescriptura a ngx_http_rewrite_module, que, segons la documentació, s'utilitza i, sembla que hauria de funcionar exactament de la mateixa manera, no funcionar). Es van eliminar les possibles conseqüències, es va afegir el filtrat de la manera més estricta possible i es va verificar el filtrat per eliminar tots els vectors possibles. Però el mecanisme que va provocar la filtració del contingut de la memòria continuava sent un misteri. Un mes després, l'informe d'error es va tancar com a resolt i l'anàlisi de les causes de l'error es va ajornar fins a temps millors.

OpenResty és un connector molt popular que us permet escriure scripts Lua dins de nginx i s'utilitza en diversos projectes de Mail.ru, de manera que el problema no es va considerar resolt. I després d'un temps, finalment hi van tornar per entendre les veritables raons, les possibles conseqüències i fer recomanacions als desenvolupadors. Ha participat en l'excavació del codi font Denis Denisov и Nikolai Ermishkin. Va resultar que:

  • A nginx, quan s'utilitza la reescriptura amb dades d'usuari, hi ha la possibilitat de recórrer el directori (i probablement SSRF) en algunes configuracions, però això és un fet conegut i hauria de ser detectat pels analitzadors de configuració estàtica a nginx. Nginx Amplify и Gixy de Yandex (sí, també ho fem servir, gràcies). Quan utilitzeu OpenResty, aquesta característica és fàcil de perdre, però això no va afectar la nostra configuració.

    exemple de configuració:

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

    resultar

    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 té un error que fa que la memòria es perdi si la línia de reescriptura conté un byte nul. Quan s'emet una redirecció, nginx assigna un nou buffer de memòria corresponent a la longitud completa de la línia, però hi copia la línia mitjançant una funció de línia en la qual el byte zero és un terminador de línia, de manera que la línia només es copia fins al zero. byte; la resta de la memòria intermèdia conté dades no inicialitzades. Es pot trobar una anàlisi detallada aquí.

    exemple de configuració (^@ zero byte)

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

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

  • Nginx protegeix els paràmetres GET de la injecció de caràcters de servei i permet utilitzar només els paràmetres GET en la reescriptura. Per tant, no és possible explotar la injecció mitjançant paràmetres controlats per l'usuari a nginx. Els paràmetres POST no estan protegits. L'OpenResty us permet treballar amb paràmetres GET i POST, de manera que quan feu servir paràmetres POST mitjançant OpenResty, és possible injectar caràcters especials.

    exemple de configuració:

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

Més reacció

El problema es va informar als desenvolupadors de nginx i OpenResty, els desenvolupadors no consideren el problema com un error de seguretat a nginx, perquè al mateix nginx no hi ha manera d'explotar l'error mitjançant la injecció de caràcters especials, solucioneu revelació de la memòria es va publicar el 16 de desembre. En els 4 mesos transcorreguts des de l'informe, no s'ha fet cap canvi a OpenResty, tot i que es va entendre que es necessitava una versió segura de la funció ngx.req.set_uri(). El 18 de març de 2020 vam publicar informació, el 21 de març es va publicar OpenResty versió 1.15.8.3, que afegeix la validació d'URI.

Portswigger va escriure bon article i va rebre comentaris d'OpenResty i Nginx (tot i que el comentari que només s'exposa un petit fragment de memòria és incorrecte i enganyós, això ve determinat per la longitud de la línia que segueix el byte nul i, en absència de restriccions explícites sobre el longitud, pot ser controlat per l'atacant).

Aleshores, quin va ser l'error i què es pot fer per evitar-ho?

Hi va haver un error a nginx? Sí, ho va ser, perquè filtrar el contingut de la memòria és un error en qualsevol cas.

Hi va haver un error a OpenResty? Sí, almenys no s'ha investigat i documentat el tema de la seguretat de la funcionalitat que ofereix OpenResty.

Hi va haver un error de configuració/ús amb OpenResty? Sí, perquè a falta d'una declaració explícita, es va fer una hipòtesi no verificada sobre la seguretat de la funcionalitat que s'utilitza.

Quin d'aquests errors és una vulnerabilitat de seguretat amb una recompensa de 10000 dòlars? Per a nosaltres, això generalment no és important. En qualsevol programari, especialment a la intersecció de diversos components, especialment els proporcionats per diferents projectes i desenvolupadors, ningú no pot garantir mai que totes les característiques del seu treball siguin conegudes i documentades i que no hi hagi errors. Per tant, qualsevol vulnerabilitat de seguretat es produeix exactament on afecta la seguretat.

En qualsevol cas, és una bona pràctica normalitzar o limitar/filtrar tant com sigui possible les dades d'entrada que entren a qualsevol mòdul/API extern, tret que hi hagi instruccions explícites i s'entengui clarament que això no és necessari.

Errada

Per experiència article anterior, per preservar la puresa de la llengua:

recompensa d'errors — Concurs de caça d'errors
informe d'error - Notificació d'error
redirigir - redirecció
codi obert - codi obert
errada - Treballar els errors

Font: www.habr.com

Afegeix comentari