Attacchi correlati al proxy inverso

Rispondi
Avatar utente
openresource
Administrator
Administrator
Messaggi: 382
Iscritto il: mar gen 28, 2020 9:52 pm
Reactions score: 4
Località: varese
Contatta:
apr 2020 27 03:46

Attacchi correlati al proxy inverso

Messaggio da openresource

Negli ultimi anni, sono state pubblicate diverse ricerche sugli attacchi deliberatamente o direttamente correlati a proxy inversi. Durante l'implementazione di vari controlli del proxy inverso sullo scanner, ho iniziato ad analizzare le implementazioni dei proxy inversi.
Inizialmente, volevo analizzare in che modo sia i proxy inversi che i server Web analizzano le richieste, scoprire le incoerenze nel processo tra di loro e utilizzare questa conoscenza per qualche tipo di bypass. Purtroppo, ero bloccato con l'analisi di web server e application server a causa di troppe possibili variazioni. Ad esempio, il server Web Apache si comporta in modo diverso a seconda di come lo si collega a PHP. Inoltre, un'implementazione di un'applicazione web, framework o middleware utilizzato da un'applicazione web può influenzare anche il processo di analisi delle richieste. Alla fine mi sono reso conto che alcuni attacchi sono ancora poco conosciuti o completamente sconosciuti.
L'obiettivo di questa ricerca è quello di rappresentare il quadro più ampio di potenziali attacchi su un proxy inverso o i server back-end dietro di esso. Nella parte principale dell'articolo, vi mostrerò alcuni esempi di configurazioni vulnerabili e lo sfruttamento di attacchi su vari proxy inversi, ma il secondo obiettivo della ricerca è quello di condividere i dati grezzi sulle varie implementazioni di proxy inversi in modo da poter trovare i vostri modi / trucchi (a seconda di un server back-end in ogni situazione specifica).
Condizioni
In realtà, la ricerca non riguarda solo i proxy inversi, ma anche i servizi di bilanciamento del carico, i proxy della cache, i WAF e altri server intermedi tra un utente e un'applicazione Web che analizza e inoltra le richieste. Tuttavia non ho trovato un buon termine che descrive correttamente un tale server ed è ben noto nella comunità, quindi userò "proxy inverso" anche quando parlo di servizi di bilanciamento del carico o proxy della cache. Chiamerò un'applicazione web dietro un proxy inverso un server back-end. Tenere presente che un server back-end è il cosiddetto server di origine (questo avrà senso quando si inizia a parlare di memorizzazione nella cache).
Immagine
Che cos'è il proxy inverso?
Come funzionano i proxy
L'idea di base di un proxy inverso è abbastanza semplice. Si tratta di un server intermedio tra un utente e un server back-end. Lo scopo di esso può essere molto diverso: può instradare le richieste a seconda dell'URL a vari back-end o può essere semplicemente lì "per proteggere" contro alcuni attacchi o semplicemente per analizzare il traffico. Anche le implementazioni possono essere diverse, ma la sequenza principale dei passaggi è la stessa.
Un proxy inverso deve ricevere una richiesta, deve elaborarla, eseguire un'azione su di essa e inoltrare a un back-end.
L'elaborazione di una richiesta è costituita da diversi passaggi principali:
1-Analisi 
Quando un proxy inverso riceve una richiesta, deve analizzarla: per ottenere un verbo, un percorso, una versione HTTP, l'intestazione host e altre intestazioni e il corpo.

Codice: Seleziona tutto

GET /path HTTP/1.1

Codice: Seleziona tutto

Host: example.com

Codice: Seleziona tutto

Header: something

Tutto può sembrare abbastanza semplice, ma se ti immergi nei dettagli, vedrai che le implementazioni sono diverse.
Alcuni esempi:

  • Se un inverso supporta Absolute-URI, come verrà analizzato? Absolute-URI ha una priorità più alta rispetto all'intestazione Host?

Codice: Seleziona tutto

GET http://other_host_header/path HTTP/1.1

Codice: Seleziona tutto

