Como encontrar o ID da conta AWS de qualquer bucket S3
(tracebit.com)- A Tracebit reuniu uma técnica para inferir o AWS Account ID de buckets S3 públicos e privados, e recuperou
123456789101no bucket de exemplobucket-alpha - A pista central é a condição
s3:ResourceAccountna 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 usandoaws:userideRoleSessionName, isso cai para menos de 10 minutos - Essa técnica é possível porque
StringLikepermite correspondência parcial ems3: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íram123456789101
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:ResourceAccountdí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
StringLikee 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
curlpara o endpoint HTTP do bucket, mesmo que a requisição seja proibida, o cabeçalhox-amz-bucket-regioné retornado - No exemplo,
us-east-1foi identificado no cabeçalho de resposta debucket-alpha.s3.amazonaws.com
- Ao enviar
- 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:ResourceAccountcomeç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*"ems3:ResourceAccount
- Por exemplo, para verificar se o Account ID começa com
- 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 com0
- Ex.: se o evento aparece com a condição
- 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
- Por exemplo, colocando vários padrões na condição
- 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
- Mesmo com busca binária, isso pode levar cerca de
- Em um exemplo executado por várias horas, o Account ID de
bucket-alphafoi encontrado com sucesso como123456789101
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:ResourceAccounte uma condiçãoaws:userid
- A condição
aws:useridé usada para casar com o valorRoleSessionName, que pode ser definido livremente na chamada STSAssumeRole- Ao assumir um role com um
RoleSessionNameespecí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
- Ao assumir um role com um
- 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
- Ex.:
- 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
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
StringLikena 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
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
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.
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
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
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
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
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
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
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
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
Se não é segredo, nem sensível, nem confidencial, por que deve ser compartilhado com cuidado?
Os usuários podem ver de outra forma