2 pontos por GN⁺ 2024-02-27 | 1 comentários | Compartilhar no WhatsApp
  • A Tracebit reuniu uma técnica para inferir o AWS Account ID de buckets S3 públicos e privados, e recuperou 123456789101 no bucket de exemplo bucket-alpha
  • A pista central é a condição s3:ResourceAccount na política de Interface VPC Endpoint do S3 e se a requisição aparece nos próprios logs do CloudTrail
  • Em buckets privados, mesmo que a resposta final continue sendo AccessDenied, só as requisições que passaram pela política do VPC Endpoint aparecem no CloudTrail, o que permite verificar se um padrão numérico corresponde
  • Por causa da propagação da política e da latência do CloudTrail, uma busca simples pode levar cerca de 40 * 12 minutos = 8 horas, mas com um teste paralelo de 120 instruções de política usando aws:userid e RoleSessionName, isso cai para menos de 10 minutos
  • Essa técnica é possível porque StringLike permite correspondência parcial em s3:ResourceAccount, e algumas atividades também podem aparecer no CloudTrail do proprietário do bucket

Expansão a partir da técnica para buckets públicos

  • Em 2021, Ben Bridts publicou como encontrar o AWS Account ID de qualquer bucket S3 público
  • A abordagem da Tracebit reutiliza vários elementos dessa ideia, mas foca em descobrir o Account ID de buckets S3 incluindo buckets privados
  • Na execução de exemplo, para bucket-alpha, eles reuniram os nomes de sessão que passaram no CloudTrail e no fim reconstruíram 123456789101

Por que o método existente para buckets públicos funciona

  • O método de Ben Bridts funciona porque três condições se combinam
    • É possível aplicar uma política IAM à requisição
    • É possível inferir se a política permitiu ou bloqueou a requisição
    • É possível aplicar correspondência com curingas à chave de condição s3:ResourceAccount
  • Em buckets públicos, se a política bloquear a requisição, retorna AccessDenied; se a política permitir, a requisição é bem-sucedida, então fica fácil distinguir se a política foi satisfeita
  • Ao restringir s3:ResourceAccount dígito por dígito, o espaço total de busca cai de trilhões para algumas centenas de possibilidades

Em buckets privados, observar o CloudTrail em vez da resposta

  • Em buckets privados, independentemente da política aplicada, a resposta final vira AccessDenied por causa da política do bucket de destino
  • A técnica da Tracebit usa como critério não o resultado da resposta, mas se a requisição aparece nos próprios logs do CloudTrail
    • Se a requisição aparece no CloudTrail, a política do VPC Endpoint permitiu a requisição, e depois ela foi negada pela política do bucket
    • Se a requisição não aparece no CloudTrail, ela foi bloqueada pela política do VPC Endpoint
  • Ao criar um Interface VPC Endpoint para S3, é possível aplicar uma política de VPC Endpoint à requisição, e essa política é avaliada junto com outras, como a política do bucket e a política IAM do principal que fez a requisição
  • A política do VPC Endpoint também permite curingas StringLike e chaves de condição de recurso, o que viabiliza o mesmo método de exploração

Procedimento básico: da confirmação da região à consulta dos eventos

  • Primeiro, é preciso descobrir a região do bucket de destino
    • Ao enviar curl para o endpoint HTTP do bucket, mesmo que a requisição seja proibida, o cabeçalho x-amz-bucket-region é retornado
    • No exemplo, us-east-1 foi identificado no cabeçalho de resposta de bucket-alpha.s3.amazonaws.com
  • Implanta-se uma VPC e um VPC Endpoint do S3 na mesma região do bucket de destino
    • O VPC Endpoint deve ser do tipo Interface, pois é esse tipo que permite aplicar política
    • Como esse VPC Endpoint afeta as requisições S3 da VPC, é recomendável criar uma VPC dedicada para esse objetivo
  • Para enviar requisições S3 de dentro da VPC, inicia-se uma instância EC2 e confirma-se que ela está usando o VPC Endpoint do S3
  • A política do VPC Endpoint é alterada para testar se s3:ResourceAccount começa com um número específico
    • Por exemplo, para verificar se o Account ID começa com 0, usa-se a condição "0*" em s3:ResourceAccount
  • Da instância EC2, envia-se ao bucket de destino uma requisição de Management como GetBucketAcl
    • Usar uma requisição de Management reduz a necessidade de tratamento separado na configuração do CloudTrail
    • O resultado da requisição é AccessDenied, como esperado

