New Technique: T1651 (#3031)
Co-authored-by: Carrie Roberts <clr2of8@gmail.com> Co-authored-by: Bhavin Patel <bhavin.j.patel91@gmail.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
attack_technique: T1651
|
||||
display_name: Cloud Administration Command
|
||||
atomic_tests:
|
||||
- name: AWS Run Command (and Control)
|
||||
description: |
|
||||
This test simulates an adversary using the AWS Run Command service to execute commands on EC2 instances.
|
||||
supported_platforms:
|
||||
- iaas:aws
|
||||
input_arguments:
|
||||
access_key:
|
||||
description: AWS Access Key
|
||||
type: string
|
||||
default: ""
|
||||
secret_key:
|
||||
description: AWS Secret Key
|
||||
type: string
|
||||
default: ""
|
||||
session_token:
|
||||
description: AWS Session Token
|
||||
type: string
|
||||
default: ""
|
||||
profile:
|
||||
description: AWS profile
|
||||
type: string
|
||||
default: ""
|
||||
region:
|
||||
description: AWS region to deploy the EC2 instance
|
||||
type: string
|
||||
default: us-east-2
|
||||
dependency_executor_name: powershell
|
||||
dependencies:
|
||||
- description: |
|
||||
The AWS PowerShell module must be installed.
|
||||
prereq_command: |
|
||||
try {if (Get-InstalledModule -Name AWSPowerShell -ErrorAction SilentlyContinue) {exit 0} else {exit 1}} catch {exit 1}
|
||||
get_prereq_command: |
|
||||
Install-Module -Name AWSPowerShell -Force
|
||||
- description: |
|
||||
Terraform must be installed.
|
||||
prereq_command: |
|
||||
terraform --version
|
||||
get_prereq_command: |
|
||||
Write-Host "Terraform is required. Download it from https://www.terraform.io/downloads.html"
|
||||
executor:
|
||||
command: |
|
||||
Import-Module "PathToAtomicsFolder/T1651/src/T1651-1/AWSSSMAttack.ps1" -Force
|
||||
$access_key = "#{access_key}"
|
||||
$secret_key = "#{secret_key}"
|
||||
$session_token = "#{session_token}"
|
||||
$aws_profile = "#{profile}"
|
||||
$region = "#{region}"
|
||||
Set-AWSAuthentication -AccessKey $access_key -SecretKey $secret_key -SessionToken $session_token -AWSProfile $aws_profile -AWSRegion $region
|
||||
Invoke-Terraform -TerraformCommand init -TerraformDirectory "PathToAtomicsFolder/T1651/src/T1651-1"
|
||||
Invoke-Terraform -TerraformCommand apply -TerraformDirectory "PathToAtomicsFolder/T1651/src/T1651-1" -TerraformVariables @("profile=T1651-1", "region=$region")
|
||||
Invoke-SSMAttack -AWSProfile "T1651-1" -TerraformDirectory "PathToAtomicsFolder/T1651/src/T1651-1"
|
||||
Invoke-Terraform -TerraformCommand destroy -TerraformDirectory "PathToAtomicsFolder/T1651/src/T1651-1" -TerraformVariables @("profile=T1651-1", "region=$region")
|
||||
name: powershell
|
||||
@@ -0,0 +1,126 @@
|
||||
Import-Module AWSPowerShell
|
||||
|
||||
function Set-AWSAuthentication {
|
||||
param (
|
||||
[string]$AccessKey,
|
||||
[string]$SecretKey,
|
||||
[string]$SessionToken,
|
||||
[string]$AWSProfile,
|
||||
[string]$AWSRegion
|
||||
)
|
||||
if ($SessionToken -eq "" -and $AWSProfile -eq "") {
|
||||
Set-AWSCredential -AccessKey $AccessKey -SecretKey $SecretKey -StoreAs "T1651-1"
|
||||
}
|
||||
elseif ($SessionToken -ne "" -and $AWSProfile -ne "") {
|
||||
Set-AWSCredential -AccessKey $AccessKey -SecretKey $SecretKey -SessionToken $SessionToken -StoreAs "T1651-1"
|
||||
}
|
||||
elseif ($AWSProfile -ne "") {
|
||||
Set-AWSCredential -ProfileName $AWSProfile -StoreAs "T1651-1"
|
||||
}
|
||||
|
||||
try {
|
||||
Get-STSCallerIdentity -ProfileName "T1651-1" | Out-Null
|
||||
}
|
||||
catch {
|
||||
Write-Host "ERROR: Failed to authenticate to AWS. Please check your credentials and try again."
|
||||
exit 1
|
||||
}
|
||||
Set-DefaultAWSRegion -Region $AWSRegion
|
||||
}
|
||||
|
||||
function Invoke-Terraform {
|
||||
param (
|
||||
[string]$TerraformCommand,
|
||||
[string]$TerraformDirectory,
|
||||
[string[]]$TerraformVariables
|
||||
)
|
||||
|
||||
$currentPath = Resolve-Path .
|
||||
|
||||
if (-not (Test-Path $TerraformDirectory)) {
|
||||
Write-Host "ERROR: Terraform directory not found. Please check the path and try again."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Get-ChildItem $TerraformDirectory -Filter "*.tf")) {
|
||||
Write-Host "ERROR: No Terraform files found in the directory. Please check the path and try again."
|
||||
exit 1
|
||||
}
|
||||
|
||||
foreach($variable in $TerraformVariables) {
|
||||
$varName = $variable.Split("=")[0]
|
||||
$varValue = $variable.Split("=")[1]
|
||||
[Environment]::SetEnvironmentVariable("TF_VAR_$varName", $varValue, "Process")
|
||||
}
|
||||
|
||||
Set-Location $TerraformDirectory
|
||||
|
||||
if ($TerraformCommand -eq "init") {
|
||||
try {
|
||||
terraform init | Out-Null
|
||||
}
|
||||
catch {
|
||||
Write-Host "ERROR: Failed to initialize Terraform. Please check the error message and try again."
|
||||
exit 1
|
||||
}
|
||||
} elseif ($TerraformCommand -eq "apply") {
|
||||
try {
|
||||
terraform apply -auto-approve | Out-Null
|
||||
}
|
||||
catch {
|
||||
Write-Host "ERROR: Failed to apply Terraform. Please check the error message and try again."
|
||||
exit 1
|
||||
}
|
||||
} elseif ($TerraformCommand -eq "destroy") {
|
||||
try {
|
||||
terraform destroy -auto-approve | Out-Null
|
||||
}
|
||||
catch {
|
||||
Write-Host "ERROR: Failed to destroy Terraform. Please check the error message and try again."
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Host "ERROR: Invalid Terraform command. Please use 'init', 'apply', or 'destroy'."
|
||||
exit 1
|
||||
}
|
||||
|
||||
Set-Location $currentPath
|
||||
}
|
||||
|
||||
function Invoke-SSMAttack {
|
||||
param (
|
||||
[string]$AWSProfile,
|
||||
[string]$TerraformDirectory
|
||||
)
|
||||
$currentPath = Resolve-Path .
|
||||
Set-Location $TerraformDirectory
|
||||
$instanceId = (terraform output -json | ConvertFrom-Json | Select-Object -ExpandProperty aws_ec2_instance_id).value
|
||||
Set-Location $currentPath
|
||||
foreach($i in 1..50) {
|
||||
$instanceStatus = (Get-SSMInstanceAssociationsStatus -InstanceId $instanceId -ProfileName $AWSProfile).Status
|
||||
if ($instanceStatus -eq "Success") {
|
||||
break
|
||||
}
|
||||
Start-Sleep -Seconds 6
|
||||
}
|
||||
$commandId = (Send-SSMCommand -DocumentName "AWS-RunShellScript" -Target @{Key="tag:AtomicTest";Values=@("T1651-1")} -Comment "Atomic Test T1651-1" -Parameters @{commands = @("cat /etc/shadow")}).CommandId
|
||||
foreach ($i in 1..50) {
|
||||
$commandStatus = (Get-SSMCommandInvocation -CommandId $commandId -ProfileName $AWSProfile).Status
|
||||
if ($commandStatus -eq "Success") {
|
||||
$instanceId = (Get-SSMCommandInvocation -CommandId $commandId)[0].InstanceId
|
||||
$output = (Get-SSMCommandInvocationDetail -CommandId $commandId -InstanceId $instanceId).StandardOutputContent
|
||||
break
|
||||
}
|
||||
elseif ($commandStatus -eq "Failed") {
|
||||
Write-Host "ERROR: Failed to execute the SSM command. Please check the error message and try again."
|
||||
exit 1
|
||||
}
|
||||
Start-Sleep -Seconds 6
|
||||
}
|
||||
if ($output -eq "") {
|
||||
Write-Host "ERROR: No output received from the SSM command. Please check the error message and try again."
|
||||
exit 1
|
||||
}
|
||||
Write-Host "SSM Command Output:"
|
||||
Write-Host $output
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
data "aws_ami" "ami" {
|
||||
most_recent = true
|
||||
|
||||
filter {
|
||||
name = "name"
|
||||
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
|
||||
}
|
||||
|
||||
filter {
|
||||
name = "virtualization-type"
|
||||
values = ["hvm"]
|
||||
}
|
||||
|
||||
owners = ["099720109477"]
|
||||
}
|
||||
|
||||
resource "aws_instance" "instance" {
|
||||
ami = data.aws_ami.ami.id
|
||||
instance_type = var.instance_type
|
||||
subnet_id = aws_subnet.subnet.id
|
||||
iam_instance_profile = aws_iam_instance_profile.profile.name
|
||||
vpc_security_group_ids = [aws_security_group.sg.id]
|
||||
user_data = <<EOF
|
||||
systemctl enable amazon-ssm-agent
|
||||
systemctl start amazon-ssm-agent
|
||||
EOF
|
||||
tags = {
|
||||
Name = "T1651-1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "= 5.82.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
profile = var.profile
|
||||
region = var.region
|
||||
|
||||
default_tags {
|
||||
tags = {
|
||||
AtomicTest = "T1651-1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
cloud = length(regexall("-gov-", var.region)) > 0 ? "aws-us-gov" : length(regexall("-cn-", var.region)) > 0 ? "aws-cn" : "aws"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
resource "aws_vpc" "vpc" {
|
||||
cidr_block = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
resource "aws_subnet" "subnet" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
cidr_block = "10.0.0.0/24"
|
||||
map_public_ip_on_launch = true
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "igw" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
resource "aws_route_table" "rt" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.igw.id
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "rta" {
|
||||
subnet_id = aws_subnet.subnet.id
|
||||
route_table_id = aws_route_table.rt.id
|
||||
}
|
||||
|
||||
resource "aws_security_group" "sg" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
output "aws_ec2_instance_id" {
|
||||
value = aws_instance.instance.id
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
data "aws_iam_policy" "ssm" {
|
||||
arn = "arn:${local.cloud}:iam::aws:policy/AmazonSSMManagedInstanceCore"
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "role" {
|
||||
name = "T1651-1-Role"
|
||||
assume_role_policy = jsonencode(
|
||||
{
|
||||
Version = "2012-10-17"
|
||||
Statement = [
|
||||
{
|
||||
Effect = "Allow"
|
||||
Principal = {
|
||||
Service = "ec2.amazonaws.com"
|
||||
}
|
||||
Action = "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy_attachment" "attachment" {
|
||||
role = aws_iam_role.role.name
|
||||
policy_arn = data.aws_iam_policy.ssm.arn
|
||||
}
|
||||
|
||||
resource "aws_iam_instance_profile" "profile" {
|
||||
name = "T1651-1-Profile"
|
||||
role = aws_iam_role.role.name
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
variable "profile" {
|
||||
description = "The AWS profile to use"
|
||||
default = "default"
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "The AWS region to deploy to"
|
||||
default = "us-east-2"
|
||||
}
|
||||
|
||||
variable "instance_type" {
|
||||
description = "The instance type to use for the EC2 instance"
|
||||
default = "t2.micro"
|
||||
}
|
||||
Reference in New Issue
Block a user