Circa una vulnerabilità in...

Circa una vulnerabilità in...

Un anno fa, 21 marzo 2019, a programma di ricompensa dei bug Mail.Ru su HackerOne ne è arrivato uno molto buono riportare un errore от maxarr. Quando si introduceva un byte zero (ASCII 0) nel parametro POST di una delle richieste API webmail che restituiva un reindirizzamento HTTP, nei dati di reindirizzamento erano visibili pezzi di memoria non inizializzata, in cui frammenti dei parametri GET e intestazioni di altre richieste al stesso server.

Questa è una vulnerabilità critica perché... le richieste contengono anche cookie di sessione. Poche ore dopo, è stata apportata una correzione temporanea che filtrava il byte zero (come si è scoperto in seguito, questo non era sufficiente, perché c'era ancora la possibilità di iniettare CRLF / ASCII 13, 10, che consente di manipolare le intestazioni e dati della risposta HTTP, questo è meno critico, ma comunque sgradevole). Allo stesso tempo, il problema è stato trasferito agli analisti e agli sviluppatori della sicurezza per trovare ed eliminare le cause del bug.

La posta di Mail.ru è un'applicazione molto complessa; un gran numero di diversi componenti front-end/back-end, sia open source (grazie a tutti gli sviluppatori di software libero) che sviluppati internamente, possono essere coinvolti nella generazione della risposta. Siamo riusciti a escludere tutti i componenti tranne nginx e openresty e a localizzare il problema prima di chiamare ngx.req.set_uri() in uno script OpenResty che non si è comportato come previsto (inserendo un byte nullo o un avanzamento riga tramite parametri GET con riscrittura in ngx_http_rewrite_module, che, secondo la documentazione, viene utilizzato e, sembrerebbe, dovrebbe funzionare esattamente allo stesso modo, lo farà non funziona). Sono state eliminate le possibili conseguenze, è stato aggiunto il filtraggio nel modo più rigoroso possibile ed è stato verificato il filtraggio per eliminare tutti i possibili vettori. Ma il meccanismo che ha portato alla fuga dei contenuti della memoria è rimasto un mistero. Un mese dopo, la segnalazione del bug è stata chiusa come risolta e l'analisi delle cause del bug è stata rinviata a tempi migliori.

OpenResty è un plugin molto popolare che ti permette di scrivere script Lua all'interno di nginx, ed è utilizzato in diversi progetti Mail.ru, quindi il problema non è stato considerato risolto. E dopo un po 'ci sono finalmente tornati per comprendere le vere ragioni, le possibili conseguenze e fornire raccomandazioni agli sviluppatori. Partecipato allo scavo del codice sorgente Denis Denisov и Nikolay Ermishkin. È venuto fuori che:

  • In nginx, quando si utilizza la riscrittura con i dati utente, esiste la possibilità di attraversamento della directory (e probabilmente SSRF) in alcune configurazioni, ma questo è un fatto noto e dovrebbe essere rilevato dagli analizzatori di configurazione statici in Nginx Amplifica и gixy da Yandex (sì, usiamo anche quello, grazie). Quando si utilizza OpenResty, è facile non notare questa funzionalità, ma ciò non ha influito sulla nostra configurazione.

    esempio di configurazione:

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

    provocare

    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 ha un bug che causa perdite di memoria se la riga di riscrittura contiene un byte null. Quando viene emesso un reindirizzamento, nginx alloca un nuovo buffer di memoria corrispondente all'intera lunghezza della riga, ma copia lì la riga tramite una funzione di riga in cui il byte zero è un terminatore di riga, quindi la riga viene copiata solo fino allo zero byte; il resto del buffer contiene dati non inizializzati. È possibile trovare un'analisi dettagliata qui.

    esempio di configurazione (^@ zero byte)

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

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

  • Nginx protegge i parametri GET dall'inserimento di caratteri di servizio e consente di utilizzare solo i parametri GET nella riscrittura. Pertanto, non è possibile sfruttare l’iniezione tramite parametri controllati dall’utente in nginx. I parametri POST non sono protetti. OpenResty ti consente di lavorare sia con i parametri GET che POST, quindi quando usi i parametri POST tramite OpenResty, diventa possibile inserire caratteri speciali.

    esempio di configurazione:

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

    il risultato:

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

Ulteriore reazione

Il problema è stato segnalato agli sviluppatori di nginx e OpenResty, gli sviluppatori non considerano il problema come un bug di sicurezza in nginx, perché nello stesso nginx non c'è modo di sfruttare l'errore attraverso l'iniezione di caratteri speciali, fix divulgazione della memoria è stato pubblicato il 16 dicembre. Nei 4 mesi successivi alla segnalazione, non è stata apportata alcuna modifica a OpenResty, sebbene si fosse capito che era necessaria una versione sicura della funzione ngx.req.set_uri(). Il 18 marzo 2020 abbiamo pubblicato le informazioni, il 21 marzo è uscito OpenResty versione 1.15.8.3, che aggiunge la convalida dell'URI.

Portwigger ha scritto buon articolo e ha preso commenti da OpenResty e Nginx (anche se il commento secondo cui è esposto solo un piccolo frammento di memoria è errato e fuorviante, ciò è determinato dalla lunghezza della riga che segue il byte null e, in assenza di restrizioni esplicite sul lunghezza, può essere controllata dall'attaccante).

Allora qual è stato l’errore e cosa si può fare per prevenirlo?

C'era un bug in nginx? Sì, perché la perdita del contenuto della memoria è in ogni caso un errore.

C'era un bug in OpenResty? Sì, almeno la questione della sicurezza delle funzionalità offerte da OpenResty non è stata studiata e documentata.

Si è verificato un errore di configurazione/utilizzo con OpenResty? Sì, perché in assenza di una dichiarazione esplicita si è partiti da un presupposto non verificato sulla sicurezza della funzionalità utilizzata.

Quale di questi bug è una vulnerabilità di sicurezza con una taglia di $ 10000? Per noi questo generalmente non è importante. In qualsiasi software, soprattutto nell'intersezione di più componenti, soprattutto quelli forniti da progetti e sviluppatori diversi, nessuno può mai garantire che tutte le caratteristiche del proprio lavoro siano conosciute e documentate e che non siano presenti errori. Pertanto, qualsiasi vulnerabilità della sicurezza si verifica esattamente dove influisce sulla sicurezza.

In ogni caso, è buona pratica normalizzare o limitare/filtrare il più possibile i dati di input che vanno in qualsiasi modulo/API esterno, a meno che non ci siano istruzioni esplicite e una chiara comprensione che ciò non è richiesto.

errore di stampa

Per esperienza articolo precedente, per preservare la purezza della lingua:

ricompensa per gli insetti — Gara di caccia agli insetti
riportare un errore - notifica di errore
reindirizzare - reindirizzamento
fonte aperta - fonte aperta
errata - lavorare sugli errori

Fonte: habr.com

Aggiungi un commento