Dalla SSRF alla presa totale di un account cloud: attaccare il servizio di metadati
Un solo bug SSRF in un recuperatore di URL può raggiungere l’endpoint dei metadati cloud, rubare le credenziali del ruolo IAM e sfociare nella presa totale dell’account. Ecco la catena d’attacco – e come spezzarla.

Affidateci un’applicazione web che recupera un URL controllato da voi – un importatore di avatar, un tester di webhook, un pulsante del tipo “genera un PDF da questo link” – e la prima cosa che proviamo è un sondaggio SSRF verso i metadati cloud. L’indirizzo di destinazione cambia appena da un bersaglio all’altro: l’indirizzo link-local 169.254.169.254, dove AWS (e, su percorsi leggermente diversi, GCP e Azure) esegue un servizio di metadati di istanza che consegna credenziali IAM temporanee al carico di lavoro.
Quella singola richiesta è tutta la partita. Un rilievo che si legge come “il server ha fatto una chiamata in uscita che non avrebbe dovuto” diventa in sordina “il server ci ha consegnato la sua identità cloud”. Abbiamo visto un proxy di immagini in sola lettura trasformarsi in una testa di ponte che leggeva bucket S3 ed enumerava altri ruoli. La server-side request forgery è la CWE-918, e su un host cloud non è quasi mai una semplice nota informativa nel report.
Questa guida segue l’intera catena: come una funzione ordinaria diventa SSRF, come la richiesta atterra sull’endpoint dei metadati, perché IMDSv1 contro IMDSv2 decide se l’attacco funziona, e come credenziali rubate salgono verso la presa dell’account. Poi le difese che reggono davvero alla prova dei test.
Punti chiave
- La SSRF (CWE-918) induce un server a inviare richieste HTTP verso destinazioni scelte dall’attaccante, compresi indirizzi interni che l’applicazione può raggiungere ma la rete internet pubblica no.
- Il bottino su un host cloud è l’endpoint dei metadati a 169.254.169.254. Su AWS EC2 con IMDSv1 restituisce credenziali del ruolo IAM temporanee via HTTP in chiaro, senza alcuna autenticazione.
- Quelle credenziali si inseriscono direttamente nella AWS CLI o in un SDK. Se il ruolo dell’istanza ha permessi eccessivi, il bug scala a furto di dati, movimento laterale e presa dell’account.
- IMDSv2 richiede un token di sessione emesso via PUT e impone un limite di hop, il che spezza la maggior parte dei tentativi ingenui di SSRF verso i metadati. Imporlo – cioè disabilitare IMDSv1 – è la singola correzione a maggior impatto.
- Stratificate il resto: allowlist di egress, blocco degli intervalli link-local e RFC 1918, nuova risoluzione degli URL dopo ogni redirect e ruoli di istanza a privilegio minimo.
Che cos’è la SSRF e perché il cloud la peggiora?
La SSRF è una falla in cui un’applicazione accetta in ingresso un URL o un nome host ed effettua verso di esso una richiesta lato server, consentendo a un attaccante di dirigere quella richiesta dove non avrebbe mai dovuto andare. Il browser è tagliato fuori. È il server vulnerabile a fare la chiamata al suo posto, dall’interno del confine di fiducia, oltre il firewall perimetrale, con qualunque accesso alla rete interna abbia l’host.
Su una macchina qualsiasi è già grave: pannelli di amministrazione interni, un’istanza Redis o Elasticsearch non autenticata, una rapida scansione della sottorete interna. Il cloud alza la posta per un motivo ben preciso. Ogni grande provider esegue un servizio di metadati sullo stesso magico indirizzo link-local, 169.254.169.254, raggiungibile solo dall’istanza stessa, e il suo unico compito è consegnare segreti al codice che vi gira. Ingannate l’applicazione perché lo interroghi e l’attaccante eredita l’identità dell’istanza.
Come fa una funzione normale a trasformarsi in SSRF?
La funzione vulnerabile è di solito una di quelle che il team di prodotto ha rilasciato con un certo orgoglio. I soliti sospetti che testiamo:
- Recuperatori di URL e “importa da un link”: foto profilo tramite URL, “importa i tuoi dati da questo URL”, importatori di RSS e sitemap. Il server dereferenzia tutto ciò che incollate.
- Webhook e tester di callback: “invieremo i tuoi eventi in POST verso il tuo endpoint, clicca su Test.” Quel pulsante di test fa scattare una richiesta lato server verso un host scelto da voi.
- Renderer di PDF e immagini: i motori da HTML a PDF e gli screenshotter Headless-Chrome seguono i riferimenti
<img>,<iframe>e CSSurl(). Puntatene uno all’endpoint dei metadati e l’output renderizzato può farvi trapelare indietro la risposta. - Processori di documenti e SVG: i parser XML e i renderer SVG possono essere indotti a recuperare risorse esterne – ed è lì che una XXE si trasforma in sordina in SSRF.
Il segnale rivelatore è qualsiasi parametro che finisce per diventare una richiesta in uscita. Confermiamo quel comportamento prima con un payload fuori banda, di solito Burp Collaborator o un interactsh self-hosted, prima di toccare qualsiasi cosa interna:
POST /api/avatar/import HTTP/1.1
Host: example.com
Content-Type: application/json
{"image_url":"http://abcd1234.oastify.com/ping"}
Se il listener registra un colpo, il server sta recuperando URL per noi. Notate se è stata solo una risoluzione DNS o un callback HTTP completo, perché un colpo solo DNS a volte indica una pipeline di rendering che risolve ma non mostra il corpo. In ogni caso, ora lo puntiamo verso qualcosa di interessante.
Come si raggiunge l’endpoint dei metadati a 169.254.169.254?
Una volta confermate le richieste in uscita, sostituiamo l’host esterno con l’indirizzo link-local dei metadati. Su un’istanza EC2 con IMDSv1, il primo passo chiede quale ruolo è collegato:
GET /latest/meta-data/iam/security-credentials/ HTTP/1.1
Host: 169.254.169.254
Recapitato attraverso il parametro vulnerabile, non è che:
{"image_url":"http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
La risposta è il nome del ruolo. Aggiungetelo al percorso e l’endpoint restituisce credenziali vive:
GET /latest/meta-data/iam/security-credentials/example-app-role HTTP/1.1
Host: 169.254.169.254
{
"Code": "Success",
"AccessKeyId": "ASIAEXAMPLEKEY",
"SecretAccessKey": "EXAMPLEsecret...",
"Token": "IQoJb3JpZ2luX2VjE...",
"Expiration": "2026-07-02T18:00:00Z"
}
Quando uno sviluppatore ha avvitato una blocklist ingenua, saltano fuori i classici bypass. In decimale, lo stesso IP è http://2852039166/; in ottale, http://0251.0376.0251.0376/; e in una forma IPv6 mappata su IPv4, http://[::ffff:169.254.169.254]/. Anche un nome DNS che risolve all’indirizzo link-local funziona. Il nostro preferito nella pratica è un open redirect su un dominio consentito: l’applicazione convalida diligentemente che l’URL punti a un host fidato, segue il 302 e atterra comunque sull’endpoint dei metadati. È esattamente per questo che convalidare la stringa URL iniziale, da sola, non basta.
Qual è la differenza tra IMDSv1 e IMDSv2?
È la differenza tra un medio e un critico. IMDSv1 è un semplice servizio richiesta-risposta: qualsiasi processo in grado di inviare un GET a 169.254.169.254 ottiene una risposta. Nessun token, nessuna sessione, nessuna autenticazione. È esattamente la forma di una SSRF di base – ed è per questo che i due formano un accoppiamento così pericoloso.
IMDSv2 rende il flusso con stato. Il client invia prima un PUT per ottenere un token, poi include quel token come header su ogni GET successivo:
PUT /latest/api/token HTTP/1.1
Host: 169.254.169.254
X-aws-ec2-metadata-token-ttl-seconds: 21600
GET /latest/meta-data/iam/security-credentials/ HTTP/1.1
Host: 169.254.169.254
X-aws-ec2-metadata-token: <token-from-put>
Due proprietà sconfiggono qui la maggior parte delle SSRF. Primo, serve un PUT, e molte primitive di SSRF emettono solo GET e non possono controllare il metodo. Secondo, serve un header di richiesta personalizzato che il recuperatore vulnerabile non aggiungerà al posto vostro. IMDSv2 imposta inoltre un limite di hop di risposta predefinito pari a 1, quindi se la richiesta è stata inoltrata anche solo attraverso un hop di rete aggiuntivo, il servizio di metadati la scarta in silenzio. Ciò che vogliamo vedere imposto è IMDSv1 disabilitato, non semplicemente IMDSv2 disponibile.
Che IMDSv2 sia disponibile non cambia nulla di per sé. Se IMDSv1 è ancora accettato, un attaccante usa semplicemente il vecchio percorso, senza token. L’impostazione che conta è HttpTokens = required.
Come diventa l’accesso a credenziali rubate una presa dell’account?
Le credenziali dal servizio di metadati sono normali chiavi temporanee STS: una chiave di accesso, un segreto e un token di sessione. Esportiamo le tre e guidiamo la CLI con l’identità del ruolo dell’istanza:
export AWS_ACCESS_KEY_ID=ASIAEXAMPLEKEY
export AWS_SECRET_ACCESS_KEY=EXAMPLEsecret...
export AWS_SESSION_TOKEN=IQoJb3JpZ2luX2VjE...
aws sts get-caller-identity
Da qui il raggio d’impatto è una funzione diretta di ciò che quel ruolo è autorizzato a fare. La prima mossa è un’enumerazione silenziosa: quali bucket, quali segreti, quali altri ruoli. Se il ruolo può leggere Secrets Manager o SSM Parameter Store, tiriamo fuori di routine password di database e chiavi API che sbloccano ben più della singola istanza. Se porta con sé ampi diritti IAM – l’anti-pattern che vediamo fin troppo spesso -, la strada verso la presa è breve: collegare una policy admin, coniare una nuova chiave di accesso su un utente privilegiato o assumere un ruolo più forte. Sul fronte dell’attaccante questo si allinea a MITRE ATT&CK Unsecured Credentials (T1552) e al riuso di materiale di autenticazione alternativo.
La lezione di anni di questi ingaggi è netta. La gravità di una SSRF è fissata dal ruolo dell’istanza, non dal bug web in sé. Un ruolo strettamente delimitato trasforma un rilievo dall’aria spaventosa in uno circoscritto. Un ruolo permissivo trasforma un singolo parametro URL in un incidente esteso a tutto il cloud.
Come si prevengono gli attacchi SSRF verso i metadati?
Non esiste un interruttore unico, perciò raccomandiamo di stratificare i controlli qui sotto. Ognuno preso da solo può essere aggirato. Impilati insieme, rendono la catena davvero difficile da portare a termine.
- Imporre IMDSv2 e disabilitare IMDSv1. Impostate HttpTokens su required su ogni istanza e integratelo nelle launch template e nelle AMI, così i nuovi host lo ereditano per impostazione predefinita. Dove un carico di lavoro non ha mai bisogno dei metadati di istanza, spegnete del tutto l’endpoint.
- Bloccare gli intervalli link-local e privati. L’applicazione – o un forward proxy attraverso cui deve obbligatoriamente passare – dovrebbe rifiutare le connessioni verso 169.254.0.0/16, gli intervalli RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) e il loopback. Fatelo a livello di rete, non solo nel codice applicativo.
- Filtraggio dell’egress con allowlist. Il traffico in uscita dagli host applicativi dovrebbe raggiungere solo le destinazioni di cui una funzione ha legittimamente bisogno. Un recuperatore di URL che attinge sempre e solo da un’unica API partner non ha nulla da fare su un IP interno.
- Convalidare e ri-risolvere gli URL. Analizzate l’URL, rifiutate gli schemi non HTTP e le porte insolite, risolvete il nome host in un IP e verificate quell’IP contro la vostra denylist prima di connettervi. Ricontrollate dopo ogni redirect così che un 302 non possa condurvi nel servizio di metadati. Questo smorza anche il DNS rebinding.
- Ruoli di istanza a privilegio minimo. Delimitate ogni ruolo a ciò che il suo carico di lavoro usa davvero, e a nient’altro. È il controllo che mette un tetto al danno quando gli altri cedono.
Un avvertimento dal campo: le blocklist di stringhe che combaciano con “169.254.169.254” e si accontentano falliscono di continuo contro le forme decimale, ottale e IPv6. Risolvete a un IP numerico e confrontate contro intervalli, mai contro il testo letterale.
Come aiuta CyberXplore
La SSRF verso i metadati è uno dei percorsi standard che i nostri tester battono durante un ingaggio di penetration testing cloud. Mettiamo alla prova la funzione che effettua richieste in uscita, tentiamo la catena completa fino al servizio di metadati e poi tracciamo fin dove le credenziali del ruolo rubate arriverebbero davvero nel vostro account – così ottenete il reale impatto di business invece di una casella spuntata. Se volete che ciò venga eseguito contro il vostro ambiente, richiedete un preventivo e ne definiremo il perimetro insieme a voi.
FAQ
La SSRF è ancora un rischio reale se giro nel cloud con un firewall?
Sì. Un firewall perimetrale qui non fa nulla, perché la richiesta malevola nasce dentro la vostra stessa istanza, proprio dove il servizio di metadati è raggiungibile. La SSRF trasforma il vostro server fidato nel proxy dell’attaccante, così qualsiasi controllo che ispezioni solo il traffico in entrata viene aggirato. Vi servono controlli di egress e un IMDSv2 imposto, non solo un firewall in entrata.
IMDSv2 impedisce del tutto alla SSRF di rubare credenziali?
Ferma la grande maggioranza dei casi reali, ma non è assoluto. IMDSv2 sconfigge la SSRF limitata ai GET e qualsiasi richiesta che attraversi un hop aggiuntivo, il che copre la maggior parte dei bug che troviamo. Una SSRF molto flessibile, in grado di emettere un PUT e iniettare l’header personalizzato richiesto, potrebbe comunque passare – ed è per questo che IMDSv2 va affiancato ai ruoli a privilegio minimo e al filtraggio di egress, anziché essere trattato come l’unico controllo.
Che cos’è l’indirizzo 169.254.169.254 e perché continua a saltar fuori?
È l’IP link-local che i provider cloud usano per esporre il loro servizio di metadati di istanza, raggiungibile solo dall’istanza stessa. Su AWS serve i metadati EC2 e, soprattutto, le credenziali del ruolo IAM temporanee. GCP e Azure espongono servizi simili a quell’indirizzo o tramite nomi host di metadati – il che ne fa il primo bersaglio universale non appena un attaccante conferma una SSRF su un host cloud.
Come faccio a capire se una funzione è vulnerabile prima che lo faccia un attaccante?
Cercate qualsiasi input che diventa una richiesta in uscita lato server: importatori di URL, webhook, renderer di PDF o immagini, parser di documenti. Testate ciascuno con un listener fuori banda come Burp Collaborator o interactsh. Se il server raggiunge il vostro listener, verificate se raggiunge anche indirizzi interni e link-local e se segue i redirect verso di essi. È il comportamento che sondiamo in un penetration test.
Quali CWE e quali standard coprono questo problema?
La server-side request forgery è la CWE-918, e ha una propria categoria, la A10, nell’OWASP Top 10 (2021). Sul fronte dell’attaccante, raccogliere credenziali di istanza e usarle si mappa su MITRE ATT&CK intorno alle unsecured credentials (T1552) e all’uso di materiale di autenticazione alternativo. Citarli in un report aiuta i team a classificare e instradare correttamente la correzione.
Qual è la singola correzione più importante?
Imponete IMDSv2 con IMDSv1 disabilitato su ogni istanza, poi delimitate i vostri ruoli di istanza al privilegio minimo. Il primo cambiamento spezza di netto la comune tecnica di SSRF verso i metadati. Il secondo garantisce che perfino un furto di credenziali riuscito resti confinato a un piccolo e ben compreso insieme di permessi anziché al vostro intero account.



