SSRF na prática: quando uma vulnerabilidade web vira comprometimento de uma conta AWS

SSRF na prática: quando uma vulnerabilidade web vira comprometimento de uma conta AWS

Quando pensamos em SSRF, normalmente pensamos em uma aplicação sendo usada como proxy para acessar algum serviço interno. É uma vulnerabilidade conhecida, mas que continua aparecendo com frequência em aplicações reais.

O cenário fica bem mais interessante quando essa aplicação está rodando dentro da AWS. Nesse caso, uma requisição que aparentemente deveria apenas consultar uma URL pode acabar chegando a serviços que fazem parte da própria infraestrutura da aplicação. Entre eles está o Instance Metadata Service (IMDS), utilizado por instâncias EC2 para obter informações sobre seu ambiente e, quando configurado, credenciais temporárias de uma IAM Role.

Foi exatamente esse caminho que encontrei durante a exploração da máquina Typhon, do HackingClub. A partir de um código-fonte exposto, foi possível identificar um SSRF, confirmar que o servidor realizava requisições arbitrárias e, depois, usar essa funcionalidade para interagir com o IMDSv2. O resultado foi o acesso às credenciais temporárias da IAM Role da instância e, com elas, a recursos de um bucket S3.

O interessante aqui é entender como uma vulnerabilidade na aplicação pode ir muito além da camada web. Quando o SSRF permite acessar serviços internos, o impacto deixa de se limitar ao site e pode alcançar a infraestrutura em cloud e até o próprio sistema operacional.

O endpoint vulnerável no código-fonte

O reconhecimento inicial revelou um servidor HTTP e SSH. A aplicação web utilizava virtual hosts e, durante a enumeração, apareceu um subdomínio rodando Gitea. O problema é que havia um repositório que deveria ser privado, mas estava acessível publicamente. Esse repositório continha o código-fonte da aplicação NexStore.

Com o código em mãos, eu já não dependia apenas do que a interface mostrava. Era possível revisar diretamente a implementação dos endpoints, e um deles chamou atenção: o /api/notify

Na imagem abaixo, podemos ver a implementação desse endpoint no arquivo server.js. O código recebe os valores de webhookUrl e orderId, extrai o host, a porta e o caminho informados e abre uma conexão TCP diretamente com o destino. O problema é que a aplicação não verifica se esse destino pertence a uma rede interna ou a um endereço reservado, O destino informado pelo usuário não passava por nenhuma validação capaz de bloquear redes internas ou endereços reservados. Era ali que estava o SSRF.

Implementação do endpoint /api/notify no arquivo server.js.

Para entender como esses valores eram enviados à aplicação, interceptei a requisição com o Burp Suite. A captura abaixo mostra a chamada ao endpoint /api/notify, com os parâmetros webhookUrl e orderId no corpo da requisição. Como o valor de webhookUrl era controlado pelo usuário, bastava alterá-lo para fazer o servidor tentar se conectar a outro endereço.

PoC via Burp Repeater: webhookUrl apontando para o listener do atacante. "notified": true confirma que a requisição saiu do servidor.

A pista de que havia uma EC2

Durante a enumeração, o hostname ip-172-16-6-12.ec2.internal revelou que a aplicação estava em uma instância EC2. Com o SSRF confirmado nesse ambiente, o próximo alvo era o IMDS.

O IMDS fica acessível a partir da própria instância e fornece metadados sobre o ambiente. Quando uma IAM Role está associada à EC2, esse serviço também entrega as credenciais temporárias usadas pela aplicação, evitando que chaves permanentes precisem ser armazenadas no código.

Se o /api/notify conseguia alcançar o IMDS, havia a possibilidade de obter as mesmas credenciais utilizadas pela instância.

IMDSv1 seria o cenário mais simples

O endereço tradicional do serviço de metadata é:

169.254.169.254

Em ambientes que utilizam IMDSv1, o acesso é relativamente direto. Uma aplicação que consiga realizar requisições arbitrárias pode tentar consultar o serviço e obter informações disponíveis naquele contexto. Por isso, proteger o IMDS é uma das medidas importantes contra o abuso de SSRF em EC2.

A AWS criou o IMDSv2 justamente para adicionar uma camada de proteção a esse fluxo. A Datadog aborda esse problema de forma bastante interessante no artigo Misconfiguration Spotlight: IMDS, destacando o risco de expor aplicações a SSRF quando o acesso ao metadata service não está devidamente protegido.

No IMDSv2, o acesso não começa simplesmente com um GET. Primeiro é necessário obter um token utilizando uma requisição PUT. Depois, esse token é enviado nos headers das requisições seguintes. Na prática, o fluxo passa a ser algo parecido com:

Fluxo de acesso ao IMDSv2: a aplicação obtém um token com uma requisição PUT e o envia nas requisições seguintes para consultar os metadados da instância.

Isso dificulta alguns cenários de SSRF. Se uma aplicação permite apenas informar uma URL, por exemplo, pode não ser possível completar o fluxo exigido pelo IMDSv2. Só que não era esse o caso aqui.

