feat: T1526 discovery (AWS and Azure) (#3023)
Co-authored-by: Bhavin Patel <bhavin.j.patel91@gmail.com>
This commit is contained in:
@@ -51,3 +51,98 @@ atomic_tests:
|
|||||||
cleanup_command: |
|
cleanup_command: |
|
||||||
remove-item #{output_directory} -recurse -force -erroraction silentlycontinue
|
remove-item #{output_directory} -recurse -force -erroraction silentlycontinue
|
||||||
name: powershell
|
name: powershell
|
||||||
|
- name: AWS - Enumerate common cloud services
|
||||||
|
description: |
|
||||||
|
Upon successful execution, this test will enumerate common resources that are contained within a valid AWS account.
|
||||||
|
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: ""
|
||||||
|
regions:
|
||||||
|
description: AWS regions
|
||||||
|
type: string
|
||||||
|
default: us-east-1,us-east-2,us-west-1,us-west-2
|
||||||
|
output_directory:
|
||||||
|
description: Directory to output results to
|
||||||
|
type: string
|
||||||
|
default: $env:TMPDIR/aws_discovery
|
||||||
|
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
|
||||||
|
executor:
|
||||||
|
command: |
|
||||||
|
Import-Module "PathToAtomicsFolder\T1526\src\AWSDiscovery.ps1"
|
||||||
|
$access_key = "#{access_key}"
|
||||||
|
$secret_key = "#{secret_key}"
|
||||||
|
$session_token = "#{session_token}"
|
||||||
|
$aws_profile = "#{profile}"
|
||||||
|
$regions = "#{regions}"
|
||||||
|
Set-AWSAuthentication -AccessKey $access_key -SecretKey $secret_key -SessionToken $session_token -AWSProfile $aws_profile
|
||||||
|
Get-AWSDiscoveryData -Regions $regions -OutputDirectory "#{output_directory}"
|
||||||
|
Remove-BlankFiles -OutputDirectory "#{output_directory}"
|
||||||
|
name: powershell
|
||||||
|
- name: Azure - Enumerate common cloud services
|
||||||
|
description: |
|
||||||
|
Upon successful execution, this test will enumerate common resources that are contained within a valid Azure subscription.
|
||||||
|
supported_platforms:
|
||||||
|
- iaas:azure
|
||||||
|
input_arguments:
|
||||||
|
client_id:
|
||||||
|
description: Azure AD client ID
|
||||||
|
type: string
|
||||||
|
default:
|
||||||
|
client_secret:
|
||||||
|
description: Azure AD client secret
|
||||||
|
type: string
|
||||||
|
default:
|
||||||
|
tenant_id:
|
||||||
|
description: Azure AD tenant ID
|
||||||
|
type: string
|
||||||
|
default:
|
||||||
|
cloud:
|
||||||
|
description: Azure cloud environment
|
||||||
|
type: string
|
||||||
|
default: AzureCloud
|
||||||
|
output_directory:
|
||||||
|
description: Directory to output results to
|
||||||
|
type: string
|
||||||
|
default: $env:TMPDIR/azure_discovery
|
||||||
|
dependency_executor_name: powershell
|
||||||
|
dependencies:
|
||||||
|
- description: |
|
||||||
|
The Az module must be installed.
|
||||||
|
prereq_command: |
|
||||||
|
try {if (Get-InstalledModule -Name Az -ErrorAction SilentlyContinue) {exit 0} else {exit 1}} catch {exit 1}
|
||||||
|
get_prereq_command: |
|
||||||
|
Install-Module -Name Az -Force
|
||||||
|
executor:
|
||||||
|
command: |
|
||||||
|
Import-Module "PathToAtomicsFolder\T1526\src\AzureDiscovery.ps1"
|
||||||
|
$client_id = "#{client_id}"
|
||||||
|
$client_secret = "#{client_secret}"
|
||||||
|
$tenant_id = "#{tenant_id}"
|
||||||
|
$environment = "#{cloud}"
|
||||||
|
Set-AzureAuthentication -ClientID $client_id -ClientSecret $client_secret -TenantID $tenant_id -Environment $environment
|
||||||
|
Get-AzureDiscoveryData -OutputDirectory "#{output_directory}" -Environment $environment
|
||||||
|
Remove-BlankFiles -OutputDirectory "#{output_directory}"
|
||||||
|
name: powershell
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
Import-Module AWSPowerShell
|
||||||
|
|
||||||
|
function Set-AWSAuthentication {
|
||||||
|
param (
|
||||||
|
[string]$AccessKey,
|
||||||
|
[string]$SecretKey,
|
||||||
|
[string]$SessionToken,
|
||||||
|
[string]$Regions,
|
||||||
|
[string]$AWSProfile
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($SessionToken -eq "" -and $AWSProfile -eq "") {
|
||||||
|
Set-AWSCredential -AccessKey $AccessKey -SecretKey $SecretKey -StoreAs "atomic"
|
||||||
|
}
|
||||||
|
elseif ($SessionToken -ne "" -and $AWSProfile -ne "") {
|
||||||
|
Set-AWSCredential -AccessKey $AccessKey -SecretKey $SecretKey -SessionToken $SessionToken -StoreAs "atomic"
|
||||||
|
}
|
||||||
|
elseif ($AWSProfile -ne "") {
|
||||||
|
Set-AWSCredential -ProfileName $AWSProfile -StoreAs "atomic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AWSDiscoveryData {
|
||||||
|
param(
|
||||||
|
[string]$OutputDirectory,
|
||||||
|
[string]$Regions
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not (Test-Path $OutputDirectory)) {
|
||||||
|
$null = New-Item -ItemType Directory -Path $OutputDirectory
|
||||||
|
}
|
||||||
|
# Account Discovery
|
||||||
|
"AccountID" | Out-File -FilePath $OutputDirectory/account.csv
|
||||||
|
Get-AWSAccountInfo | Out-File $OutputDirectory/account.csv -Append
|
||||||
|
# EC2 Discovery
|
||||||
|
"Name,Id,PublicIP,Size" | Out-File -FilePath $OutputDirectory/instances.csv
|
||||||
|
foreach ($region in $Regions.Split(",")) {
|
||||||
|
Get-EC2Discovery -Region $region | Out-File $OutputDirectory/instances.csv -Append
|
||||||
|
}
|
||||||
|
# S3 Bucket Discovery
|
||||||
|
"BucketName,CreationDate" | Out-File -FilePath $OutputDirectory/buckets.csv
|
||||||
|
Get-S3BucketDiscovery | Out-File $OutputDirectory/buckets.csv -Append
|
||||||
|
# IAM User Discovery
|
||||||
|
"UserName,CreateDate,PasswordLastUsed" | Out-File -FilePath $OutputDirectory/users.csv
|
||||||
|
Get-IAMUserDiscovery | Out-File $OutputDirectory/users.csv -Append
|
||||||
|
|
||||||
|
Write-Host "Discovery data saved to $OutputDirectory"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AWSAccountInfo {
|
||||||
|
$account = Get-STSCallerIdentity
|
||||||
|
$accountID = $account.Account
|
||||||
|
return $accountID
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-EC2Discovery {
|
||||||
|
param(
|
||||||
|
[string]$Region
|
||||||
|
)
|
||||||
|
Set-DefaultAWSRegion -Region $region
|
||||||
|
$instances = Get-EC2Instance | Select-Object -ExpandProperty Instances
|
||||||
|
$output = $null
|
||||||
|
foreach($instance in $instances) {
|
||||||
|
$instanceName = $instance.Tags | Where-Object { $_.Key -eq "Name" } | Select-Object -ExpandProperty Value
|
||||||
|
$instanceId = $instance.InstanceId
|
||||||
|
$instancePublicIp = $instance.PublicIpAddress
|
||||||
|
$instanceSize = $instance.InstanceType
|
||||||
|
$output += "$instanceName,$instanceId,$instancePublicIp,$instanceSize,$Region`n"
|
||||||
|
}
|
||||||
|
if ($null -ne $output) {
|
||||||
|
$output = $output.Substring(0, $output.Length - 1)
|
||||||
|
}
|
||||||
|
return $output
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-S3BucketDiscovery {
|
||||||
|
$buckets = Get-S3Bucket
|
||||||
|
foreach($bucket in $buckets) {
|
||||||
|
$bucketName = $bucket.BucketName
|
||||||
|
$creationDate = $bucket.CreationDate
|
||||||
|
$output += "$bucketName,$creationDate`n"
|
||||||
|
}
|
||||||
|
if ($null -ne $output) {
|
||||||
|
$output = $output.Substring(0, $output.Length - 1)
|
||||||
|
}
|
||||||
|
return $output
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-IAMUserDiscovery {
|
||||||
|
$users = Get-IAMUser
|
||||||
|
foreach($user in $users) {
|
||||||
|
$userName = $user.UserName
|
||||||
|
$createDate = $user.CreateDate
|
||||||
|
$passwordLastUsed = $user.PasswordLastUsed
|
||||||
|
$output += "$userName,$createDate,$passwordLastUsed`n"
|
||||||
|
}
|
||||||
|
if ($null -ne $output) {
|
||||||
|
$output = $output.Substring(0, $output.Length - 1)
|
||||||
|
}
|
||||||
|
return $output
|
||||||
|
}
|
||||||
|
|
||||||
|
function Remove-BlankFiles {
|
||||||
|
param (
|
||||||
|
[string]$OutputDirectory
|
||||||
|
)
|
||||||
|
$files = Get-ChildItem -Path $OutputDirectory
|
||||||
|
foreach ($file in $files) {
|
||||||
|
$lineCount = (Get-Content -Path $file.FullName).Count
|
||||||
|
if ($lineCount -eq 1) {
|
||||||
|
$null = Remove-Item -Path $file.FullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
function Set-AzureAuthentication {
|
||||||
|
param (
|
||||||
|
[string]$TenantID,
|
||||||
|
[string]$ClientID,
|
||||||
|
[string]$ClientSecret,
|
||||||
|
[string]$Environment
|
||||||
|
)
|
||||||
|
$SecurePassword = ConvertTo-SecureString -String $ClientSecret -AsPlainText -Force
|
||||||
|
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $ClientID, $SecurePassword
|
||||||
|
|
||||||
|
$null = Connect-AzAccount -ServicePrincipal -TenantId $TenantID -Credential $Credential -Environment $Environment -WarningAction:SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AzureDiscoveryData {
|
||||||
|
param(
|
||||||
|
[string]$Environment,
|
||||||
|
[string]$OutputDirectory
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not (Test-Path $OutputDirectory)) {
|
||||||
|
$null = New-Item -ItemType Directory -Path $OutputDirectory
|
||||||
|
}
|
||||||
|
# Subscription Discovery
|
||||||
|
"SubscriptionID" | Out-File -FilePath $OutputDirectory/subscriptions.csv
|
||||||
|
$subscriptions = Get-AzureSubscriptions
|
||||||
|
$subscriptions | Out-File $OutputDirectory/subscriptions.csv -Append
|
||||||
|
$subscriptions = $subscriptions -split "`n"
|
||||||
|
# VM Discovery
|
||||||
|
"Name,Id,PublicIP,Size" | Out-File -FilePath $OutputDirectory/vms.csv
|
||||||
|
Get-AzureVMDiscovery -Subscriptions $subscriptions | Out-File $OutputDirectory/vms.csv -Append
|
||||||
|
# Storage Account Discovery
|
||||||
|
"Name,ResourceGroup,Location" | Out-File -FilePath $OutputDirectory/storage.csv
|
||||||
|
Get-AzureStorageDiscovery -Subscriptions $subscriptions | Out-File $OutputDirectory/storage.csv -Append
|
||||||
|
# Key Vault Discovery
|
||||||
|
"Name,ResourceGroup,Location" | Out-File -FilePath $OutputDirectory/keyvaults.csv
|
||||||
|
Get-AzureKeyVaultDiscovery -Subscriptions $subscriptions | Out-File $OutputDirectory/keyvaults.csv -Append
|
||||||
|
|
||||||
|
Write-Host "Discovery data saved to $OutputDirectory"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AzureSubscriptions {
|
||||||
|
$subscriptions = Get-AzSubscription | Select-Object -ExpandProperty Id
|
||||||
|
foreach ($subscription in $subscriptions) {
|
||||||
|
$output += "$subscription`n"
|
||||||
|
}
|
||||||
|
if ($null -ne $output) {
|
||||||
|
$output = $output.Substring(0, $output.Length - 1)
|
||||||
|
}
|
||||||
|
return $output
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AzureVMDiscovery {
|
||||||
|
param (
|
||||||
|
[string[]]$Subscriptions
|
||||||
|
)
|
||||||
|
foreach ($subscription in $subscriptions) {
|
||||||
|
$null = Set-AzContext -Subscription $subscription
|
||||||
|
$vms = Get-AzVM
|
||||||
|
foreach ($vm in $vms) {
|
||||||
|
$vmName = $vm.Name
|
||||||
|
$vmId = $vm.Id
|
||||||
|
$nicId = ($vm | Select-Object -ExpandProperty NetworkProfile).NetworkInterfaces[0].Id
|
||||||
|
$pipId = (Get-AzNetworkInterface -ResourceId $nicId | Select-Object -ExpandProperty IpConfigurations | Select-Object -ExpandProperty PublicIpAddress).Id
|
||||||
|
$pipName = ($pipId -split "/")[-1]
|
||||||
|
$vmPublicIP = (Get-AzPublicIpAddress -Name $pipName).IpAddress
|
||||||
|
$vmSize = $vm.HardwareProfile.VmSize
|
||||||
|
$output += "$vmName,$vmId,$vmPublicIP,$vmSize`n"
|
||||||
|
}
|
||||||
|
if ($null -ne $output) {
|
||||||
|
$output = $output.Substring(0, $output.Length - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $output
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AzureStorageDiscovery {
|
||||||
|
param (
|
||||||
|
[string[]]$Subscriptions
|
||||||
|
)
|
||||||
|
foreach ($subscription in $subscriptions) {
|
||||||
|
$null = Set-AzContext -Subscription $subscription
|
||||||
|
$storageAccounts = Get-AzStorageAccount
|
||||||
|
foreach ($storageAccount in $storageAccounts) {
|
||||||
|
$storageAccountName = $storageAccount.StorageAccountName
|
||||||
|
$resourceGroup = $storageAccount.ResourceGroupName
|
||||||
|
$location = $storageAccount.Location
|
||||||
|
$output += "$storageAccountName,$resourceGroup,$location`n"
|
||||||
|
}
|
||||||
|
if ($null -ne $output) {
|
||||||
|
$output = $output.Substring(0, $output.Length - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $output
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AzureKeyVaultDiscovery {
|
||||||
|
param (
|
||||||
|
[string[]]$Subscriptions
|
||||||
|
)
|
||||||
|
foreach ($subscription in $subscriptions) {
|
||||||
|
$null = Set-AzContext -Subscription $subscription
|
||||||
|
$keyVaults = Get-AzKeyVault
|
||||||
|
foreach ($keyVault in $keyVaults) {
|
||||||
|
$keyVaultName = $keyVault.VaultName
|
||||||
|
$resourceGroup = $keyVault.ResourceGroupName
|
||||||
|
$location = $keyVault.Location
|
||||||
|
$output += "$keyVaultName,$resourceGroup,$location`n"
|
||||||
|
}
|
||||||
|
if ($null -ne $output) {
|
||||||
|
$output = $output.Substring(0, $output.Length - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $output
|
||||||
|
}
|
||||||
|
|
||||||
|
function Remove-BlankFiles {
|
||||||
|
param (
|
||||||
|
[string]$OutputDirectory
|
||||||
|
)
|
||||||
|
$files = Get-ChildItem -Path $OutputDirectory
|
||||||
|
foreach ($file in $files) {
|
||||||
|
$lineCount = (Get-Content -Path $file.FullName).Count
|
||||||
|
if ($lineCount -eq 1) {
|
||||||
|
$null = Remove-Item -Path $file.FullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user