Host: example.com
  • L'URL è costituito da

    Codice: Seleziona tutto

    [//authority]path[?query][#fragment]

    e i browser non inviano 

    Codice: Seleziona tutto

    #fragment

    . Ma come deve un proxy inverso gestire 

    Codice: Seleziona tutto

    #fragment

    ?
    Nginx genera un frammento, Apache restituisce un errore 400 (a causa del simbolo di 

     altri gestirlo come un simbolo normale.

  • Come gestisce i simboli che devono essere codificati in URL?

Codice: Seleziona tutto

GET /index.php[0x01].jsp HTTP/1.1

 
2-Decodifica URL
A causa degli standard, i simboli con un significato speciale nell'URL devono essere codificati in URL (%-encoding), come il segno tra virgolette doppie (") o "maggiore di" (>). Ma in pratica, qualsiasi simbolo può essere codificato in URL e inviato in una parte di percorso. Molti server Web eseguono la decodifica URL durante l'elaborazione di una richiesta, pertanto le richieste successive verranno trattate nello stesso modo da esse.

Codice: Seleziona tutto

GET /index.php HTTP/1.1GET %2f%69%6e%64%65%78%2e%70%68%70 HTTP/1.1

 
3-Normalizzazione del percorso
Molti server Web supportano la normalizzazione del percorso. I casi principali sono ben noti:

Codice: Seleziona tutto

/long/../path/here -> /path/here

Codice: Seleziona tutto

/long/./path/here -> /long/path/here

 
Ma che dire di /..? Per Apache, è un equivalente di /../, ma per Nginx non significa niente.

Codice: Seleziona tutto

/long/path/here/.. -> /long/path/ - Apache

Codice: Seleziona tutto

/long/path/here/.. -> /long/path/here/.. - Nginx

Lo stesso con // ("directory vuota"). Nginx lo converte in una sola barra /, ma, se non è la prima barra, Apache la considera come una directory.
 

Codice: Seleziona tutto

//long//path//here -> /long/path/here - Nginx

Codice: Seleziona tutto

//long/path/here -> /long/path/here - Apache

Codice: Seleziona tutto

/long//path/here -> /long//path/here - Apache

 
Ecco alcune funzionalità aggiuntive (strane) supportate da alcuni server Web. Ad esempio: il supporto dei parametri di percorso – /..;/ è valido per Tomcat e Jetty o attraversamento con barra rovesciata (\..\).
 
b) Applicazione di regole ed esecuzione di azioni su una richiesta
Dopo l'elaborazione di una richiesta, il proxy inverso può eseguire alcune azioni sulla richiesta a causa della relativa configurazione. Importante notare che in molti casi, le regole di un proxy inverso sono basate sul percorso (posizione). Se il percorso è pathA, eseguire una cosa, se pathB – fare un'altra.
A seconda dell'implementazione o della configurazione, un proxy inverso applica regole basate su un percorso elaborato (analizzato, decodificato da URL, normalizzato) o su un percorso non elaborato (caso raro). È anche importante per noi notare se fa distinzione tra maiuscole e minuscole o meno. Ad esempio, i percorsi successivi saranno trattati allo stesso modo da un proxy inverso?:
/path1/ == /Path1/ == /p%61th1/ == /lala/../path1/
 
C) Inoltro a un back-end
Il proxy inverso ha elaborato una richiesta, trovato le regole appropriate ed eseguito le azioni necessarie. Ora deve inviarlo (inoltro) a un back-end. Invierà la richiesta elaborata o la richiesta iniziale? Ovviamente, se ha modificato la richiesta, quindi invia la versione modificata, ma in questo caso, deve eseguire tutti i passaggi necessari, ad esempio, per eseguire la codifica URL di simboli speciali. Ma cosa succede se il proxy inverso inoltra solo tutte le richieste a un solo back-end, forse inoltrare la richiesta iniziale è una buona idea?
Come potete vedere tutti questi passaggi sono abbastanza evidenti e non ci sono così tante varianti. Tuttavia, ci sono differenze nelle implementazioni, che noi, come aggressori, possiamo utilizzare per i nostri obiettivi.
Pertanto, l'idea di tutti gli attacchi descritti di seguito è che un proxy inverso elabora una richiesta, trova e applica regole e la inoltra a un back-end. Se troviamo un'incoerenza tra il modo in cui un proxy inverso elabora una richiesta e il modo in cui un server back-end la elabora, siamo quindi in grado di creare tale richiesta (percorso) che viene interpretato come un percorso dal proxy inverso e un percorso completamente diverso dal back-end. Così, saremo in grado di bypassare o di applicare con forza alcune regole del proxy inverso.
 
