diff --git a/atomics/T1526/T1526.yaml b/atomics/T1526/T1526.yaml index 856a81d8..068ad16a 100644 --- a/atomics/T1526/T1526.yaml +++ b/atomics/T1526/T1526.yaml @@ -51,3 +51,98 @@ atomic_tests: cleanup_command: | remove-item #{output_directory} -recurse -force -erroraction silentlycontinue 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 diff --git a/atomics/T1526/src/AWSDiscovery.ps1 b/atomics/T1526/src/AWSDiscovery.ps1 new file mode 100644 index 00000000..c22b6f88 --- /dev/null +++ b/atomics/T1526/src/AWSDiscovery.ps1 @@ -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 + } + } +} diff --git a/atomics/T1526/src/AzureDiscovery.ps1 b/atomics/T1526/src/AzureDiscovery.ps1 new file mode 100644 index 00000000..4eda6c12 --- /dev/null +++ b/atomics/T1526/src/AzureDiscovery.ps1 @@ -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 + } + } +}