Entenda o risco das políticas. Faça perguntas sobre políticas em linguagem natural. Solicite uma demonstração →

Published:

Quebrar as kill chains dos atacantes na AWS: IAM roles

by FireMon

Ao longo do último ano, observei um aumento enorme do interesse por orientações concretas sobre como lidar com incidentes de segurança dentro da cloud, com técnicas nativas da cloud. À medida que as organizações movem as suas cargas de trabalho de produção para a cloud, não demora muito até que os profissionais de segurança percebam que os fundamentos, embora conceptualmente semelhantes, são bastante diferentes na prática. Um desses conceitos centrais é o de kill chain, termo cunhado pela primeira vez pela Lockheed Martin para descrever o processo do atacante. Quebre qualquer elo e quebrará o ataque, pelo que este conceito se adequa bem à combinação de defesa em profundidade com as componentes ativas da resposta a incidentes.

Em implementações na cloud existem quatro grandes categorias de ataque, cada uma com kill chains diferentes:

  1. Ataques à própria plataforma de cloud. Ignorando um comprometimento fundamental do fornecedor de cloud (fora do controlo do cliente de cloud), estes ataques incidem normalmente sobre configurações incorretas de serviços de cloud. Se deixar um bucket S3 público, não colocar um autorizador num API Gateway ou expor as suas credenciais da AWS no GitHub, isso enquadra-se nesta categoria.
  2. Ataques a recursos e aplicações implementados pelo cliente na cloud. Estes ataques tradicionais não são diferentes dos executados contra o seu centro de dados. Exemplos comuns incluem a injeção de SQL numa aplicação web e servidores vulneráveis com as portas erradas abertas para a Internet. Tendem a ser um pouco mais limitados do que seriam contra um centro de dados, partindo do princípio de que utiliza contas/subscrições/projetos e VPCs ou redes virtuais para limitar o raio de impacto.
  3. Ataques aos seus administradores e programadores de cloud. Da próxima vez que realizar um teste de intrusão, certifique-se de que permite aos atacantes tentar fazer phishing aos seus programadores e administradores. Esta é uma das melhores formas de pivotar para a cloud, uma vez que muitas vezes é bastante mais fácil para um atacante obter acesso ao sistema de um programador do que quebrar a própria aplicação na cloud. Abordaremos este tema no futuro, mas por agora comecemos por dizer que “a MFA é minha amiga”.
  4. Ataques combinados. É nesta categoria que nos vamos focar hoje. Nestes ataques, o agente de ameaça invade algo implementado na cloud e usa-o depois para pivotar para o plano de gestão da cloud. (Há quem considere que os ataques a programadores são combinados, mas prefiro tratá-los separadamente).

Como regra geral, começo sempre por assumir que qualquer ataque bem-sucedido a qualquer nível pode escalar ou pivotar para um ataque combinado, momento a partir do qual a segurança do seu plano de gestão e a resposta a incidentes passam a ser as suas melhores defesas.

Hoje vou focar-me num dos processos de ataque combinado mais comuns e descrever uma combinação de controlos de deteção e de prevenção que ajudam a quebrar a kill chain. Antes de entrar nos detalhes, não tome este artigo como uma simplificação excessiva de um problema complexo. Gerir aquilo que vou descrever à escala é incrivelmente difícil, mesmo quando se sabe o que se está a fazer.

Nas próximas semanas iremos disponibilizar aos nossos clientes em acesso antecipado as primeiras Ops concebidas especificamente para estas questões, e deveremos tê-las em produção relativamente pouco tempo depois.

O ataque combinado na AWS: extração de credenciais de funções IAM

Num ataque combinado, o agente de ameaça invade algo mais tradicional e usa-o depois para pivotar para o plano de gestão da cloud. Há três formas principais de isto acontecer. Em cada caso, o atacante extrai credenciais estáticas armazenadas ou credenciais efémeras de funções IAM, que explicaremos daqui a pouco.

  1. Comprometimento direto de uma instância ou de um contentor. Por exemplo, se deixar a porta 22 aberta e o atacante conseguir invadir ou obter de outra forma acesso à shell.
  2. Server Side Request Forgery (SSRF). O atacante tira partido (normalmente) de uma vulnerabilidade de um servidor/serviço web e consegue executar comandos sem obter acesso à shell.
  3. Comprometimento de uma função Lambda. Embora não seja possível obter uma shell numa Lambda, estas continuam sujeitas a vulnerabilidades de execução de código e até à execução arbitrária de código se contiverem uma falha aplicacional. As implicações concretas podem assemelhar-se às de um SSRF.

