Comprendete il rischio delle policy. Ponete domande sulle policy in linguaggio naturale. Richiedi una demo →
Published:
Spezzare le kill chain degli attaccanti in AWS: ruoli IAM
by FireMon
Nell'ultimo anno ho osservato un forte aumento dell'interesse per indicazioni concrete sulla gestione degli incidenti di sicurezza all'interno del cloud, con tecniche cloud native. Man mano che le organizzazioni spostano i propri carichi di lavoro di produzione nel cloud, i professionisti della sicurezza si rendono conto in poco tempo che i fondamentali, pur essendo concettualmente simili, sono piuttosto diversi nella pratica. Uno di questi concetti chiave è quello della kill chain, termine coniato per la prima volta da Lockheed Martin per descrivere il processo seguito dall'attaccante. Se si spezza un anello si blocca l'attacco, quindi il concetto si presta bene a combinare la difesa in profondità con le componenti attive della risposta agli incidenti.
Nelle implementazioni cloud esistono quattro grandi categorie di attacco, ciascuna con kill chain diverse:
- Attacchi alla piattaforma cloud stessa. Escludendo una compromissione radicale del provider cloud (fuori dal controllo del cliente cloud), questi attacchi si concentrano tipicamente su configurazioni errate dei servizi cloud. Se si lascia pubblico un bucket S3, non si imposta un authorizer su un API Gateway o si espongono le proprie credenziali AWS su GitHub, si ricade in questa categoria.
- Attacchi a risorse e applicazioni distribuite dal cliente nel cloud. Questi attacchi tradizionali non sono diversi da quelli condotti contro il proprio data center. Esempi comuni sono la SQL injection in un'applicazione web e i server vulnerabili con le porte sbagliate aperte verso Internet. Tendono a essere un po' più circoscritti rispetto a quelli contro un data center, ammesso che si utilizzino account/sottoscrizioni/progetti e VPC o reti virtuali per limitare il raggio d'azione.
- Attacchi contro gli amministratori cloud e gli sviluppatori. La prossima volta che esegue un penetration test, si assicuri di consentire agli attaccanti di provare a effettuare phishing verso i suoi sviluppatori e amministratori. È uno dei modi migliori per entrare nel cloud, poiché per un attaccante è spesso molto più facile ottenere l'accesso al sistema di uno sviluppatore che violare l'applicazione cloud stessa. Tratteremo questo tema in futuro; per ora limitiamoci a dire che "l'MFA è nostra amica".
- Attacchi combinati. È la categoria su cui ci concentreremo oggi. In questi attacchi il threat actor viola qualcosa di distribuito nel cloud e poi lo utilizza per spostarsi verso il management plane del cloud. (Alcuni considerano combinati anche gli attacchi contro gli sviluppatori, ma preferisco trattarli separatamente).
Come regola generale parto sempre dal presupposto che qualsiasi attacco riuscito, a qualsiasi livello, possa scalare o evolvere in un attacco combinato: a quel punto la sicurezza del management plane e la risposta agli incidenti diventano le difese migliori.
Oggi mi concentrerò su uno dei processi di attacco combinato più comuni e illustrerò un insieme di controlli investigativi e preventivi utili a spezzare la kill chain. Prima di entrare nel dettaglio, non consideri questo articolo come una semplificazione eccessiva di un problema complesso. Gestire su larga scala ciò di cui sto per parlare è estremamente difficile anche quando si sa quello che si fa.
Nelle prossime settimane distribuiremo ai nostri clienti in early access le prime Ops progettate specificamente per questi problemi e relativamente poco dopo dovremmo averle in produzione.
L'attacco combinato su AWS: estrazione delle credenziali dei ruoli IAM
In un attacco combinato il threat actor viola qualcosa di più tradizionale e poi lo utilizza per spostarsi verso il management plane del cloud. Ciò avviene principalmente in tre modi. In ciascun caso l'attaccante estrae credenziali statiche memorizzate oppure credenziali effimere di ruoli IAM, che spiegheremo tra poco.
- Compromissione diretta di un'istanza o di un container. Per esempio, se si lascia aperta la porta 22 e l'attaccante riesce a entrare o a ottenere in altro modo l'accesso alla shell.
- Server Side Request Forgery (SSRF). L'attaccante sfrutta (tipicamente) una vulnerabilità di un server o servizio web e può eseguire comandi senza ottenere l'accesso alla shell.
- Compromissione di una funzione Lambda. Sebbene non sia possibile ottenere una shell su una Lambda, queste restano soggette a vulnerabilità di esecuzione di codice e persino all'esecuzione di codice arbitrario se contengono un difetto applicativo. Le implicazioni concrete possono assomigliare a quelle dell'SSRF.
In ogni caso l'obiettivo dell'attaccante è ottenere le credenziali del management plane di AWS e poi sfruttare i privilegi esistenti o scalare i privilegi. Parleremo dell'escalation dei privilegi in un prossimo articolo; per ora ci concentreremo su quali siano queste credenziali e su come si possa impedirne l'abuso.
La maggior parte delle persone conosce le credenziali statiche, che in AWS sono una Access Key e una Secret Key. Sono come un nome utente e una password, ma vengono usate per le chiamate API di AWS. La versione attuale utilizza un processo crittografico noto come Signature 4 per la firma delle richieste HTTP quando si effettuano tali chiamate API. Si possono e si devono trattare esattamente come un nome utente e una password, e non vanno mai memorizzate all'interno di risorse cloud come istanze e Lambda.
I ruoli IAM sono più insidiosi quando si inizia a usare AWS: sono allo stesso tempo eccellenti e preoccupanti. Un IAM Role in AWS è di fatto un contenitore di autorizzazioni utilizzato per una sessione. Gli IAM Role sono ottimi perché non sono credenziali in senso stretto: quando si assume il ruolo, AWS fornisce un insieme di credenziali per una sessione a tempo limitato. I ruoli esistono "solo all'interno di AWS". È possibile assegnarli a risorse all'interno di AWS (come un'istanza o una funzione Lambda) e quella risorsa può quindi effettuare chiamate API senza credenziali statiche memorizzate! Utilizziamo i ruoli per le connessioni di identità federata, le istanze, le funzioni Lambda e ogni altro servizio all'interno di AWS. Le access key servono in realtà solo quando si crea un utente in un account AWS: per tutto il resto usiamo i ruoli.
Ai ruoli sono associati quattro tipi di autorizzazione:
- Ciò che il ruolo può fare all'interno di AWS. Sono le vere e proprie permission policy che si collegano al ruolo.
- Chi o cosa può usare il ruolo (la trust policy). Creare un ruolo non significa che chiunque o qualsiasi cosa possa utilizzarlo: questa policy limita l'accesso, per esempio, alle istanze AWS o a una specifica funzione Lambda.
- Un permission boundary per limitare l'ambito del ruolo. È un aspetto un po' più complesso e non rilevante per la discussione di oggi, quindi lo tratteremo più avanti.
- Quando si assume un ruolo per una sessione, è anche possibile specificare un sottoinsieme delle autorizzazioni esistenti da usare per quella sessione. È una funzionalità interessante per il privilegio minimo, ma anch'essa non del tutto rilevante per la discussione di oggi.
Probabilmente è più semplice spiegare come funziona ripercorrendone i passaggi. Supponiamo di avere un'applicazione che deve accedere a un bucket S3 o a un database Dynamo. Creo un ruolo IAM per l'istanza e imposto la trust policy in modo che il servizio EC2 possa utilizzare il ruolo. Poi avvio un'istanza e le assegno il ruolo. AWS esegue l'istanza e le fa assumere il ruolo. L'assunzione del ruolo apre una sessione e assegna una access key, una secret key e un session token. AWS ruota poi queste credenziali ogni 1-6 ore e l'istanza può ora effettuare le chiamate API autorizzate dalle permission policy.
Sebbene le credenziali non si trovino nell'istanza, le credenziali restano accessibili all'istanza. Qualsiasi codice in esecuzione al suo interno deve conoscere le credenziali per effettuare le chiamate API di accesso a S3 e Dynamo, quindi un componente noto come metadata service le fornisce su richiesta. Il metadata service è un elemento particolare di AWS per istanze e container che contiene tutte le informazioni sulla loro configurazione. È piuttosto importante, per esempio, che un server possa ottenere il proprio indirizzo IP.
Ed è qui che entra in gioco l'attacco.
Il metadata service è semplicemente un url a cui si può accedere per ottenere le informazioni richieste. curl 169.254.169.254/latest/meta-data/ fornisce tutte le informazioni di base, e usando il percorso curl 169.254.169.254/latest/meta-data/iam-security-credentials/ si ottengono access key, secret key e token. (Nel caso di un attacco basato su Lambda tutto questo si presenta diversamente e si usa codice SDK anziché curl, ma valgono gli stessi principi).
L'attaccante può quindi copiare quelle credenziali e utilizzarle altrove, incorporandole in strumenti invece di dover caricare ed eseguire codice sul server compromesso. Inoltre, essendo basato su URL, il metadata service è esposto a una gamma più ampia di attacchi SSRF, poiché non è necessaria l'esecuzione completa di codice arbitrario. Le credenziali scadranno a un certo punto, ma a seconda dell'attacco l'aggressore potrebbe semplicemente tornare a prenderne un nuovo set quando si accorge che quelle attuali hanno smesso di funzionare.
Oggi gli attaccanti più accorti utilizzano le credenziali all'interno di un account AWS che controllano, poiché Amazon dispone di strumenti in grado di rilevare credenziali estratte e utilizzate al di fuori dei propri intervalli di indirizzi noti.
Interrompere la kill chain di estrazione dei ruoli IAM
Vediamo come si compone la kill chain. L'attaccante deve fare quanto segue:
- Individuare e sfruttare una vulnerabilità in un'istanza, un container o una Lambda che gli consenta di accedere alle credenziali del ruolo. Si tratta quasi sempre di un errore lato cliente… come la mancata applicazione delle patch, l'apertura delle porte sbagliate o la distribuzione di codice vulnerabile.
- Estrarre le credenziali correnti del ruolo.
- Eseguire con successo le chiamate API consentite in un ambiente sotto il proprio controllo.
- Compiere qualcosa di dannoso entro l'ambito della policy di autorizzazione del ruolo IAM consentito. Probabilmente dannoso, intendo: non è che la maggior parte degli attaccanti applichi le patch al vostro codice.
Le tecniche seguenti possono spezzare diversi anelli della catena e comprendono un insieme di controlli investigativi e preventivi. Non preoccupatevi se tutto questo sembra soverchiante… pochissime, VERAMENTE pochissime delle organizzazioni con cui lavoro le implementano in modo completo, soprattutto su larga scala.
6 tecniche per spezzare diversi anelli della catena d'attacco
- Gestione delle vulnerabilità
- Policy di autorizzazione IAM a privilegio minimo con restrizioni sulle risorse
- Utilizzo di restrizioni condizionali su IP, VPC o altra origine della richiesta nelle policy di autorizzazione
- Utilizzo di service endpoint con policy + policy delle risorse
- Aggiunta di proxy per i metadati con filtri sull'HTTP User Agent (protezione del servizio metadati)
- Protezione dall'uso duplicato dei ruoli
Gestione delle vulnerabilità
- Complessità: moderata
- Efficacia: bassa
- Scalabilità: difficile
- Tipo: Investigativo e preventivo
Non sorprende che si debba partire eliminando tutte le vulnerabilità e le configurazioni errate iniziali che l'attaccante può sfruttare per muoversi lateralmente e sottrarre le credenziali. Ho valutato la complessità come moderata solo perché non c'è nulla di nuovo o di specifico del cloud in tutto ciò. Ma valuto l'efficacia come bassa, dal momento che una gestione completa delle vulnerabilità non ha certo impedito le innumerevoli violazioni degli ultimi decenni. Semplice in teoria, incredibilmente complessa su larga scala.
Policy di autorizzazione IAM a privilegio minimo con restrizioni sulle risorse
- Complessità: moderata
- Efficacia: alta
- Scalabilità: da moderata a difficile
- Tipo: Preventivo
Le policy IAM in AWS prevedono il deny come impostazione predefinita e includono istruzioni esplicite di allow e deny. Ad esempio, potete scrivere una policy che consenta solo la lettura di un bucket S3. Includono inoltre restrizioni sulle risorse: mentre l'istruzione allow autorizza il ruolo a chiamare l'API di lettura, la restrizione sulla risorsa consente al ruolo di leggere solo bucket o oggetti specifici. Le vostre difese dovrebbero SEMPRE partire da qui. Quando svolgo delle valutazioni riscontro, in quasi ogni singolo progetto, policy IAM che concedono troppi privilegi (le chiamate API) e troppo poche restrizioni sulle risorse. Sì, quel servizio potrebbe aver bisogno di accedere a un database Dynamo, ma ha davvero bisogno di accedere a ogni tabella? Questo particolare controllo non è troppo difficile da implementare su piccola scala, ma più siete grandi e più sono le persone che prendono queste decisioni sulle policy, più diventa difficile mantenere la coerenza su larga scala. È inoltre importante aggiungere istruzioni deny esplicite, nel caso in cui qualcuno aggiunga al ruolo una nuova policy con nuove autorizzazioni. Le autorizzazioni sono cumulative, ma qualsiasi istruzione deny prevale sulle istruzioni allow.
Utilizzo di restrizioni condizionali su IP, VPC o altra origine della richiesta nelle policy di autorizzazione
- Complessità: alta
- Efficacia: da moderata ad alta
- Scalabilità: difficile
- Tipo: Preventivo
Le policy IAM supportano istruzioni condizionali che prevedono diverse opzioni, tra cui l'indirizzo IP o il VPC di origine. Se sapete che un determinato ruolo deve effettuare chiamate API esclusivamente da una risorsa specifica del vostro stack applicativo, potete vincolare l'autorizzazione a quell'esatto indirizzo IP o sottorete. Se l'attaccante sottrae le credenziali e prova a usarle altrove, le chiamate API falliranno. È una mazza guidata con precisione: semplice in teoria e difficile nell'esecuzione, perché potreste scoprire che altre complessità interferiscono con una corretta implementazione. Ad esempio, le chiamate API verso i servizi AWS raggiungono Internet direttamente, passano per un NAT Gateway oppure vengono instradate internamente con un service endpoint (di cui parleremo tra poco). L'indirizzo IP rilevato dipenderà dal percorso seguito dalla chiamata API verso Internet. Sono tutti aspetti gestibili e rilevabili (nonché automatizzabili), ma è bene documentarsi prima per assicurarsi di aver compreso tutte le combinazioni possibili.
Per alcuni esempi, consultate la prima parte di questo post di Netflix.
A meno che non eseguiate la vostra funzione Lambda su un VPC, questa non sarà un'opzione praticabile per proteggere una funzione compromessa.
Utilizzo di service endpoint con policy + policy delle risorse
- Complessità: moderata
- Efficacia: da moderata ad alta
- Scalabilità: moderata
- Tipo: Preventivo
In AWS un service endpoint è come una derivazione sulla rete che prende il traffico normalmente diretto a un servizio AWS via Internet e lo reinstrada internamente. Sono stati creati in origine per consentire alle sottoreti completamente private in AWS, prive di qualsiasi possibilità di raggiungere Internet, di accedere comunque a determinati servizi AWS. Gli endpoint supportano policy che potete usare per limitare accessi e azioni in modi molto simili alle policy IAM. In questo caso aggiungete alla policy dell'endpoint restrizioni che consentano solo l'accesso a risorse specifiche dietro quell'endpoint (S3 è l'esempio più comune). Specificate quali bucket sono consentiti e nessun'altra risorsa in quella sottorete avrà accesso a quel servizio. Consideratelo una rete di sicurezza per la policy IAM: con un service endpoint dotato di una policy restrittiva, anche se qualcuno concedesse accidentalmente (o deliberatamente) al ruolo un accesso più ampio del dovuto, il ruolo non potrebbe comunque accedere a nulla che non sia consentito dalla policy del service endpoint. Ciò significa che ora abbiamo tre livelli di policy, che devono tutti consentire l'accesso alla risorsa:
- La policy di autorizzazione IAM che consente al ruolo di accedere alla risorsa.
- La policy del service endpoint che consente l'accesso alle risorse quando le richieste transitano dall'endpoint, indipendentemente dalle autorizzazioni del ruolo utilizzato.
- La policy del bucket o della risorsa (dipende dal tipo di risorsa), che può limitare l'accesso ai soli indirizzi IP approvati.
A meno che non eseguiate la vostra funzione Lambda su un VPC, anche in questo caso non sarà un'opzione praticabile per proteggere una funzione compromessa.
Aggiunta di proxy per i metadati con filtri sull'HTTP User Agent (protezione del servizio metadati)
- Complessità: alta
- Efficacia: moderata
- Scalabilità: difficile
- Tipo: Preventivo
Tutti questi controlli presuppongono che un attaccante possa sottrarre le credenziali del ruolo, ma se avessimo un modo per ridurne la capacità di ottenerle anche in caso di compromissione dell'istanza o del container autorizzati? (Questa tecnica non funziona per le funzioni Lambda.) Un'opzione emergente consiste nel limitare in primo luogo l'accesso al servizio metadati. Ci sono stati alcuni tentativi di farlo con IPTables, ma ciò potrebbe compromettere funzionalità necessarie al codice in esecuzione sull'istanza. Nel novembre 2018 AWS e Netflix hanno collaborato e hanno iniziato ad aggiungere agli header HTTP i dati utente per le chiamate API effettuate dagli SDK AWS. Si tratta di una difesa contro l'SSRF, poiché la maggior parte degli attacchi SSRF si basa sull'indurre un'applicazione a effettuare richieste HTTP per conto dell'attaccante, ma tali richieste provengono di solito da uno strumento a riga di comando come curl o da un altro processo e non conterranno l'header con i dati utente generato dagli SDK AWS. Per far funzionare questo meccanismo occorre inserire un proxy per quelle richieste. Esistono alcune opzioni open source per istanze e container, inclusi proxy che vengono eseguiti sull'istanza anziché richiedere l'instradamento del traffico verso un'appliance virtuale o un proxy squid.
Questa tecnica non funzionerà se l'attaccante compromette l'istanza host ed esegue una shell, poiché in tal caso può disabilitare il Roxy o dirottare il processo approvato.
Potete leggere tutti i dettagli in questo post di Netflix.
Protezione dall'uso duplicato dei ruoli
- Complessità: alta
- Efficacia: alta
- Scalabilità: alta
- Tipo: Investigativo
Anche questa arriva dal team di Netflix. Hanno pubblicato una guida a un'ottima tecnica per rilevare quando un ruolo IAM viene usato in una posizione non autorizzata, anche all'interno di AWS. Consiglio vivamente di leggere il post collegato, ma in sintesi combinano i log di CloudTrail con altri strumenti per mantenere una tabella di quali istanze utilizzano quali ruoli e da quali indirizzi IP. Monitorano poi le altre chiamate API per individuare i casi in cui un ruolo viene riutilizzato da un nuovo indirizzo IP mentre è contemporaneamente in uso da uno approvato. Con questo metodo non è necessario conoscere tutti gli indirizzi IP in uso nell'organizzazione: si costruisce dinamicamente una tabella di ciò che è in uso e si rileva quando quel ruolo viene utilizzato altrove nello stesso momento. È estremamente scalabile, perché la logica può essere eseguita centralmente se centralizzate CloudTrail, cosa che comunque è una best practice diffusa.
Riepilogo
Questo è l'ennesimo post mastodontico e non ci aspettiamo che tutti possano implementare ognuna di queste opzioni in ogni distribuzione. Per semplificare, ripercorriamo la kill chain dell'abuso dei ruoli IAM:
- Individuare e sfruttare una vulnerabilità in un'istanza, un container o una Lambda che gli consenta di accedere alle credenziali del ruolo. Si tratta quasi sempre di un errore lato cliente… come la mancata applicazione delle patch, l'apertura delle porte sbagliate o la distribuzione di codice vulnerabile.
- La gestione delle vulnerabilità (compresi strumenti come SASST e DAST per le applicazioni) e la valutazione della configurazione cloud (con strumenti come DisruptOps o strumenti open source come Prowler e CloudMapper) sono la vostra prima difesa.
- Estrarre le credenziali correnti del ruolo.
- Protezione del servizio metadati e gestione delle vulnerabilità
- Eseguire con successo le chiamate API consentite in un ambiente sotto il proprio controllo.
- Rilevamento dell'uso duplicato dei ruoli, utilizzo di restrizioni condizionali su IP, VPC o altra origine della richiesta nelle policy di autorizzazione, utilizzo di service endpoint con policy + policy delle risorse
- Compiere qualcosa di dannoso entro l'ambito della policy di autorizzazione del ruolo IAM consentito. Probabilmente dannoso, intendo: non è che la maggior parte degli attaccanti applichi le patch al vostro codice.
- Policy di autorizzazione IAM a privilegio minimo con restrizioni sulle risorse
Ci auguriamo che questo vi dia un quadro più chiaro di come ridurre le probabilità di successo di questo tipo di attacchi.