Acessando o IMDSv2 com o SSRF

O /api/notify fazia mais do que receber uma URL de destino. Pelo corpo da requisição, também era possível definir o método HTTP e adicionar headers. Isso permitia reproduzir o fluxo exigido pelo IMDSv2: enviar uma requisição PUT para obter o token e reutilizá-lo nas consultas seguintes.

A exploração foi dividida em três etapas: obter o token, identificar a IAM Role associada à instância e consultar suas credenciais temporárias.

A primeira etapa consistiu em obter um token do IMDSv2. Para isso, o SSRF foi usado para enviar uma requisição PUT ao endpoint /latest/api/token, incluindo o header que define o tempo de vida do token. A imagem abaixo mostra essa requisição sendo enviada pelo /api/notify e o token retornado na resposta.

Etapa 1: PUT via SSRF obtém o token IMDSv2.

Com o token em mãos, a etapa seguinte era descobrir qual IAM Role estava associada à instância. Na captura abaixo, o token é enviado no header da requisição para /latest/meta-data/iam/security-credentials/. A resposta do IMDSv2 revela o nome da Role utilizada pela máquina: MACHINE_ECOMMERCE_ROLE.

Etapa 2: com o token, o SSRF enumera a Role: MACHINE_ECOMMERCE_ROLE.

Depois de identificar a Role, bastava consultar o mesmo caminho acrescentando seu nome ao final da URL. A última imagem mostra a requisição para /latest/meta-data/iam/security-credentials/MACHINE_ECOMMERCE_ROLE e a resposta contendo as credenciais temporárias, incluindo AccessKeyId, SecretAccessKey e Token. Os valores sensíveis foram ocultados na captura.

Etapa 3: credenciais temporárias da Role (SecretAccessKey e Token ocultados no print).

Com as credenciais temporárias em mãos, o impacto do SSRF foi além do acesso a um serviço interno. A partir delas, era possível realizar chamadas às APIs da AWS com as permissões da IAM Role associada à instância.

Até onde essa IAM Role permitia chegar?

Em uma instância EC2, a IAM Role funciona como a identidade da aplicação dentro da AWS. É ela que define quais APIs e recursos podem ser acessados sem a necessidade de manter credenciais permanentes no código.

Quando as credenciais temporárias dessa Role são expostas, o atacante passa a realizar chamadas com as mesmas permissões. Obter as credenciais, portanto, era apenas parte do caminho. A próxima pergunta era a mais importante:

o que essa Role conseguia acessar?

No caso da Typhon, a resposta estava no S3.

Do IMDS ao S3

Com as credenciais temporárias obtidas através do IMDS, foi possível interagir com a AWS usando a identidade da instância. Durante a enumeração, apareceu o bucket s3-ecommerce-bucket-prod. Dentro dele havia um backup do ambiente, e o backup acabou revelando algo ainda mais interessante: uma chave SSH associada ao usuário zeus.

Nesse caso específico foi uma chave SSH, mas backups de ambiente em S3 são uma mina de achados em ambientes reais. É comum encontrar arquivos .env com credenciais de banco de dados e chaves de API de terceiros (Stripe, SendGrid, Twilio), dumps .sql inteiros de produção, arquivos .git/ completos com histórico de commits (inclusive secrets já "removidos" mas ainda no histórico) etc... Qualquer um desses achados poderia ter aberto um caminho tão bom quanto, ou pior que, a chave do zeus.

usando as credenciais roubadas do IMDS diretamente na AWS CLI:

export AWS_ACCESS_KEY_ID="ASIA6G2S5QLBOK6ZFL53"
export AWS_SECRET_ACCESS_KEY="Q7uG7A***************************ihR"
export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2VjEJn...(truncado)"

aws sts get-caller-identity
AWS: 976742089410  arn:aws:sts::976742089410:assumed-role/MACHINE_ECOMMERCE_ROLE/i-03311e685355dcf51

A identidade retornada confirma que as credenciais são válidas e pertencem à IAM Role da instância. A partir daí, o bucket relevante foi localizado e o backup baixado:

aws s3 ls s3://s3-ecommerce-bucket-prod/
2026-04-17 18:23:55    3813117 backup_dev_core.zip
aws s3 cp s3://s3-ecommerce-bucket-prod/backup_dev_core.zip .
unzip -o backup_dev_core.zip
cat backup_dev/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFcjyVZNlGximpNFXdpaZmlDwyu1ujk9huIwdQHpYX/u zeus@ip-172-16-9-227

O comentário da chave pública (zeus@ip-172-16-9-227) já entrega a quem ela pertence, bastava usar a chave privada correspondente para autenticar.

Esse foi um daqueles momentos em que a exploração muda novamente de direção. O objetivo inicial era explorar uma aplicação web. Agora havia uma identidade AWS. Depois, essa identidade dava acesso a um bucket. E o bucket continha uma credencial que podia ser usada contra o próprio servidor.

A chave foi recuperada do backup e utilizada para autenticar como zeus via SSH.