Em todos os casos, o objetivo do atacante é obter credenciais para o plano de gestão da AWS e depois tirar partido dos privilégios existentes ou escalar privilégios. Abordaremos a escalada de privilégios num artigo futuro; por agora vamos focar-nos no que são essas credenciais e em como pode evitar o seu uso abusivo.

A maioria das pessoas compreende as credenciais estáticas; na AWS, são uma Access Key e uma Secret Key. São como um nome de utilizador e uma palavra-passe, mas são usadas para chamadas à API da AWS. A versão atual utiliza um processo criptográfico conhecido como Signature 4 para assinar pedidos HTTP quando efetua essas chamadas à API. Pode e deve tratá-las exatamente como um nome de utilizador e uma palavra-passe — e nunca as deve armazenar dentro de recursos de cloud, como instâncias e Lambdas.

As funções IAM são mais complicadas quando se começa a trabalhar com a AWS: são ao mesmo tempo excelentes e assustadoras. Uma IAM Role na AWS é, na prática, um contentor de permissões que utiliza numa sessão. As IAM Roles são ótimas porque não são credenciais propriamente ditas… quando assume a função, a AWS fornece um conjunto de credenciais para uma sessão limitada no tempo. As funções são algo que existe “apenas dentro da AWS”. Pode atribuí-las a recursos dentro da AWS (como uma instância ou uma função Lambda) e esse recurso passa a poder fazer chamadas à API sem credenciais estáticas armazenadas! Usamos funções para ligações de identidade federada, instâncias, funções Lambda e todos os outros serviços da AWS. As access keys servem realmente apenas para quando cria um utilizador numa conta AWS; para todo o resto usamos funções.

As funções têm quatro tipos de permissões associados:

  1. O que a função pode fazer dentro da AWS. São as próprias políticas de permissões que associa à função.
  2. Quem ou o que pode utilizar a função (a política de confiança). Criar uma função não significa que qualquer coisa ou qualquer pessoa a possa utilizar; esta política restringe o acesso, por exemplo, a instâncias AWS ou a uma função Lambda específica.
  3. Um limite de permissões para restringir o âmbito da função. É um pouco mais complexo e não é relevante para a discussão de hoje, pelo que o abordaremos mais tarde.
  4. Quando assume uma função para uma sessão, pode também especificar um subconjunto das suas permissões existentes para utilizar nessa sessão. É uma funcionalidade interessante para o princípio do menor privilégio, mas também não é totalmente relevante para a discussão de hoje.

Provavelmente é mais fácil explicar como isto funciona percorrendo o processo. Suponha que tenho uma aplicação que precisa de aceder a um bucket S3 ou a uma base de dados Dynamo. Crio uma função IAM para a instância e defino a política de confiança para que o serviço EC2 possa utilizar a função. Depois lanço uma instância e atribuo-lhe a função. A AWS executa a instância e faz com que esta assuma a função. Assumir a função abre uma sessão e atribui uma access key, uma secret key e um token de sessão. A AWS roda depois essas credenciais a cada 1-6 horas e a instância pode agora fazer as chamadas à API autorizadas pelas políticas de permissões.

Embora as credenciais não estejam na instância, as credenciais continuam acessíveis à instância. Qualquer código que corra no interior precisa de conhecer as credenciais para fazer as chamadas reais à API para aceder ao S3 e ao Dynamo, pelo que algo conhecido como o serviço de metadados as fornece a pedido. O serviço de metadados é algo especial na AWS para instâncias e contentores, que guarda toda a informação sobre a forma como estão configurados. É bastante importante que um servidor consiga obter o seu endereço IP, por exemplo.

É aqui que entra o ataque.