Como o CloudTrail identifica o padrão numérico

  • Depois da requisição, consulta-se no CloudTrail se apareceu um evento GetBucketAcl
  • Se o evento aparece, a política do VPC Endpoint permitiu a requisição, então o Account ID corresponde ao padrão testado
    • Ex.: se o evento aparece com a condição "0*", o Account ID começa com 0
  • Se o evento não aparece, a política do VPC Endpoint bloqueou a requisição, então ele não corresponde àquele padrão
  • Como pode levar alguns minutos para um evento aparecer no CloudTrail, é recomendável esperar 10 minutos antes de concluir que ele não existe
  • Alterações na política do VPC Endpoint também levam tempo para se propagar e entrar totalmente em vigor; esperar 5 minutos após a mudança da política funciona bem

Automatizado, mas o método básico ainda é lento

  • A Tracebit escreveu um script para automatizar esse processo e encontrar com confiabilidade o Account ID do bucket
  • Em vez de testar todos os dígitos um a um, a cada posição eles reduziram o número de testes com uma abordagem próxima de busca binária
    • Por exemplo, colocando vários padrões na condição s3:ResourceAccount, como ["0*", "1*", "2*", "3*", "4*"], para dividir o intervalo
  • Ainda assim, o gargalo continua sendo o tempo de espera pela aplicação da política e pela verificação no CloudTrail
    • Mesmo com busca binária, isso pode levar cerca de 40 * 12 minutos = 8 horas
  • Em um exemplo executado por várias horas, o Account ID de bucket-alpha foi encontrado com sucesso como 123456789101

Menos de 10 minutos com 120 instruções de política

  • Um método mais rápido é colocar antecipadamente na política do VPC Endpoint todas as combinações possíveis de posição e dígito
  • A política contém ao todo 120 instruções
    • São testados os 10 dígitos possíveis para cada posição do AWS Account ID
    • Cada instrução usa em conjunto um padrão de posição específico em s3:ResourceAccount e uma condição aws:userid
  • A condição aws:userid é usada para casar com o valor RoleSessionName, que pode ser definido livremente na chamada STS AssumeRole
    • Ao assumir um role com um RoleSessionName específico, é possível fazer com que apenas a instrução de política correspondente a um teste específico de posição e dígito seja satisfeita
  • Essa política quase encosta no limite máximo de tamanho em caracteres da política do VPC Endpoint
  • Como todas as 120 possibilidades são testadas em paralelo, deixa de ser necessário alterar a política a cada vez ou esperar individualmente pelos resultados do CloudTrail
  • Com isso, o tempo para descobrir o Account ID cai para menos de 10 minutos

Alcance da exposição e possibilidades de uso

  • Algumas atividades podem aparecer nos logs do CloudTrail do proprietário do bucket de destino
  • A Tracebit consultou a equipe de segurança da AWS antes da divulgação
  • Já houve muita discussão sobre o quanto um AWS Account ID é uma informação sensível, e no evento de exemplo do CloudTrail o Account ID de terceiros aparece mascarado como HIDDEN_DUE_TO_SECURITY_REASONS
  • A mesma técnica pode ser aplicada a outras chaves de condição de recurso relacionadas ao bucket
    • Ex.: aws:ResourceOrgID
    • Ex.: aws:ResourceOrgPaths
    • Ex.: aws:ResourceTag
  • Ela também pode ser adaptada para outros serviços além do S3 onde esse método seja aplicável
  • Se forem criadas VPCs e VPC Endpoints com peering mútuo em todas as regiões, pode ser possível montar uma configuração que funcione independentemente da região do bucket de destino
  • Essa técnica é possível porque é permitido usar correspondência parcial StringLike na condição s3:ResourceAccount
  • Pode ser útil se até mesmo eventos negados pela política do VPC Endpoint forem registrados no CloudTrail