autenticação SSH com a chave recuperada do bucket:

chmod 600 backup_dev/.ssh/id_ed25519
ssh -i backup_dev/.ssh/id_ed25519 [email protected] "whoami; hostname; id"
zeus
ip-172-16-4-66
uid=1001(zeus) gid=1001(zeus) groups=1001(zeus),100(users)

Uma vulnerabilidade que começou em um endpoint HTTP acabou fornecendo acesso ao sistema operacional.

O SSRF não fez tudo sozinho

Resumir essa exploração como “o SSRF roubou credenciais AWS” esconde as condições que tornaram a cadeia possível. O código-fonte estava exposto, o endpoint aceitava URL, método e headers controlados pelo usuário, a EC2 utilizava uma IAM Role com acesso ao S3 e o bucket armazenava uma chave SSH reutilizável.

O SSRF abriu o caminho, mas o impacto veio da combinação entre a falha da aplicação, as permissões da Role e o conteúdo do backup. Se qualquer uma dessas peças fosse diferente, a exploração poderia ter terminado antes.

E se a IAM Role tivesse menos permissões?

Aqui entra o princípio de Least Privilege. A IAM Role de uma aplicação deveria ter apenas as permissões que ela realmente precisa. Se uma aplicação precisa ler alguns objetos de um bucket específico, não existe motivo para sua Role possuir permissões amplas sobre todos os buckets da conta.

Isso não impediria necessariamente o SSRF, mas poderia impedir que o SSRF chegasse tão longe.

Esse é um dos motivos pelos quais IAM é tão importante em ambientes cloud. Não basta pensar em "o que a aplicação precisa fazer quando tudo está funcionando normalmente". Também precisamos pensar:

o que acontece se alguém conseguir controlar essa aplicação?

Uma Role excessivamente permissiva transforma uma vulnerabilidade de aplicação em um problema muito maior.

IMDSv2 não significa que SSRF deixou de ser perigoso

Existe uma ideia comum de que habilitar IMDSv2 resolve o problema de SSRF. Não resolve. IMDSv2 é uma camada importante de proteção e deve ser utilizado, mas a aplicação continua precisando ser protegida contra SSRF.

A recomendação de utilizar IMDSv2 continua sendo extremamente válida. A Datadog também destaca o enforcement do IMDSv2 como uma medida importante de hardening para ambientes EC2. Datadog Security Labs, IMDS Mas isso deve ser tratado como uma camada adicional de proteção, e não como substituto para corrigir a vulnerabilidade.

Como evitar esse tipo de ataque?

A primeira coisa a corrigir é o SSRF. Aplicações que precisam realizar requisições para URLs fornecidas pelo usuário devem validar cuidadosamente os destinos permitidos. Não basta bloquear apenas 169.254.169.254, porque existem diferentes formas de representar ou alcançar destinos internos. Também é importante considerar redirects, resolução DNS, protocolos e portas permitidas. Na infraestrutura AWS, o ideal é exigir IMDSv2 e evitar que novas instâncias sejam criadas utilizando o modelo antigo quando ele não for necessário.

Depois vem a IAM: as Roles utilizadas pelas aplicações devem possuir o menor conjunto de permissões possível. Se uma aplicação não precisa acessar determinado bucket, ela não deveria conseguir acessá-lo.

Por último, existe o armazenamento. Backups são frequentemente tratados como arquivos "sem importância", mas podem conter exatamente o tipo de informação que um atacante procura: chaves privadas, tokens, arquivos .env, configurações e credenciais. No caso da Typhon, o backup armazenado no S3 foi justamente o que permitiu transformar acesso cloud em acesso SSH.

Conclusão

A exploração da Typhon é um bom exemplo de por que SSRF merece uma atenção especial em aplicações hospedadas na AWS. O endpoint vulnerável não fornecia diretamente uma shell, também não fornecia uma senha de administrador. O que ele fornecia era algo aparentemente mais simples: a capacidade de fazer o servidor realizar requisições, e isso foi suficiente para levar a exploração até uma identidade AWS real.

É justamente esse tipo de caminho que precisamos procurar durante uma avaliação de segurança em cloud. Quando encontrar um SSRF em uma aplicação hospedada na AWS, não pare em "consigo acessar o servidor internamente".

Quer ir além da teoria?

No Hacking Club você não só lê sobre vulnerabilidades como SSRF. Você explora, na prática, ambientes vulneráveis que simulam falhas reais encontradas em aplicações corporativas, APIs, infraestrutura cloud e muito mais.

Nossos cursos são construídos por quem vive segurança ofensiva no dia a dia — consultoria de verdade, não teoria de slide — com trilhas que vão do básico ao avançado em pentest, AppSec, red team e outras áreas da segurança ofensiva.

🎯 Explore os labs práticos e coloque em prática técnicas de exploração de aplicações, APIs e ambientes cloud.

📚 Cursos com trilhas estruturadas e certificações reconhecidas no mercado.

🔥 Comunidade ativa de hackers trocando conhecimento, compartilhando técnicas e aprendendo todos os dias.

Referências