O serviço de metadados é simplesmente um url a que pode aceder e que devolve a informação pedida. curl 169.254.169.254/latest/meta-data/ devolve toda a informação básica e pode usar o caminho curl 169.254.169.254/latest/meta-data/iam-security-credentials/ que devolve a access key, a secret key e o token. (No caso de um ataque baseado em Lambda, tudo isto é diferente e usa-se código do SDK em vez de curl, mas aplicam-se os mesmos princípios).

O atacante pode depois copiar essas credenciais e utilizá-las noutro local, incorporando-as em ferramentas em vez de ter de carregar e executar código no servidor comprometido. Além disso, por ser baseado em URL, o serviço de metadados fica exposto a um leque mais alargado de ataques SSRF, uma vez que não é necessária a execução arbitrária de código completa. As credenciais acabam por expirar, mas, consoante o ataque, o atacante pode simplesmente voltar e obter um novo conjunto quando verificar que as atuais deixaram de funcionar.

Hoje em dia, os atacantes mais habilidosos utilizam as credenciais numa conta AWS que controlam, uma vez que a Amazon dispõe de ferramentas para detetar credenciais extraídas e utilizadas fora dos seus intervalos de endereços conhecidos.

Quebrar a kill chain de extração de IAM Role

Vamos mapear a kill chain. O atacante precisa fazer o seguinte:

  • Descobrir e explorar uma vulnerabilidade numa instância, contentor ou Lambda que lhe permita aceder às credenciais da role. Isto é quase sempre um erro do lado do cliente… como não aplicar patches, abrir as portas erradas ou implementar código vulnerável.
  • Extrair as credenciais atuais da role.
  • Executar com êxito as chamadas de API permitidas num ambiente sob o seu controlo.
  • Fazer algo prejudicial dentro do âmbito da política de permissões da IAM role permitida. Bem, provavelmente prejudicial, já que não é habitual os atacantes aplicarem patches ao seu código.

As técnicas seguintes podem quebrar diferentes elos da cadeia e incluem uma combinação de controlos de deteção e de prevenção. Não se sinta mal se isto parecer excessivo… muito, MUITO poucas das organizações com que trabalho implementam estas medidas de forma abrangente, sobretudo em escala.

6 técnicas para ajudar a quebrar diferentes elos da cadeia de ataque

  1. Gestão de vulnerabilidades
  2. Políticas de permissões IAM de privilégio mínimo com restrições de recursos
  3. Utilizar restrições condicionais de IP, VPC ou outra origem do pedido nas políticas de permissões
  4. Utilizar service endpoints com políticas + políticas de recursos
  5. Adicionar proxies de metadados com filtros de HTTP User Agent (proteção do serviço de metadados)
  6. Proteção contra utilização duplicada de roles

Gestão de vulnerabilidades

  • Complexidade: Moderada
  • Eficácia: Baixa
  • Escalabilidade: Difícil
  • Tipo: Deteção e prevenção

Sem surpresa, o ponto de partida deve ser eliminar todas as vulnerabilidades e configurações incorretas iniciais que o atacante pode utilizar para se movimentar lateralmente e obter credenciais. Classifiquei a complexidade apenas como moderada, uma vez que não há nada de novo ou específico da cloud nisto. Mas também classifico a eficácia como baixa, já que a gestão abrangente de vulnerabilidades não impediu as legiões de violações ocorridas nas últimas décadas. Simples no conceito, incrivelmente complexo em escala.

Políticas de permissões IAM de privilégio mínimo com restrições de recursos

  • Complexidade: Moderada
  • Eficácia: Elevada
  • Escalabilidade: Moderada a difícil
  • Tipo: Prevenção