1 comentários

 
GN⁺ 2024-02-27
Comentários do Hacker News
  • É realmente estranho que seja possível aplicar correspondência com curingas à chave de condição s3:ResourceAccount
    Não parece haver nenhum motivo legítimo para permitir ou negar permissões com base em correspondência parcial do ID da conta

    • Parece que é porque a execução de políticas da AWS tem vários operadores e operandos e, neste caso, a estrutura usa StringLike na string do ID da conta
      É meio interessante ver a área de DevOps agora descobrindo ataques de canal lateral. Os canais laterais de execução especulativa de CPU, como Meltdown e Spectre, também causaram grande repercussão quando foram descobertos; antes disso, já havia áreas como análise de consumo de energia, detecção de distorção magnética e criptografia em tempo constante
      https://en.m.wikipedia.org/wiki/Side-channel_attack
      https://en.m.wikipedia.org/wiki/Power_analysis
    • Eu também achei essa parte surpreendente. Parece que esse campo não deveria permitir nada além de correspondência exata, e não consigo pensar em um caso de uso para correspondência por padrão em IDs de conta
    • Talvez venha de uma tendência à generalização
      Em um side project recente, criei um recurso para escrever consultas em um formato inspirado em OWL, e há uma biblioteca de operadores relacionais para coisas como extrair o host de uma URL, fazer consultas por prefixo, consultas like, consultas com regex etc.
      Como era um side project dentro de outro side project meu, fiz do jeito mais fácil e deixei os operadores sempre disponíveis, mesmo em casos que não fazem sentido. Não sei nem me importo com o que acontece se você fizer uma consulta regex em números. Pode haver algo parecido internamente na AWS, mas, para um sistema com muitos usuários e sensível a segurança, o padrão deveria ser outro
    • É parecido com fazer correspondência de bitfields de IDs de grupo em sistemas Unix
      Alguém pode ter tido essa ideia e achado que era inteligente, mas implementá-la em um sistema que você não controla 100% parece tolice
  • Em geral, você não sairia distribuindo publicamente o ID da conta, mas é preciso assumir que alguma parte dele será exposta em algum momento
    Cada vez mais fornecedores terceirizados e plataformas SaaS estão migrando para integrações que preferem delegação de função em vez de usuários IAM e chaves de acesso, e isso é o correto. Com isso, pelo menos o ID da conta usada como ponto de integração fica conhecido por outras partes, e elas também têm dependências, vulnerabilidades etc.

    • Fico curioso sobre isso. O que um atacante pode fazer com um ID de conta AWS? Em que isso difere de saber o endereço de e-mail de alguém?
  • IDs de conta AWS são como endereços IP. Podem ser sensíveis, mas alguém precisa conhecê-los para o trabalho acontecer
    Por exemplo, um ou dois anos atrás tivemos um terceiro com o qual precisávamos integrar por causa de procedimentos de prevenção à lavagem de dinheiro. Dissemos que deveríamos configurar PrivateLink com aquela organização, já que isso normalmente é mais seguro do que uma porta SFTP pública, mas a empresa recusou por motivos de segurança, dizendo que precisava ocultar o ID da conta. Isso apesar de ele ser necessário no ARN da função do endpoint PV para permissões mútuas
    No fim, colocamos na allowlist a faixa de IPs públicos que eles usavam na porta 22 de entrada
    A lição é que você pode ofuscar o ID e se achar esperto, mas fica difícil operar um negócio se a outra parte não souber o endereço para responder

    • AWS PrivateLink tem mais uma característica que geralmente o torna indesejável para esse tipo de integração. A comunicação é bidirecional, e as sub-redes IP não podem se sobrepor
      Do ponto de vista de fornecedor, normalmente integramos usando VPC Endpoint Service. Nesse modelo, a comunicação é unidirecional, e nosso serviço é exposto como um endpoint de load balancer dentro da VPC do cliente
  • Para quem tiver interesse, coloquei o código aqui: https://github.com/tracebit-com/find-s3-account

  • É uma descoberta interessante, sem dúvida, mas pelo título achei que haveria um método mais direto
    Seria bom poder, como conta administradora na AWS, simplesmente perguntar dentro da organização “onde está o recurso X” e descobrir rapidamente em qual conta está um determinado bucket S3. Isso vale para outros recursos também, mas S3 buckets é um caso especialmente grande
    Sinceramente, esse é um problema que surge principalmente com buckets legados, anteriores a práticas melhores, ou com coisas que existiam antes de todos os buckets serem definidos como código. Ainda assim, quando se tem muitas contas AWS, encontrar recursos em contas e regiões desconhecidas pode ficar entediante

    • Se você configurar um agregador do AWS Config para a organização, poderá consultar o inventário de recursos de todas as contas da organização com SQL no Athena
      Assim, descobrir qual conta possui um recurso é algo como select accountId where arn = "x"
  • Outros recursos AWS públicos com namespace global também revelam o ID da conta AWS
    https://blog.plerion.com/conditional-love-for-aws-metadata-e...

  • Um pouco relacionado: Cloudflare account_id e zone_id são seguros para serem públicos
    https://github.com/cloudflare/cloudflare-docs/issues/474
    https://community.cloudflare.com/t/api-zone-id/355566

    The Zone ID and Account ID are not sensitive. Sensitive data like account API Key, Secrets etc. can all be revoked, rotated or changed. See the comment 36 below on the Wrangler repo: as per our security team, it’s completely Fine to have your zone_id and account_id public, the Global API key and associated email address should be kept secret.

    • O ID da conta AWS também é seguro para ser público
      Porém, uma das coisas que dá para fazer com isso é identificar correlações. Se você opera vários sites S3 na mesma conta AWS, as pessoas podem ver que eles são hospedados pela mesma conta. Se isso é importante ou não depende do seu modelo de ameaça
    • Em contas CF, uso o recurso de + do Gmail para criar um endereço de e-mail totalmente único e difícil de adivinhar
      Não é perfeito, mas acrescenta mais uma camada de abstração
  • Relacionado a isso, mesmo que o AWS Key ID não seja a parte da chave secreta, ele contém dentro dele o ID da conta em uma forma deslocada em um bit
    https://medium.com/@TalBeerySec/a-short-note-on-aws-key-id-f...
    Esse Key ID é incluído nas URLs pré-assinadas do S3, então é bem provável que você já estivesse expondo o ID da conta

    • Parece que bastante gente nesta thread assume que o AWS Key ID faz parte de segurança por obscuridade ou de defesa em profundidade
      Provavelmente vou receber downvotes, mas, se ainda assim você estiver lendo, este é um exemplo de por que segurança por obscuridade não é uma boa defesa. Você vai deixar passar alguma coisa; um atacante persistente não vai
      Segurança que não depende de obscuridade vale independentemente de eu ter entendido tudo ou não, a menos que o atacante contrate, por exemplo, um gênio capaz de simplesmente quebrar AES-256: https://www.youtube.com/watch?v=KEkrWRHCDQU
  • Por que isso pode ser importante? Como exemplo claro, dado um bucket de produção, agora fica possível encontrar buckets de desenvolvimento da mesma organização. Pessoalmente, esse não é um comportamento que eu esperaria

    • Isso só é verdade se você usar a mesma conta para produção e desenvolvimento. É mais um motivo para não usar a mesma conta
    • Para fazer isso, basta ter o nome do bucket
      Para impedir esse tipo de tentativa de enumeração, é preciso colocar no nome do bucket um prefixo ou sufixo gerado aleatoriamente. Além disso, não como substituição, mas como medida adicional, também é uma boa prática expor os objetos do bucket por um nome que não seja o hostname padrão, para que o próprio nome do bucket não vaze
    • Como isso acontece? Primeiro não seria preciso saber o nome do bucket de desenvolvimento?
    • A possibilidade é baixa, a menos que o bucket de desenvolvimento de alguma forma esteja na mesma conta
  • While account IDs, like any identifying information, should be used and shared carefully, they are not considered secret, sensitive, or confidential information.
    https://docs.aws.amazon.com/accounts/latest/reference/manage...

    • Pelo menos no mundo digital, parece que a informação é tratada como uma de duas coisas: pública ou privada. Não há uma noção muito boa de informações que exigem permissão ou informações protegidas
      Por exemplo, meu endereço residencial é tecnicamente uma informação pública, mas eu jamais gostaria que ele fosse colocado em um outdoor ao lado de uma rodovia, junto com fotos da minha família, dizendo onde eu moro. Eu o forneço apenas a quem precisa, e acredito e espero que, em geral, ele seja mantido quase como confidencial ou tenha uso limitado
    • O que isso quer dizer?
      Se não é segredo, nem sensível, nem confidencial, por que deve ser compartilhado com cuidado?
    • Acho que “não é considerado informação secreta, sensível ou confidencial” deveria vir com “pelos nossos critérios
      Os usuários podem ver de outra forma