Ecco alcuni esempi
Nginx
Nginx è un server web ben noto, ma è anche molto popolare come proxy inverso. Nginx supporta Absolute-URI con uno schema arbitrario e una priorità più alta rispetto a un'intestazione Host. Nginx analizza, decodifica gli URL e normalizza un percorso di richiesta. Applica quindi le regole basate sulla posizione in base al percorso elaborato.
Ma sembra che Nginx abbia due comportamenti principali e ognuno di essi ha le sue caratteristiche interessanti:

  • Con barra finale

Codice: Seleziona tutto

location /

Codice: Seleziona tutto

{ proxy_pass http://backend_server/;

In questa configurazione, Nginx inoltra tutte le richieste al 'backend_server'. Invia la richiesta elaborata al back-end, il che significa che Nginx deve codificare in URL i simboli necessari. La cosa interessante per un attaccante è che Nginx non codifica tutti i simboli che i browser di solito fanno. Ad esempio, non codifica l'URL ' " < >.
Anche se c'è un'applicazione web (server back-end) che prende un parametro da un percorso e che è vulnerabile a XSS, un utente malintenzionato non può sfruttarlo, perché i browser moderni (tranne trucchi sporchi con IE) codificano l'URL di questi simboli. Ma se c'è Nginx come proxy inverso, un utente malintenzionato può forzare un utente a inviare un payload XSS con codifica URL nel percorso. Il Nginx lo decodifica e invia la versione decodificata al server back-end, il che rende possibile lo sfruttamento di XSS.

Codice: Seleziona tutto

Browser -> http://victim.com/path/%3C%22xss_here%22%3E/ -> Nginx -> http://backend_server/path/<"xss_here">/ -> WebApp
  • Senza barra finale

Codice: Seleziona tutto

location / {

Codice: Seleziona tutto

proxy_pass http://backend_server;

L'unica differenza tra questa configurazione e quella precedente è la mancanza della barra finale. Anche se apparentemente insignificante, costringe Nginx ad inoltrare una richiesta non elaborata al back-end. Quindi, se si invia /any_path/../to%61pp#/path2, dopo l'elaborazione della richiesta, Nginx tenterà di trovare una regola per '/to_app', ma invierà /any_path/../to%61pp#/path2 al back-end. Tale comportamento è utile per trovare incoerenze.
Haproxy
Haproxy è un servizio di bilanciamento del carico (con supporto HTTP). Non ha molto senso confrontarlo con Nginx, ma ti darà un'idea di un approccio diverso.
Haproxy esegue un'elaborazione minima di una richiesta. Quindi non c'è analisi "reale", decodifica URL, normalizzazione. Non supporta nemmeno Absolute-URI.
Pertanto, accetta tutto (con poche eccezioni) tra un verbo e una versione HTTP (GET !i<@>?lala=#anything HTTP/1.1) e, dopo aver applicato le regole, lo inoltra a un server back-end. Tuttavia supporta le regole basate su percorso e consente di modificare le richieste e le risposte.
Come vengono utilizzati i proxy
Mentre stavo lavorando su questa ricerca, analizzando varie configurazioni di proxy inversi, sono giunto alla conclusione che possiamo sia bypassare e applicare le regole di un proxy inverso. Pertanto, per comprendere il reale potenziale degli attacchi legati al proxy inverso, dobbiamo dare un'occhiata alle loro capacità.
Prima di tutto, un proxy inverso ha accesso sia a una richiesta che a una risposta (incluse quelle inviate/ricevute da un server back-end). In secondo luogo, abbiamo bisogno di una buona comprensione di tutte le funzionalità supportate da un proxy inverso e di come le persone le configurano.
In che modo un proxy inverso può gestire una richiesta? :

  1. Routing all'endpoint. Significa che un proxy inverso riceve una richiesta su un percorso (/app1/), ma inoltra la richiesta a uno completamente diverso (/any/path/app2/) su un back-end. Oppure inoltra la richiesta a un back-end specifico in base al valore di un'intestazione Host.

  2. Riscrittura percorso/query. Questo è simile al precedente, ma di solito comporta diversi meccanismi interni (regexp)

  3. Negazione dell'accesso. Quando un proxy inverso blocca una richiesta a un determinato percorso.

  4. Modifica delle intestazioni. In alcuni casi, un proxy inverso può aggiungere o modificare le intestazioni della richiesta. Potrebbe essere una caratteristica interessante per un attaccante, ma è difficile da sfruttare con un approccio scatola nera.

In che modo un proxy inverso può gestire una risposta?:

  1. Cache. Molti proxy inversi supportano la memorizzazione nella cache della risposta.

  2. Modifica delle intestazioni. A volte un proxy inverso aggiunge o modifica le intestazioni di risposta (anche relative alla sicurezza), perché non può essere eseguito su un server back-end

  3. Modifica del corpo. I proxy inversi a volte modificano anche il corpo. Edge Side Includes (ESI) è un esempio di quando questo può accadere.

Tutto questo è importante per vedere più potenziali attacchi, ma anche capire che in molti casi non abbiamo bisogno di bypassare, ma applicare regole. Il che porta a un nuovo tipo di attacchi contro i proxy inversi: regole proxy che si comportano in modo improprio.
Attacchi sul lato server
Limitazione del Bypass
Il caso più noto sugli attacchi correlati al proxy inverso.
Quando qualcuno limita l'accesso (3. Negando l'accesso), un utente malintenzionato deve ignorarlo.
Ecco un esempio.
Immaginiamo che ci siano Nginx come proxy inverso e Weblogic come server back-end. Nginx blocca l'accesso a un'interfaccia amministrativa di Weblogic (tutto ciò che inizia con /console/).
Configurazione:

Codice: Seleziona tutto

location /console/

Codice: Seleziona tutto

{deny all;

Codice: Seleziona tutto

return 403;

Codice: Seleziona tutto

 

Codice: Seleziona tutto

location / {

Codice: Seleziona tutto

proxy_pass http://weblogic;

Come si può vedere, 'proxy_pass' qui è senza barra finale, il che significa che una richiesta viene inoltrata non elaborata. Un'altra cosa importante per aggirare la restrizione è che Weblogic considera il simbolo '' come un simbolo abituale. Pertanto, un utente malintenzionato può accedere all'interfaccia amministrativa di Weblogic inviando una richiesta di questo tipo:

Codice: Seleziona tutto

GET /#/../console/ HTTP/1.1

Quando Nginx avvia l'elaborazione della richiesta, viene generato tutto #che segue, quindi ignora la regola /console/ Viene quindi inoltrato lo stesso percorso non elaborato (/#/../console/) al Weblogic, il Weblogic elabora il percorso e dopo la normalizzazione del percorso, ci rimane/console/.
Richiedere il calcolo errato
Si tratta di "1. Routing all'endpoint" e, in alcuni casi, "2. Riscrittura percorso/query".
Quando un proxy inverso inoltra le richieste solo a un endpoint, può avere l'illusione che un utente malintenzionato non possa raggiungere altri endpoint in un back-end o che non possa raggiungere un back-end completamente diverso.
Esempio 1.
Diamo un'occhiata a combinazioni simili: Nginx-Weblogic. In questo caso, Nginx proxy richieste solo a un determinato endpoint di Weblogic (http://weblogic/to_app). Pertanto, solo le richieste, che arrivano a un percorso /to_app su Nginx, vengono inoltrate allo stesso percorso su Weblogic. In questo caso, potrebbe sembrare interfaccia amministrativa di Weblogic (console) o altri percorsi non sono accessibili per un utente malintenzionato.

Codice: Seleziona tutto

location /to_app {

Codice: Seleziona tutto

proxy_pass http://weblogic;

Per reindirizzare erroneamente le richieste verso altri percorsi, abbiamo bisogno di conoscere di nuovo due cose. In primo luogo, lo stesso dell'esempio precedente – 'proxy_pass' è senza una barra finale.
In secondo luogo, Weblogic supporta i "parametri di percorso" (https://tools.ietf.org/html/rfc3986#section-3.3). Ad esempio, /path/to/app/here;param1=val1e param1 saranno accessibili in un'app Web tramite API.
Penso che molti siano consapevoli di questa caratteristica (soprattutto dopo la presentazione di Orange Tsai da BlackHat nel contesto di Tomcat. Tomcat permette di eseguire attraversamenti davvero "strani" come /..;/..;/. Ma Weblogic considera i parametri di percorso in modo diverso, in quanto tratta tutto dopo il primo ; come un parametro path. Significa che questa funzionalità è inutile per un utente malintenzionato?
No. Diamo un'occhiata a questa "magia" che permette di accedere a qualsiasi percorso su Weblogic in questa configurazione.

Codice: Seleziona tutto

GET /any_path_on_weblogic;/../to_app HTTP/1.1

Quando Nginx riceve tale richiesta, normalizza il percorso. Da /any_path_on_weblogic;/../to_app ottiene /to_app che viene applicato correttamente alla regola. Ma Nginx inoltra /any_path_on_weblogic;/../to_app e Weblogic, durante l'analisi, considera tutto ciò che segue ; come parametro path, pertanto Weblogic vede /any_path_on_weblogic. Se necessario, un utente malintenzionato può andare "più profondo" aumentando la quantità di /../after;.
Esempio 2.
Questo parla di un "bug" di Nginx. Ma questo "bug" è solo una conseguenza di come funziona Nginx (quindi non sarà risolto)
Un percorso della regola location /to_app indica che tutti i percorsi che iniziano con /to_app (prefisso) rientrano nella regola. Quindi, /to_app, /to_app/, /to_app_anything (inclusi i simboli speciali) rientrano. Inoltre, tutto ciò che segue questo prefisso(/to_app) verrà preso e quindi concatenato con valore in proxy_pass.
Esamina la configurazione successiva. Nginx, dopo l'elaborazione '/to_app_anything', inoltrerà la richiesta a http://server/any_path/_anything

Codice: Seleziona tutto

location /to_app {

Codice: Seleziona tutto

proxy_pass http://server/any_path/;

Se mettiamo insieme entrambe le caratteristiche, vedremo che possiamo andare a qualsiasi percorso di un livello superiore su quasi tutti i back-end. Abbiamo solo bisogno di inviare:

Codice: Seleziona tutto

GET /to_app../other_path HTTP/1.1

Nginx applica /to_app regola, ottiene tutto(../other_path) dopo il prefisso, lo concatena con un valore da 'proxy_pass', in modo da inoltrare http://server/any_path/../other_path a un back-end. Se il back-end normalizza il percorso, è possibile raggiungere un endpoint completamente diverso.
In realtà, questo trucco è simile a un trucco alias ben noto. Tuttavia, l'idea qui è quella di mostrare un esempio di possibile uso improprio delle funzionalità del proxy inverso.
Esempio 3.
Come accennato in precedenza, è un caso comune quando un proxy inverso instrada le richieste a back-end diversi a seconda dell'intestazione Host in una richiesta.
Diamo un'occhiata alla configurazione Haproxy che dice che tutte le richieste con example1.com nell'intestazione Host devono essere inoltrate a un example1_backend back-end – 192.168.78.1:9999.

Codice: Seleziona tutto

frontend http-in

Codice: Seleziona tutto

acl host_example1 hdr(host) -i example1.com

Codice: Seleziona tutto

use_backend example1_backend if host_example1

Codice: Seleziona tutto

backend example1_backend

Codice: Seleziona tutto

server server1 192.168.78.1:9999 maxconn 32

Tale configurazione significa che un utente malintenzionato non può accedere ad altri host virtuali di un server back-end? Può sembrare così, ma un attaccante può facilmente farlo. Perché, come accennato in precedenza, Haproxy non supporta uri assoluti, ma la maggior parte dei server web. Quando Haproxy riceve l'URI assoluto, inoltra questo URI assoluto non elaborato a un back-end. Pertanto, semplicemente inviando la richiesta successiva, è possibile accedere facilmente ad altri host virtuali del server back-end.

Codice: Seleziona tutto

GET http://unsafe-value/path/ HTTP/1.1

Codice: Seleziona tutto

Host: example1.com

È possibile forzare la connessione di un proxy inverso a un server back-end arbitrario? Direi che nella maggior parte dei casi (Nginx, Haproxy, Varnish), questo non può essere fatto, ma Apache (in alcune configurazioni / versioni) è vulnerabile ad esso. Come Apache "analizza" un valore host da ProxyPass, possiamo inviare qualcosa come GET @evil.com HTTP/1.1, in modo Apache vede un valore 'http://backend_server@evil.com' e invia la richiesta a 'evil.com' (SSRF). Qui potete vedere un esempio di tale vulnerabilità.
Attacchi lato client
Se diamo un'occhiata di nuovo alle funzionalità del proxy inverso, possiamo vedere che tutte le risposte hanno un potenziale per gli attacchi lato client. Non li rende inutili. Direi il contrario. Tuttavia, gli attacchi lato client presentano limitazioni aggiuntive per possibili incoerenze tra il proxy inverso e il server Web, poiché il browser elabora una richiesta prima di inviarla.
Elaborazione del browser
In un attacco lato client, un utente malintenzionato deve forzare il browser di una vittima per inviare una richiesta speciale, che influenzerà una risposta, a un server. Ma il browser segue le specifiche ed elabora il percorso prima di inviarlo: - Il browser analizza l'URL (ad esempio genera una parte di frammento), codifica l'URL di tutti i simboli necessari (con alcune eccezioni) e normalizza un percorso. Pertanto, per eseguire tali attacchi, possiamo utilizzare solo una richiesta "valida" che deve rientrare nell'incoerenza tra tre componenti (browser, proxy inverso, server back-end).
Naturalmente, ci sono differenze nelle implementazioni del browser, oltre ad alcune caratteristiche che ci permette ancora di trovare tali incoerenze:

  • Ad esempio, Chrome e IE non decodificano '%2f', quindi un percorso simile a quello /path/anything/..%2f../ non sarà percorso normalizzato.

  • Le versioni precedenti di Firefox non decodificavano url di simboli speciali prima della normalizzazione, ma ora si comporta in modo simile a Chrome.

  • Ci sono informazioni che Safari non decodifica un percorso DA URL, quindi possiamo forzarlo a inviare tale percorso /path/%2e%2e/another_path/.

  • Inoltre, IE, come al solito, ha qualche magia: non elabora un percorso quando viene reindirizzato con l'intestazione Location.

Utilizzo improprio della modifica dell'intestazione
Un'attività comune per il proxy inverso consiste nell'aggiungere, eliminare o modificare le intestazioni da una risposta di un back-end. In alcune situazioni, è molto più semplice della modifica del back-end stesso. A volte comporta la modifica di intestazioni importanti per la sicurezza. Quindi, come aggressori, potremmo voler forzare un proxy inverso per applicare tali regole a risposte errate (da posizioni di back-end errate) e quindi utilizzarlo per gli attacchi ad altri utenti.
Immaginiamo di avere Nginx e Tomcat come backend. Tomcat, per impostazione predefinita, imposta l'intestazione 'X-Frame-Options: deny', quindi un browser non può aprirlo in un iframe. Per qualche motivo, una parte dell'applicazione Web (/iframe_safe/) sul Tomcat deve essere accessibile tramite iframe, pertanto Nginx è configurato per eliminare l'intestazione 'X-Frame-Options' per questa parte. Tuttavia, non vi è alcun potenziale per gli attacchi clickjacking su iframe_safe. Di seguito è riportata la configurazione:

Codice: Seleziona tutto

location /iframe_safe/ {

Codice: Seleziona tutto

proxy_pass http://tomcat_server/iframe_safe/;

Codice: Seleziona tutto

proxy_hide_header "X-Frame-Options";

Codice: Seleziona tutto

location / {

Codice: Seleziona tutto

proxy_pass http://tomcat_server/;

Tuttavia, come aggressori, possiamo fare una richiesta che rientra nella iframe_safe ma sarà interpretata da Tomcat come una posizione completamente diversa. Eccolo:

Codice: Seleziona tutto

<iframe src="http://nginx_with_tomcat/iframe_safe/..;/any_other_path">

Un browser non normalizza tale percorso. Per Nginx rientra sotto la iframe_safe Poiché Tomcat supporta i parametri di percorso, dopo la normalizzazione del percorso, otterrà '/any_other_path'. Pertanto, in tale configurazione, qualsiasi percorso di Tomcat può essere iframed, in modo che un utente malintenzionato può eseguire attacchi clickjacking sugli utenti.
Naturalmente, con un approccio simile, altre intestazioni relative alla sicurezza (ad esempio CORS, CSP e così via) potrebbero essere utilizzate in modo improprio.
Memorizzazione nella cache
La memorizzazione nella cache è una delle più interessanti, con un buon potenziale per vari attacchi, ma è ancora una funzionalità poco conosciuta dei proxy inversi. Recentemente, gli attacchi relativi alla cache hanno ottenuto più attenzione in alcune ricerche impressionanti tra cui Web Cache Deception e Practical Web Cache Poisoning. Nella mia ricerca, mi sono concentrato troppo sulla memorizzazione nella cache: volevo analizzare varie implementazioni di cache. Di conseguenza, ho diverse idee su come migliorare sia l'inganno della cache che gli attacchi di avvelenamento da cache.
Come funziona
Ci sono diversi fattori sulla cache di un proxy inverso che ci aiutano a capire gli attacchi.
L'idea della memorizzazione nella cache è abbastanza semplice. In alcune situazioni, un proxy inverso archivia una risposta da un back-end nella cache e quindi restituisce la stessa risposta dalla cache senza accedere al back-end. Alcuni proxy inversi supportano la memorizzazione nella cache per impostazione predefinita, alcuni richiedono la configurazione. In genere, un proxy inverso utilizza come chiave della cache, una concatenazione del valore dell'intestazione Host con path/query non elaborato da una richiesta.
Per decidere se è OK memorizzare nella cache una risposta o no, la maggior parte dei proxy inversi controllare Cache-Control e Set-Cookie intestazioni da una risposta di un back-end. I proxy inversi non archiviano affatto le risposte con Set-Cookie, ma Cache-Control, in quanto descrive un criterio di memorizzazione nella cache e richiede un'analisi aggiuntiva. Il formato dell'intestazione del controllo Cache è piuttosto complesso, ma fondamentalmente ha diversi flag che consente la memorizzazione nella cache o meno e imposta per quanto tempo una risposta può essere memorizzata nella cache.
L'intestazione Cache-Control potrebbe essere simile alla seguente:Cache-Control header may look like these:

Codice: Seleziona tutto

Cache-Control: no-cache, no-store, must-revalidate

Codice: Seleziona tutto

Cache-Control: public, max-age=31536000

Il primo esempio vieta la memorizzazione nella cache da un proxy inverso, il secondo – lo consente. L'assenza di un'intestazione Cache-Control in genere significa che un proxy inverso è autorizzato a memorizzare una risposta.
Molti server Web, server applicazioni e framework impostano le intestazioni Cache-Control in modo automatico e corretto. Nella maggior parte dei casi, se un'app Web usa la sessione in uno script, imposterà le intestazioni Cache-Control che limita la memorizzazione nella cache, pertanto i programmatori di solito non devono pensarci. Tuttavia, in alcune situazioni, ad esempio, se un'applicazione web utilizza il proprio meccanismo di sessione, cache-Control intestazione può essere impostata in modo non corretto.
Attacchi
Una funzionalità comunemente utilizzata di una cache proxy inversa è la "memorizzazione nella cache aggressiva" (non è in realtà un termine ufficiale, ma descrive l'idea). In alcuni casi (ad esempio, un back-end può essere troppo rigoroso sulla memorizzazione nella cache e non consente di memorizzare nella cache) un amministratore, anziché modificare il back-end, modifica le regole di un proxy inverso, in modo da avviare la memorizzazione nella cache risposte anche con cache-controllo intestazione che limita la memorizzazione. Di solito tali regole hanno alcune limitazioni. Ad esempio, per memorizzare nella cache solo le risposte di determinate estensioni (.jpg, .css, .js) o da percorsi specifici (/images/).
Se un proxy inverso dispone di una regola basata sul percorso che consente la memorizzazione nella cache aggressiva, un utente malintenzionato può creare un percorso che rientra nella regola ma verrà interpretato come un percorso completamente diverso da un server back-end.
Ad esempio, prendiamo di nuovo Nginx-Tomcat. La regola successiva intende forzare Nginx a memorizzare nella cache tutte le risposte dalla directory /images di Tomcat.

Codice: Seleziona tutto

location /images {

Codice: Seleziona tutto

proxy_cache my_cache;

Codice: Seleziona tutto

proxy_pass http://tomcat_server;

Codice: Seleziona tutto

proxy_cache_valid 200 302 60m;

Codice: Seleziona tutto

proxy_ignore_headers Cache-Control Expires;

Come aggressori, possiamo abusare di questa regola per eseguire un attacco di inganno cache web. Tutto quello che dobbiamo fare è forzare un utente vittima per aprire l'URL successivo (utilizzando img, per esempio):

Codice: Seleziona tutto

<img src="http://nginx_with_tomcat.com/images/..;/index.jsp">

Il browser di una vittima invia quindi una richiesta (con cookie di autenticazione). Nginx vede /images, quindi inoltra la richiesta a Tomcat e quindi memorizza nella cache una risposta (non si preoccupa delle intestazioni Cache-Control). Anche in questo caso, per Tomcat, un percorso dopo la normalizzazione è completamente diverso – /index.jsp. In questo modo un utente malintenzionato può forzare Nginx a memorizzare nella cache qualsiasi pagina di Tomcat. Per leggere questa risposta memorizzata nella cache, l'utente malintenzionato deve solo accedere allo stesso percorso (/images/..;/index.jsp) e Nginx restituisce i dati sensibili della vittima (ad esempio token csrf).
In qualche modo, è solo un inganno cache web variante, ma non solo.
Pensiamo a un attacco di avvelenamento da cache. L'attacco si basa sulla ricerca di valori senza chiave da una richiesta che può influenzare in modo significativo (dal punto di vista di sicurezza) influenzare una risposta, ma allo stesso tempo, questa risposta deve essere memorizzata nella cache da un proxy inverso, pertanto l'intestazione Cache-Control deve essere permissiva. Se mescoliamo tutto insieme, saremo in grado di trovare più modi per sfruttare gli attacchi di avvelenamento della cache.
Immaginiamo la situazione. C'è Nuster (è un proxy di cache basato su Haproxy) e un'applicazione web. L'applicazione web ha una vulnerabilità auto-XSS (che funziona solo nell'account di un utente malintenzionato) in /account/attacker/. Nuster è configurato per memorizzare nella cache tutte le risposte dalla directory /img/ nell'applicazione Web:

Codice: Seleziona tutto

nuster cache on

Codice: Seleziona tutto

nuster rule img ttl 1d if { path_beg /img/ }

L'utente malintenzionato deve solo creare un URL speciale (/img/..%2faccount/attacker/), pertanto Nuster applica una regola di "caching aggressivo", tuttavia, l'app Web restituisce una risposta di self XSS (vede '/account/attacker/'). La risposta con un payload XSS verrà memorizzata nella cache da Nuster (con la chiave: Host /img/..%2faccount/attacker/), in modo che l'utente malintenzionato sarà in grado di utilizzare in modo improprio questa cache per xSS attaccare altri utenti dell'applicazione web. Dall'auto-XSS, abbiamo un solito XSS.
Conclusione
Ho mostrato diversi esempi di configurazioni vulnerabili per ogni tipo di attacco. Ma i casi esatti non sono così importanti. Volevo dare un nuovo sguardo sugli attacchi legati al proxy inverso. Se sappiamo come funziona un proxy inverso, come elabora una richiesta e qual è la differenza rispetto a un server back-end, noi (come aggressori) saremo in grado di raggiungere più endpoint o eseguire attacchi più sofisticati sugli utenti.
Per quanto riguarda le protezioni contro tali attacchi, non vedo alcun "proiettile d'argento" qui (fino a quando non abbiamo un ottimo standard / specifica su come gestire una richiesta / percorso), ma penso che questo progetto potrebbe aiutare i difensori pure. Se si conosce il proxy e le relative limitazioni, sarà possibile modificarne la configurazione di conseguenza.
A causa del mio desiderio di condividere i miei pensieri e spiegare le cose, l'articolo è diventato molto lungo. Eppure, ho dovuto saltare un sacco di trucchi. E il punto più importante di questa ricerca – risultati "grezzi". La ricerca non è ancora terminata. Lo realizzerò passo dopo passo con altri software. Le richieste push sono molto apprezzate.
Durante la preparazione di questa ricerca, ho trovato diversi altri tipi di quelli simili, tra cui – https://github.com/irsdl/httpninja. Attraverso una combinazione dei nostri progetti, è possibile ottenere quasi una matrice di possibili incongruenze.

Immagine
Rispondi