As políticas IAM na AWS são de negação por predefinição e incluem declarações explícitas de permissão e de negação. Por exemplo, pode escrever uma política que apenas permita a leitura de um bucket S3. Incluem também restrições de recursos, pelo que, onde a declaração de permissão autoriza a role a chamar a API de leitura, a restrição de recursos apenas permite que a role leia buckets ou objetos específicos. Deve SEMPRE começar as suas defesas por aqui. Quando realizo avaliações, encontro, em praticamente todos os projetos, políticas IAM que permitem demasiados privilégios (as chamadas de API) e poucas restrições de recursos. Sim, esse serviço pode precisar de acesso a uma base de dados Dynamo, mas precisa de acesso a todas as tabelas? Este controlo em particular não é difícil de implementar em pequena escala, mas quanto maior for a organização, e quantas mais pessoas tomarem estas decisões de política, mais difícil é ser consistente em escala. É também importante acrescentar declarações explícitas de negação, caso alguém adicione uma nova política com novas permissões à role. As permissões são cumulativas, mas quaisquer declarações de negação prevalecem sobre as de permissão.

Utilizar restrições condicionais de IP, VPC ou outra origem do pedido nas políticas de permissões

  • Complexidade: Elevada
  • Eficácia: Moderada a elevada
  • Escalabilidade: Difícil
  • Tipo: Prevenção

As políticas IAM suportam declarações condicionais que abrangem várias opções, incluindo o endereço IP ou a VPC de origem. Se souber que uma determinada role só deve fazer chamadas de API a partir de um recurso específico da sua stack aplicacional, pode restringir a autorização a esse endereço IP ou sub-rede exatos. Se o atacante roubar as credenciais e tentar utilizá-las noutro local, as chamadas de API falharão. Esta é uma marreta de precisão guiada - fácil no conceito e difícil na execução, uma vez que pode encontrar outras complexidades a interferir com uma implementação adequada. Por exemplo, as chamadas de API para serviços AWS ou vão diretamente para a Internet, ou passam por um NAT Gateway, ou são encaminhadas internamente através de um Service Endpoint (que abordaremos daqui a pouco). O endereço IP detetado dependerá da rota da chamada de API para a Internet. Tudo isto é gerível e detetável (e automatizável), mas convém informar-se primeiro para garantir que compreende as permutações.

Consulte a primeira parte deste artigo da Netflix para ver alguns exemplos.

A menos que execute a sua função Lambda numa VPC, esta não será uma opção para proteger uma função comprometida.

Utilizar service endpoints com políticas + políticas de recursos

  • Complexidade: Moderada
  • Eficácia: Moderada a elevada
  • Escalabilidade: Moderada
  • Tipo: Prevenção

Na AWS, um service endpoint é como uma derivação na rede que capta o tráfego que normalmente iria pela Internet até um serviço AWS e o reencaminha internamente. Foram originalmente criados para permitir que sub-redes totalmente privadas na AWS, sem qualquer forma de alcançar a Internet, pudessem ainda assim aceder a determinados serviços AWS. Os endpoints suportam políticas que pode utilizar para restringir acessos e ações de formas muito semelhantes às políticas IAM. Neste caso, acrescenta restrições à política do endpoint para apenas permitir o acesso a recursos específicos por detrás desse endpoint (o S3 é o exemplo mais comum). Especifica quais os buckets permitidos, e nenhum outro recurso nessa sub-rede tem acesso a esse serviço. Encare isto como uma rede de segurança para a política IAM: com um service endpoint a utilizar uma política restritiva, mesmo que alguém acidentalmente (ou deliberadamente) conceda à role um acesso mais amplo do que deveria, continua a não conseguir aceder a nada que não seja permitido na política do service endpoint. Isto significa que passamos a ter três camadas de políticas, todas elas tendo de permitir o acesso ao recurso:

  • A política de permissões IAM que concede à role acesso ao recurso.
  • A política do service endpoint que permite o acesso aos recursos quando os pedidos passam pelo endpoint, independentemente das permissões da role utilizada.
  • A política do bucket ou do recurso (isto depende do tipo de recurso), que pode restringir o acesso apenas aos endereços IP aprovados.

A menos que execute a sua função Lambda numa VPC, também aqui esta não será uma opção para proteger uma função comprometida.

Adicionar proxies de metadados com filtros de HTTP User Agent (proteção do serviço de metadados)

  • Complexidade: Elevada
  • Eficácia: Moderada
  • Escalabilidade: Difícil
  • Tipo: Prevenção

Todos estes controlos pressupõem que um atacante consegue roubar as credenciais da role, mas e se houvesse forma de reduzir a sua capacidade de obter essas credenciais, mesmo que comprometa a instância ou o contentor autorizados? (Esta técnica não funciona com funções Lambda.) Uma opção emergente é restringir, à partida, o acesso ao serviço de metadados. Houve algumas tentativas de o fazer com IPTables, o que também poderia comprometer funcionalidades necessárias ao código que está a executar na instância. Em novembro de 2018, a AWS e a Netflix trabalharam em conjunto e começaram a acrescentar dados de utilizador aos cabeçalhos HTTP das chamadas de API feitas a partir dos SDKs da AWS. Trata-se de uma defesa contra SSRF, uma vez que a maioria dos ataques SSRF depende de enganar uma aplicação para que faça pedidos HTTP em nome do atacante, mas esses pedidos vêm normalmente de uma ferramenta de linha de comandos como o curl ou de outro processo e não terão o cabeçalho de dados de utilizador proveniente dos SDKs da AWS. Para que isto funcione, é necessário inserir um proxy para esses pedidos. Existem algumas opções open source para instâncias e contentores, incluindo proxies que correm na própria instância, em vez de exigirem que encaminhe o tráfego para um appliance virtual ou um proxy squid.

Esta técnica não funcionará se o atacante comprometer a instância anfitriã e executar uma shell, uma vez que pode desativar o Roxy ou sequestrar o processo aprovado.

Pode ler tudo sobre o assunto nos detalhes deste artigo da Netflix.

Proteção contra utilização duplicada de roles

  • Complexidade: Elevada
  • Eficácia: Elevada
  • Escalabilidade: Elevada
  • Tipo: Deteção

Esta é mais uma que vem da equipa da Netflix. Eles publicaram um guia com uma excelente técnica para detetar quando uma IAM role está a ser utilizada num local não autorizado, mesmo dentro da AWS. Recomendo vivamente a leitura do artigo ligado, mas, em resumo, combinam registos do CloudTrail com outras ferramentas para manter uma tabela com a informação de que instâncias estão a utilizar que roles a partir de que endereços IP. Depois monitorizam outras chamadas de API para descobrir quando uma role está a ser reutilizada a partir de um novo endereço IP ao mesmo tempo que está em uso a partir de um endereço aprovado. Com este método não precisa de conhecer todos os endereços IP em utilização em toda a organização; constrói dinamicamente uma tabela do que está em uso e deteta quando essa role está a ser utilizada noutro local em simultâneo. Isto é extremamente escalável, uma vez que pode executar a lógica de forma centralizada se centralizar o CloudTrail, o que já é, de qualquer modo, uma boa prática comum.

Resumo

Este é mais um artigo extenso, e não esperamos que todos consigam implementar cada uma destas opções em todas as implementações. Para simplificar, vejamos a kill chain de abuso de IAM Role:

  • Descobrir e explorar uma vulnerabilidade numa instância, contentor ou Lambda que lhe permita aceder às credenciais da role. Isto é quase sempre um erro do lado do cliente… como não aplicar patches, abrir as portas erradas ou implementar código vulnerável.
    • A gestão de vulnerabilidades (incluindo ferramentas como SASST e DAST para aplicações) e a avaliação da sua configuração de cloud (com ferramentas como o DisruptOps ou ferramentas open source como o Prowler e o CloudMapper) são a sua primeira defesa.
  • Extrair as credenciais atuais da role.
    • Proteção do serviço de metadados e gestão de vulnerabilidades
  • Executar com êxito as chamadas de API permitidas num ambiente sob o seu controlo.
    • Deteção de utilização duplicada de roles, utilizar restrições condicionais de IP, VPC ou outra origem do pedido nas políticas de permissões, utilizar service endpoints com políticas + políticas de recursos
  • Fazer algo prejudicial dentro do âmbito da política de permissões da IAM role permitida. Bem, provavelmente prejudicial, já que não é habitual os atacantes aplicarem patches ao seu código.
    • Políticas de permissões IAM de privilégio mínimo com restrições de recursos

Esperamos que isto lhe dê uma ideia mais clara de como reduzir o sucesso deste tipo de ataques.

Travar as kill chains dos atacantes no IAM da AWS | FireMon