diff --git a/PowerHuntShares.psm1 b/PowerHuntShares.psm1 index 5a04c37..567c54d 100644 --- a/PowerHuntShares.psm1 +++ b/PowerHuntShares.psm1 @@ -4,7 +4,7 @@ #-------------------------------------- # Author: Scott Sutherland, 2024 NetSPI # License: 3-clause BSD -# Version: v1.128 +# Version: v1.129 # References: This script includes custom code and code taken and modified from the open source projects PowerView, Invoke-Ping, and Invoke-Parrell. function Invoke-HuntSMBShares { @@ -1497,7 +1497,7 @@ function Invoke-HuntSMBShares $FileNamePatternsAll.Columns.Add("Description") | Out-Null # Summary of keyword. $FileNamePatternsAll.Columns.Add("Instructions") | Out-Null # Used to instruct testing how to attack match. $FileNamePatternsAll.Columns.Add("Category") | Out-Null # File name category: Secret (password), sensitive (data), binaries, script, backup, database - $FileNamePatternsAll.Columns.Add("SampleRegex") | Out-Null # Used to parse sample data from file matches. + $FileNamePatternsAll.Columns.Add("ParserFunction") | Out-Null # Used to parse sample data from file matches. # Add rows to data table - Sensitive data $FileNamePatternsAll.Rows.Add("*credit*","Credit card number and/or PII.","None.","Sensitive","") | Out-Null @@ -1518,72 +1518,83 @@ function Invoke-HuntSMBShares $FileNamePatternsAll.Rows.Add("*tripwire*","This is a vulnerability scanner.","None.","Sensitive","") | Out-Null # Add rows to data table - Files containing passwords - $FileNamePatternsAll.Rows.Add("Bootstrap.ini*","Used for Windows Deployment services (WDS) PXE installation and may contain credentials.","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("Bootstrap.ini*","Used for Windows Deployment services (WDS) PXE installation and may contain credentials.","None.","Secret","Get-PwBootstrapConfig") | Out-Null $FileNamePatternsAll.Rows.Add("*.bcd","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("context.xml*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("db2cli.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*app.confg*","","None.","Secret","Get-PwAppconfig") | Out-Null + $FileNamePatternsAll.Rows.Add("context.xml*","","None.","Secret","Get-PwContextXML") | Out-Null + $FileNamePatternsAll.Rows.Add("db2cli.ini*","","None.","Secret","Get-PwDbxDriverIni") | Out-Null + $FileNamePatternsAll.Rows.Add("dbxdrivers.ini*","","None.","Secret","Get-PwDbxDriverIni") | Out-Null + $FileNamePatternsAll.Rows.Add("pureftpd.passwd*","","None.","Secret","Get-PwPureFtpConfig") | Out-Null $FileNamePatternsAll.Rows.Add("ftpd.*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("ftpusers*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("httpd.conf*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("hudson.security.HudsonPrivateSecurityRealm.*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("jboss-cli.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("hudson.security.HudsonPrivateSecurityRealm.*","","None.","Secret","Get-PwJenkinsConfig") | Out-Null + $FileNamePatternsAll.Rows.Add("config.xml*","","None.","Secret","Get-PwJenkinsConfig") | Out-Null + $FileNamePatternsAll.Rows.Add("jboss-cli.xml*","","None.","Secret","Get-PwJbossCliConfig") | Out-Null $FileNamePatternsAll.Rows.Add("jboss-logmanager.properties*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("jenkins.model.JenkinsLocationConfiguration.*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("machine.config*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("my.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("machine.config*","","None.","Secret","Get-PwMachineConfig") | Out-Null + $FileNamePatternsAll.Rows.Add("my.*","","None.","Secret","Get-PwMySQLConfig") | Out-Null $FileNamePatternsAll.Rows.Add("mysql.user*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("nginx.conf*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("*ntds.dit*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("pg_hba.conf*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("php.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("php.ini*","","None.","Secret","Get-PwPhpIni") | Out-Null $FileNamePatternsAll.Rows.Add("*.pfx*","Private key.","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("policy.xml*","May be associated with SCCM/ConfigMgr and contain credentials to support PXE that can be recovered, base64 decoded, or decrypted using PXEThief or https://github.com/1njected/CMvarDecrypt.","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add(".pol*","May contain credentials to support PXE or other things.","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("putty.reg*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("putty.reg*","","None.","Secret","Get-PwPuttyRegFile") | Out-Null $FileNamePatternsAll.Rows.Add("postgresql.conf*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("SAM","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("SAM-*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("SAM_*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("SYSTEM","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("server.xml*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("shadow*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("standalone.xml*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("tnsnames.ora*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("tomcat-users.xml*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("sitemanager.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM-*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM_*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("SYSTEM","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("server.xml*","","None.","Secret","Get-PwServerXml") | Out-Null + $FileNamePatternsAll.Rows.Add("shadow*","","None.","Secret","Get-PwShadow") | Out-Null + $FileNamePatternsAll.Rows.Add("standalone.xml*","","None.","Secret","Get-PwStandalone") | Out-Null + $FileNamePatternsAll.Rows.Add("tnsnames.ora*","","None.","Secret","Get-PwTnsOra") | Out-Null + $FileNamePatternsAll.Rows.Add("tomcat-users.xml*","","None.","Secret","Get-PwTomcatUsers") | Out-Null + $FileNamePatternsAll.Rows.Add("sitemanager.xml*","","None.","Secret","Get-PwSiteManagerConfig") | Out-Null $FileNamePatternsAll.Rows.Add("users.*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("*variable*.dat*","This file is used for SCCM/ConfigMgr PXE deployments. It may contain passwords that can be recovered, base64 decoded, or decrypted using PXEThief or https://github.com/1njected/CMvarDecrypt.","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("*.var*","Often contain credentials. May be assocaited with SCCM/MECM","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("*.sav*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*setting.ini*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.pvm*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.pvs*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.qcow*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.qcow2*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*vcenter*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*vault*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*setting.ini*","","None.","Secret","Get-PwIniFile") | Out-Null + $FileNamePatternsAll.Rows.Add("*.pvm*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.pvs*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.qcow*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.qcow2*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*vcenter*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*vault*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null $FileNamePatternsAll.Rows.Add("*DefaultAppPool*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*WinSCP.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*WinSCP.ini*","","None.","Secret","Get-PwWinSCPConfig") | Out-Null $FileNamePatternsAll.Rows.Add("*.kdbx","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("wp-config.php*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.config","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.dtsx*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.rdp*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.aws*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*vnc.ini*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*DataSource.xml*","Group policy file that may contain passwords.","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*ScheduledTasks.xml*","Group policy file that may contain passwords.","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*Groups.xml*","Group policy file that may contain passwords.","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*Drives.xml*","Group policy file that may contain passwords.","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*unattend*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*sysprep*","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.key","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.private","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.pem","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.p12","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.pfx","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.crt","","None.","Secret","") | Out-Null - $FileNamePatternsAll.Rows.Add("*.ppk","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("wp-config.php*","","None.","Secret","Get-PwWordPressConfig") | Out-Null + $FileNamePatternsAll.Rows.Add("*.config","","None.","Secret","Get-PwWebConfig") | Out-Null + $FileNamePatternsAll.Rows.Add("*.dtsx*","","None.","Secret","Get-PwSsisDtsx") | Out-Null + $FileNamePatternsAll.Rows.Add("*.rdp*","","None.","Secret","Get-PwRdpInfo") | Out-Null + $FileNamePatternsAll.Rows.Add("*.aws*","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*vnc.ini*","","None.","Secret","Get-PwVnc") | Out-Null + $FileNamePatternsAll.Rows.Add("*DataSource.xml*","Group policy file that may contain passwords.","None.","Secret","Get-PwGPP") | Out-Null + $FileNamePatternsAll.Rows.Add("*ScheduledTasks.xml*","Group policy file that may contain passwords.","None.","Secret","Get-PwGPP") | Out-Null + $FileNamePatternsAll.Rows.Add("*Groups.xml*","Group policy file that may contain passwords.","None.","Secret","Get-PwGPP") | Out-Null + $FileNamePatternsAll.Rows.Add("*Drives.xml*","Group policy file that may contain passwords.","None.","Secret","Get-PwGPP") | Out-Null + $FileNamePatternsAll.Rows.Add("*Services.xml*","Group policy file that may contain passwords.","None.","Secret","Get-PwGPP") | Out-Null + $FileNamePatternsAll.Rows.Add("*Printers.xml*","Group policy file that may contain passwords.","None.","Secret","Get-PwGPP") | Out-Null + $FileNamePatternsAll.Rows.Add("*unattend*","","None.","Secret","Get-PwUnattendFile") | Out-Null + $FileNamePatternsAll.Rows.Add("*sysprep*","","None.","Secret","Get-PwSysprepFile") | Out-Null + $FileNamePatternsAll.Rows.Add("*.key","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.private","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.pem","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.p12","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.pfx","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.crt","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*.ppk","","None.","Secret","Get-PrivateKeyFilePath") | Out-Null + $FileNamePatternsAll.Rows.Add("*sssd.conf*","","None.","Secret","Get-PwSssdConfig") | Out-Null + $FileNamePatternsAll.Rows.Add("*smb.conf*","","None.","Secret","Get-PwSmbConf") | Out-Null + $FileNamePatternsAll.Rows.Add("*krb5.conf*","","None.","Secret","Get-Pwkrb5Conf") | Out-Null + $FileNamePatternsAll.Rows.Add("*htpasswd*","","None.","Secret","Get-PwHtpasswd") | Out-Null + $FileNamePatternsAll.Rows.Add("*pgpass*","","None.","Secret","Get-PwPgPass") | Out-Null # Add rows to data table - System/VM Images $FileNamePatternsAll.Rows.Add("*.img*","","None.","SystemImage","") | Out-Null @@ -1813,6 +1824,70 @@ function Invoke-HuntSMBShares # Return row $IfRow } + + # ---------------------------------------------------------------------- + # Interesting Files - Download and Parse Secrets Files + # ---------------------------------------------------------------------- + + # Status user + $Time = Get-Date -UFormat "%m/%d/%Y %R" + Write-Output " [*][$Time] Grabbing secrets for parsing..." + + # Filter for secret files + $MySecrets = $InterestingFilesAllObjects | where category -eq 'secret' + + # Create data table to store the parsed passwords + <# + $null = $MySecretsTbl = New-Object System.Data.DataTable + $null = $MySecretsTbl.Columns.Add("ComputerName", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("ShareName", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("FilePath", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("UNCPath", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("Server", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("Port", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("Username", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("Password", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("EncryptedPassword", [System.Type]::GetType("System.String")) + $null = $MySecretsTbl.Columns.Add("KeyFile", [System.Type]::GetType("System.String")) + #> + + # Download the Files + $MySecretsTbl = $MySecrets | + Foreach { + + # "ComputerName","ShareName","SharePath","UncPath","FileName","Category" + $MySecretsComputer = $_.ComputerName + $MySecretsShare = $_.ShareName + $MySecretsFilePath = $_.UncPath + $MySecretsFile = $_.FileName + + # Download all of them if the are less than 5mb + $MySecretsFileLocalPath = Copy-FileWithStructure -ComputerName $MySecretsComputer -ShareName $MySecretsShare -FilePath $MySecretsFilePath -OutputDirectory "$OutputDirectory" -ErrorAction SilentlyContinue + + # Grab function matches for file + $FileNamePatternsAll | where category -like 'secret' | where ParserFunction -notlike "" | + foreach{ + + # Check for keyword match + $MySecretKeywordCheck = $_.Keyword + $MySecretKeywordFunction = $_.ParserFunction + if($MySecretsFile -like "$MySecretKeywordCheck"){ + + # Call function to prase file + # write-output "Parsing $MySecretsFile with $MySecretKeywordFunction" + $FunctionToCall = Get-Command $MySecretKeywordFunction + & $FunctionToCall -ComputerName $MySecretsComputer -ShareName $MySecretsShare -FileName $MySecretsFile -UncFilePath $MySecretsFilePath -FilePath $MySecretsFileLocalPath + } + } + + } + + # Write passwords to file + $MySecretsTbl | Export-Csv -NoTypeInformation "$OutputDirectory\$TargetDomain-Shares-Recovered-Passwords.csv" + + # Generate counts for dashabord summary and for "Recovered Secrets" Page + + # Generate table content for "Recovered Secrets" Page # ---------------------------------------------------------------------- # Calculate risk score per acl - ace insights @@ -22561,15 +22636,212 @@ function Get-ADDomainFromFQDN { return $domain } +# ------------------------------------------------------------ +# Password File Download Function +# ------------------------------------------------------------ + +function Copy-FileWithStructure { + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath, + + [Parameter(Mandatory = $true)] + [string]$ComputerName, + + [Parameter(Mandatory = $true)] + [string]$ShareName, + + [Parameter(Mandatory = $false)] + [string]$OutputDirectory = (Get-Location).Path + ) + + # Step 1: Check if the file exists and is a file, not a directory + if (-Not (Test-Path $FilePath)) { + Write-Error "Path not found: $FilePath" + return + } + if (-Not (Get-Item $FilePath).PSIsContainer) { + # Step 2: Get file size and check if it's greater than 5MB + $fileSize = (Get-Item $FilePath).Length + if ($fileSize -gt 5MB) { + Write-Output "File size is greater than 5MB, exiting." + return + } + + # Step 3: Create "secrets" subdirectory if it doesn't exist + $secretsDir = Join-Path $OutputDirectory "secrets" + if (-Not (Test-Path $secretsDir)) { + $null = New-Item -Path $secretsDir -ItemType Directory -Force + } + + # Step 4: Create subfolder for computer name if it doesn't exist + $computerDir = Join-Path $secretsDir $ComputerName + if (-Not (Test-Path $computerDir)) { + $null = New-Item -Path $computerDir -ItemType Directory -Force + } + + # Step 5: Create subfolder for share name if it doesn't exist + $shareDir = Join-Path $computerDir $ShareName + if (-Not (Test-Path $shareDir)) { + $null = New-Item -Path $shareDir -ItemType Directory -Force + } + + # Step 6: Handle subfolder structure from file path in share name folder + $relativePath = $FilePath -replace "^\\\\$ComputerName\\$ShareName\\", '' + $targetDir = [System.IO.Path]::GetDirectoryName($relativePath) + + if ($targetDir -ne '') { + $fullTargetDir = Join-Path $shareDir $targetDir + if (-Not (Test-Path $fullTargetDir)) { + $null = New-Item -Path $fullTargetDir -ItemType Directory -Force + } + } else { + $fullTargetDir = $shareDir + } + + # Step 7: Copy the file to the target directory with error handling + try { + $destinationFile = Join-Path $fullTargetDir (Get-Item $FilePath).Name + Copy-Item -Path $FilePath -Destination $destinationFile -ErrorAction Stop + Write-Verbose "File successfully copied to $destinationFile" + } catch { + Write-Error "Error copying file: $_" + } + } else { + Write-Error "The path provided is a directory, not a file: $FilePath" + } + + # Return local file path + $destinationFile +} + # ------------------------------------------------------------ # Password Parsing Functions # ------------------------------------------------------------ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) +# Intended input: web.config +function Get-PwWebConfig { + param ( + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required - $configFilePath + ) + + $configFilePath = $FilePath + + # Load the config file as XML + [xml]$configXml = Get-Content $configFilePath + + # Initialize a DataTable to store results + $dtCredentials = New-Object System.Data.DataTable + $null = $dtCredentials.Columns.Add("ComputerName", [string]) + $null = $dtCredentials.Columns.Add("ShareName", [string]) + $null = $dtCredentials.Columns.Add("UncFilePath", [string]) + $null = $dtCredentials.Columns.Add("FileName", [string]) + $null = $dtCredentials.Columns.Add("Section", [string]) + $null = $dtCredentials.Columns.Add("ObjectName", [string]) + $null = $dtCredentials.Columns.Add("TargetURL", [string]) + $null = $dtCredentials.Columns.Add("TargetServer", [string]) + $null = $dtCredentials.Columns.Add("TargetPort", [string]) + $null = $dtCredentials.Columns.Add("Database", [string]) + $null = $dtCredentials.Columns.Add("Domain", [string]) + $null = $dtCredentials.Columns.Add("Username", [string]) + $null = $dtCredentials.Columns.Add("Password", [string]) + $null = $dtCredentials.Columns.Add("PasswordEnc", [string]) + $null = $dtCredentials.Columns.Add("KeyFilePath", [string]) + + # Helper function to add rows to DataTable + function Add-CredentialsToDataTable { + param ( + [string]$computerName, + [string]$shareName, + [string]$uncFilePath, + [string]$fileName, + [string]$section, + [string]$name, + [string]$url, + [string]$server, + [string]$port, + [string]$database, + [string]$domain, + [string]$username, + [string]$password, + [string]$passwordEnc = "NA", + [string]$KeyFilePath = "NA" + ) + $null = $dtCredentials.Rows.Add($computerName, $shareName, $uncFilePath, $fileName, $section, $name, $url, $server, $port, $database, $domain, $username, $password, $passwordEnc, $KeyFilePath) + } + + # Parse connectionStrings for server, port, username, password, and database + if ($configXml.configuration.connectionStrings) { + foreach ($connection in $configXml.configuration.connectionStrings.add) { + $connectionString = $connection.connectionString + $providerName = $connection.providerName + $name = $connection.name + + # Initialize variables for potential data + $server = $null + $port = $null + $user = $null + $password = $null + $url = $null + $database = $null + + # Parse connection strings + if ($connectionString -match "Host\s*=\s*([^;]+).*?Port\s*=\s*(\d+).*?Username\s*=\s*([^;]+).*?Password\s*=\s*([^;]+)") { + $server = $matches[1] + $port = $matches[2] + $user = $matches[3] + $password = $matches[4] + $url = "Host=$server;Port=$port" + } elseif ($connectionString -match "(Server|Data Source)\s*=\s*([^;,]+)(?:,(\d+))?") { + $server = $matches[2] + if ($matches[3]) { $port = $matches[3] } + $url = "Server=$server" + } + + # Capture the database/catalog if found + if ($connectionString -match "(Initial Catalog|Database|Data Source)\s*=\s*([^;]+)") { + $database = $matches[2] + } + + if ($connectionString -match "User\s*Id\s*=\s*([^;]+)") { + $user = $matches[1] + } + if ($connectionString -match "Password\s*=\s*([^;]+)") { + $password = $matches[1] + } + + # Add row to the DataTable if username and password exist + if ($user -and $password) { + Add-CredentialsToDataTable -computerName $ComputerName -shareName $ShareName -uncFilePath $UncFilePath -fileName $FileName ` + -section "ConnectionStrings ($providerName)" -name $name -url $url -server $server -port $port -database $database -username $user -password $password + } + } + } + + # Output the parsed credentials using the DataTable + if ($dtCredentials.Rows.Count -eq 0) { + Write-Host "No credentials found." -ForegroundColor Red + } else { + $dtCredentials | select ComputerName, ShareName, UncFilePath, FileName, Section, ObjectName, TargetURL, TargetServer, TargetPort, Database, Domain, Username, Password, PasswordEnc, KeyFilePath + } +} +# Get-PwWebConfig -FilePath "C:\tools\Sample Configuration Files\configs\web.config" -ComputerName 'computer' -ShareName 'share' -FileName 'file.txt' -UncFilePath '\\computer\share\file.txt' + + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intented input: wp-config.php function Get-PwWordPressConfig { param ( - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -22601,195 +22873,40 @@ function Get-PwWordPressConfig { if ($dbUsername -and $dbPassword) { # Return the results as a PowerShell object [PSCustomObject]@{ - Username = $dbUsername - Password = $dbPassword + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $dbUsername + Password = $dbPassword + PasswordEnc = "NA" + KeyFilePath = "NA" } } else { Write-Error "Username or Password not found in the configuration file." } } +#Get-PwWordPressConfig -FilePath 'C:\tools\Sample Configuration Files\configs\wp-config.php' -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' -# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) -# Intended input: web.config -# Function to parse configuration files for credentials -function Get-PwWebConfig{ - param ( - [string]$configFilePath - ) - - # Load the config file as XML - [xml]$configXml = Get-Content $configFilePath - - # Initialize a DataTable to store results - $dtCredentials = New-Object System.Data.DataTable - $null = $dtCredentials.Columns.Add("Name", [string]) - $null = $dtCredentials.Columns.Add("Section", [string]) - $null = $dtCredentials.Columns.Add("URL", [string]) - $null = $dtCredentials.Columns.Add("Server", [string]) - $null = $dtCredentials.Columns.Add("Port", [string]) - $null = $dtCredentials.Columns.Add("UserName", [string]) - $null = $dtCredentials.Columns.Add("Password", [string]) - - # Helper function to add rows to DataTable - function Add-CredentialsToDataTable { - param ( - [string]$name, - [string]$section, - [string]$url, - [string]$server, - [string]$port, - [string]$username, - [string]$password - ) - $null = $dtCredentials.Rows.Add($name, $section, $url, $server, $port, $username, $password) - } - - # Dictionary to temporarily store related credentials - $credentialPairs = @{} - - # Function to store credentials in temporary dictionary - function Add-CredentialPair { - param ( - [string]$name, - [string]$section, - [string]$key, - [string]$value - ) - - if ($credentialPairs[$name]) { - $credentialPairs[$name][$key] = $value - } else { - $credentialPairs[$name] = @{} - $credentialPairs[$name][$key] = $value - $credentialPairs[$name]["Section"] = $section - } - - # If both username and password are available, add them to the DataTable - if ($credentialPairs[$name]["UserName"] -and $credentialPairs[$name]["Password"]) { - Add-CredentialsToDataTable -name $name -section $credentialPairs[$name]["Section"] ` - -url $credentialPairs[$name]["URL"] -server $credentialPairs[$name]["Server"] ` - -port $credentialPairs[$name]["Port"] -username $credentialPairs[$name]["UserName"] ` - -password $credentialPairs[$name]["Password"] - - # Clear the stored credential after adding it to the table - $credentialPairs.Remove($name) - } - } - - # Parse all instances of appSettings for OAuth, WebClient, API, and other credentials - if ($configXml.SelectNodes('//appSettings')) { - foreach ($appSettings in $configXml.SelectNodes('//appSettings')) { - foreach ($setting in $appSettings.add) { - $key = $setting.key - $value = $setting.value - $section = "AppSettings" - - # Handle specific cases for OAuth, API, and WebClient settings - switch ($key) { - "OAuthServiceUrl" { Add-CredentialPair -name "OAuth" -section $section -key "URL" -value $value } - "ClientId" { Add-CredentialPair -name "OAuth" -section $section -key "UserName" -value $value } - "ClientSecret" { Add-CredentialPair -name "OAuth" -section $section -key "Password" -value $value } - "ServiceUrl" { Add-CredentialPair -name "WebClient" -section $section -key "URL" -value $value } - "ServiceUserName" { Add-CredentialPair -name "WebClient" -section $section -key "UserName" -value $value } - "ServicePassword" { Add-CredentialPair -name "WebClient" -section $section -key "Password" -value $value } - "ApiEndpoint" { Add-CredentialPair -name "API" -section $section -key "URL" -value $value } - "ApiUserName" { Add-CredentialPair -name "API" -section $section -key "UserName" -value $value } - "ApiPassword" { Add-CredentialPair -name "API" -section $section -key "Password" -value $value } - "ApplicationUsername" { Add-CredentialPair -name "Application" -section $section -key "UserName" -value $value } - "ApplicationPassword" { Add-CredentialPair -name "Application" -section $section -key "Password" -value $value } - } - } - } - } - - # Parse custom serviceCredentials section - if ($configXml.configuration.serviceCredentials) { - foreach ($setting in $configXml.configuration.serviceCredentials.add) { - $key = $setting.key - $value = $setting.value - $section = "ServiceCredentials" - - # Handle specific cases for custom service credentials - switch ($key) { - "ServiceUrl" { Add-CredentialPair -name "CustomService" -section $section -key "URL" -value $value } - "UserName" { Add-CredentialPair -name "CustomService" -section $section -key "UserName" -value $value } - "Password" { Add-CredentialPair -name "CustomService" -section $section -key "Password" -value $value } - } - } - } - - # Parse connectionStrings for server, port, username, and password - if ($configXml.configuration.connectionStrings) { - foreach ($connection in $configXml.configuration.connectionStrings.add) { - $connectionString = $connection.connectionString - $providerName = $connection.providerName - $name = $connection.name - - # Initialize variables for potential data - $server = $null - $port = $null - $user = $null - $password = $null - $url = $null - - # Parse connection strings - if ($connectionString -match "Host\s*=\s*([^;]+).*?Port\s*=\s*(\d+).*?Username\s*=\s*([^;]+).*?Password\s*=\s*([^;]+)") { - $server = $matches[1] - $port = $matches[2] - $user = $matches[3] - $password = $matches[4] - $url = "Host=$server;Port=$port" - } elseif ($connectionString -match "(Server|Data Source)\s*=\s*([^;,]+)(?:,(\d+))?") { - $server = $matches[2] - if ($matches[3]) { $port = $matches[3] } - $url = "Server=$server" - } - - if ($connectionString -match "User\s*Id\s*=\s*([^;]+)") { - $user = $matches[1] - } - if ($connectionString -match "Password\s*=\s*([^;]+)") { - $password = $matches[1] - } - - # Add row to the DataTable if username and password exist - if ($user -and $password) { - Add-CredentialsToDataTable -name $name -section "ConnectionStrings ($providerName)" -url $url -server $server -port $port -username $user -password $password - } - } - } - - # Parse system.net/mailSettings for SMTP credentials and URLs - if ($configXml.configuration.'system.net'.mailSettings) { - foreach ($smtp in $configXml.configuration.'system.net'.mailSettings.smtp) { - $smtpServer = $smtp.network.host - $smtpPort = $smtp.network.port - $smtpUser = $smtp.network.userName - $smtpPass = $smtp.network.password - $url = "smtp://${smtpServer}:${smtpPort}" - - if ($smtpUser -and $smtpPass) { - Add-CredentialsToDataTable -name "SMTP Configuration" -section "SMTP" -url $url -server $smtpServer -port $smtpPort -username $smtpUser -password $smtpPass - } - } - } - - # Output the parsed credentials using the DataTable - if ($dtCredentials.Rows.Count -eq 0) { - Write-Host "No credentials found." -ForegroundColor Red - } else { - $dtCredentials | select Name, Section, URL, Server, Port, UserName, Password - } -} - # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intented input: WinSCP.ini function Get-PwWinSCPConfig { param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if file exists @@ -22803,21 +22920,31 @@ function Get-PwWinSCPConfig { # Initialize an empty object for results $result = [PSCustomObject]@{ - HostName = $null - PortNumber = $null - PrivateKeyFile = $null - UserName = $null - Password = $null + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $null + TargetPort = $null + Database = "NA" + Domain = "NA" + Username = $null + Password = $null + PasswordEnc = "NA" + KeyFilePath = "NA" } # Parse the .ini file for relevant information foreach ($line in $content) { if ($line -match '^HostName=(.*)') { - $result.HostName = $matches[1] + $result.TargetServer = $matches[1] } elseif ($line -match '^PortNumber=(.*)') { - $result.PortNumber = [int]$matches[1] + $result.TargetPort = [int]$matches[1] } elseif ($line -match '^PrivateKeyFile=(.*)') { - $result.PrivateKeyFile = $matches[1] + $result.KeyFilePath = $matches[1] } elseif ($line -match '^UserName=(.*)') { $result.UserName = $matches[1] } elseif ($line -match '^Password=(.*)') { @@ -22828,15 +22955,23 @@ function Get-PwWinSCPConfig { # Return the result object return $result } +# Get-PwWinSCPConfig -FilePath "C:\tools\Sample Configuration Files\configs\WinSCP.ini" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended intput: vnc.ini function Get-PwVnc { param ( - [Parameter(Mandatory=$true)] - [string]$VncIniPath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) + # Set vnc inipath + $VncIniPath = $FilePath + # Define the fixed DES key used by VNC $desKey = [byte[]](0x23, 0x52, 0x6A, 0x3B, 0x58, 0x92, 0x67, 0x34) @@ -22882,16 +23017,37 @@ function Get-PwVnc { # Return the decrypted password as an object return [pscustomobject]@{ - DecryptedPassword = $decryptedPassword + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = "NA" + Password = $decryptedPassword + PasswordEnc = $encryptedHex + KeyFilePath = "NA" } } +# Get-PwVnc -FilePath "C:\tools\Sample Configuration Files\configs\vnc.ini" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: *unattend*.xml # Supports cleartext and base46 encoded passwords -function Parse-PwUnattendFile { +function Get-PwUnattendFile { param ( - [string]$filePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Load the XML file @@ -22919,7 +23075,7 @@ function Parse-PwUnattendFile { $decodedPassword = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($passwordValue)) return $decodedPassword } catch { - Write-Host "Error: Unable to decode Base64 string, returning original value." + # Write-Host "Error: Unable to decode Base64 string, returning original value." return $passwordValue } } @@ -22941,9 +23097,22 @@ function Parse-PwUnattendFile { $password = Decode-PasswordIfNeeded -passwordValue $password -isPlainText $isPlainText $credentials += [pscustomobject]@{ - User = $username - Password = $password - Source = "AutoLogon" + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "AutoLogon" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } } @@ -22958,24 +23127,46 @@ function Parse-PwUnattendFile { $password = Decode-PasswordIfNeeded -passwordValue $password -isPlainText $isPlainText $credentials += [pscustomobject]@{ - User = $username - Password = $password - Source = "LocalAccount" + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "LocalAccount" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Return the collected credentials as an array of objects return $credentials } +# Get-PwUnattendFile -filePath "C:\tools\Sample Configuration Files\configs\unattend-base64.xml" -ComputerName 'computer' -ShareName 'share' -FileName 'asdf' -UncFilePath '\\computer\share\file.txt' +# Get-PwUnattendFile -filePath "C:\tools\Sample Configuration Files\configs\unattend-cleartext.xml" -ComputerName 'computer' -ShareName 'share' -FileName 'asdf' -UncFilePath '\\computer\share\file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended intput: tomcat-users.xml function Get-PwTomcatUsers { param ( - [Parameter(Mandatory = $true)] - [string]$TomcatConfigFile + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) + # Set file + $TomcatConfigFile = $FilePath + # Load the XML file [xml]$xml = Get-Content -Path $TomcatConfigFile @@ -22989,8 +23180,22 @@ function Get-PwTomcatUsers { foreach ($user in $users) { # Create a PowerShell object for each user $userObject = [PSCustomObject]@{ - Username = $user.name - Password = $user.password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $user.name + Password = $user.password + PasswordEnc = "NA" + KeyFilePath = "NA" } # Add the object to the list @@ -23000,12 +23205,18 @@ function Get-PwTomcatUsers { # Display the list of users as a table return $usersList } +# Get-PwTomcatUsers -FilePath "C:\tools\Sample Configuration Files\configs\tomcat-users.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: tnsnames.ora function Get-PwTnsOra { param( - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) if (-Not (Test-Path -Path $FilePath)) { @@ -23033,9 +23244,21 @@ function Get-PwTnsOra { if ($currentDatabase -and $currentUser -and $currentPassword) { # Store the previous credentials $credentialsList += [pscustomobject]@{ - Database = $currentDatabase - User = $currentUser - Password = $currentPassword + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = $currentDatabase + Domain = "NA" + Username = $currentUser + Password = $currentPassword + PasswordEnc = "NA" + KeyFilePath = "NA" } } @@ -23045,13 +23268,13 @@ function Get-PwTnsOra { $currentPassword = $null } - # Match the USER line - if ($line -match 'USER\s*=\s*(.+)$') { + # Match the USER line and remove the trailing ')' + if ($line -match 'USER\s*=\s*(.+)\)$') { $currentUser = $matches[1] } - # Match the PASSWORD line - if ($line -match 'PASSWORD\s*=\s*(.+)$') { + # Match the PASSWORD line and remove the trailing ')' + if ($line -match 'PASSWORD\s*=\s*(.+)\)$') { $currentPassword = $matches[1] } } @@ -23059,22 +23282,39 @@ function Get-PwTnsOra { # Capture the last set of credentials if ($currentDatabase -and $currentUser -and $currentPassword) { $credentialsList += [pscustomobject]@{ - Database = $currentDatabase - User = $currentUser - Password = $currentPassword + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = $currentDatabase + Domain = "NA" + Username = $currentUser + Password = $currentPassword + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Output the results as a list of objects return $credentialsList } +# Get-PwTnsOra -FilePath "C:\tools\Sample Configuration Files\configs\tnsnames.ora" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: sysprep.inf function Get-PwSysprepFile { param ( - [Parameter(Mandatory=$true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if file exists @@ -23096,78 +23336,170 @@ function Get-PwSysprepFile { # Loop through each line and extract relevant credentials foreach ($line in $fileContent) { - if ($line -match 'AdminPassword\s*=\s*(.+)') { + # Match exactly 'AdminPassword' and exclude DomainAdminPassword + if ($line -match '^AdminPassword\s*=\s*(.+)$') { $credentials['AdminPassword'] = $matches[1].Trim() } - if ($line -match 'JoinDomain\s*=\s*(.+)') { + if ($line -match '^JoinDomain\s*=\s*(.+)$') { $credentials['JoinDomain'] = $matches[1].Trim() } - if ($line -match 'DomainAdmin\s*=\s*(.+)') { + if ($line -match '^DomainAdmin\s*=\s*(.+)$') { $credentials['DomainAdmin'] = $matches[1].Trim() } - if ($line -match 'DomainAdminPassword\s*=\s*(.+)') { + if ($line -match '^DomainAdminPassword\s*=\s*(.+)$') { $credentials['DomainAdminPassword'] = $matches[1].Trim() } } - # Create and return a PowerShell object - $credObject = [pscustomobject]@{ - AdminPassword = $credentials['AdminPassword'] - JoinDomain = $credentials['JoinDomain'] - DomainAdmin = $credentials['DomainAdmin'] - DomainAdminPassword = $credentials['DomainAdminPassword'] + # Create objects with Domain, Username, and Password properties + $adminObject = [pscustomobject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = 'localhost' + Username = 'Administrator' + Password = if ($credentials['AdminPassword']) { $credentials['AdminPassword'] } else { '' } + PasswordEnc = 'NA' + KeyFilePath = "NA" } - return $credObject + $domainAdminObject = [pscustomobject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = if ($credentials['JoinDomain']) { $credentials['JoinDomain'] } else { '' } + Username = if ($credentials['DomainAdmin']) { $credentials['DomainAdmin'] } else { '' } + Password = if ($credentials['DomainAdminPassword']) { $credentials['DomainAdminPassword'] } else { '' } + PasswordEnc = "NA" + KeyFilePath = "NA" + } + + # Return both objects without "name" and "value" format, just as PowerShell objects + return $domainAdminObject, $adminObject } +# Get-PwSysprepFile -FilePath "C:\tools\Sample Configuration Files\configs\sysprep.inf" -ComputerName 'computer' -ShareName 'share' -FileName 'file.txt' -UncFilePath '\\computer\share\file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: standalone.xml function Get-PwStandalone { param ( - [string]$ConfigPath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) + + # Set path + $ConfigPath = $FilePath # Load the XML config [xml]$configXml = Get-Content -Path $ConfigPath - # Define a hashtable to store results - $result = @{} + # Define a list to store the objects (one for connection info, one for keystore info) + $results = @() # Parse the server and port from the connection URL $connectionUrl = $configXml.server.subsystem.datasources.datasource."connection-url" + $server = '' + $port = '3306' # Default MySQL port if ($connectionUrl -match "jdbc:mysql://([^:/]+)(?::(\d+))?") { - $result.Server = $matches[1] - $result.Port = if ($matches[2]) { $matches[2] } else { "3306" } # Default MySQL port + $server = $matches[1] + if ($matches[2]) { + $port = $matches[2] + } } - # Get the username - $result.Username = $configXml.server.subsystem.datasources.datasource.security."user-name" + # Get the username and password for the connection + $username = $configXml.server.subsystem.datasources.datasource.security."user-name" + $password = $configXml.server.subsystem.datasources.datasource.security.password - # Get the password - $result.Password = $configXml.server.subsystem.datasources.datasource.security.password + # Create the connection info object + $connectionObject = [PSCustomObject]@{ - # Get the keystore password from the vault section - $keystorePassword = $configXml.server.security.vault."vault-option" | Where-Object { $_.name -eq "KEYSTORE_PASSWORD" } - $result.KeystorePassword = $keystorePassword.value + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $server + TargetPort = $port + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" + } - # Convert hashtable to PowerShell object - $resultObject = [PSCustomObject]$result - - # Output the result object - return $resultObject + # Add the connection info object to the list + $results += $connectionObject + + # Parse the keystore password from the vault section + $keystorePasswordEntry = $configXml.server.security.vault."vault-option" | Where-Object { $_.name -eq "KEYSTORE_PASSWORD" } + $keystorePassword = if ($keystorePasswordEntry) { $keystorePasswordEntry.value } else { '' } + + # Create the keystore password object with the same schema + $keystoreObject = [PSCustomObject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = 'Keystore' + Password = $keystorePassword + PasswordEnc = "NA" + KeyFilePath = "NA" + } + + # Add the keystore object to the list + $results += $keystoreObject + + # Return the list of both objects + return $results } +# Get-PwStandalone -FilePath "C:\tools\Sample Configuration Files\configs\standalone.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: sssd.conf function Get-PwSssdConfig { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Initialize a hashtable to store extracted values @@ -23217,20 +23549,37 @@ function Get-PwSssdConfig { # Output the extracted configuration as a PowerShell object [PSCustomObject]@{ - Domain = $configData.Domain - Server = $configData.Server - Username = $configData.Username - Password = $configData.Password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $configData.Server + TargetPort = "NA" + Database = "NA" + Domain = $configData.Domain + Username = $configData.Username + Password = $configData.Password + PasswordEnc = "NA" + KeyFilePath = "NA" } } +# Get-PwSssdConfig -FilePath "C:\tools\Sample Configuration Files\configs\sssd.conf" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: smb.conf function Get-PwSmbConf { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Initialize a hashtable to store extracted values @@ -23268,10 +23617,26 @@ function Get-PwSmbConf { # Output the extracted configuration as a PowerShell object [PSCustomObject]@{ - Username = $configData.Username - Password = $configData.Password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $configData.Username + Password = $configData.Password + PasswordEnc = "NA" + KeyFilePath = "NA" } } +# Get-PwSmbConf -FilePath "C:\tools\Sample Configuration Files\configs\smb.conf" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intented input: sitemanager.xml @@ -23283,13 +23648,20 @@ function IsBase64String { } return $false } - # Function to process the SiteManager.xml file and extract server information function Get-PwSiteManagerConfig { param ( - [string]$xmlFilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) + + # Set path + $xmlFilePath = $FilePath + # Check if the file exists if (-not (Test-Path $xmlFilePath)) { Write-Error "File not found: $xmlFilePath" @@ -23318,21 +23690,39 @@ function Get-PwSiteManagerConfig { # Output the server details [pscustomobject]@{ - Server = $_.Host - Port = $_.Port - Username = $_.User - Password = $decodedPassword + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $_.Host + TargetPort = $_.Port + Database = "NA" + Domain = "NA" + Username = $_.User + Password = $decodedPassword + PasswordEnc = $base64Pass + KeyFilePath = "NA" } } } +#Get-PwSiteManagerConfig -FilePath "C:\tools\Sample Configuration Files\configs\SiteManager.xml" -ComputerName 'computer' -ShareName 'share' -FileName 'file.txt' -UncFilePath '\\computer\share\file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: shadow -function Get-GetPwShadow { +function Get-PwShadow { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Initialize an array to store extracted user data @@ -23363,8 +23753,23 @@ function Get-GetPwShadow { # Create an object to store the extracted information $userObject = [PSCustomObject]@{ - Username = $username - PasswordHash = $passwordHash + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = "NA" + PasswordEnc = $passwordHash + KeyFilePath = "NA" + } # Add the object to the array @@ -23374,14 +23779,19 @@ function Get-GetPwShadow { # Output the array of credentials return $credentials } +# Get-GetPwShadow -FilePath "C:\tools\Sample Configuration Files\configs\shadow" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: setting.ini / Generic function Get-PwIniFile { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Initialize an array to store the credentials @@ -23413,9 +23823,22 @@ function Get-PwIniFile { # If we have collected username and password, store them before moving to the next section if ($username -and $password) { $credentials += [PSCustomObject]@{ - Section = $currentSection - Username = $username - Password = $password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = $currentSection + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Reset username and password for the new section @@ -23442,22 +23865,41 @@ function Get-PwIniFile { # Capture any remaining username/password pair after the last section if ($username -and $password) { $credentials += [PSCustomObject]@{ - Section = $currentSection - Username = $username - Password = $password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = $currentSection + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Output the credentials as PowerShell objects return $credentials } +# Get-PwIniFile -FilePath "C:\tools\Sample Configuration Files\configs\setting.ini" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Putty.reg does not store passwords, but can point to private keys # Intended input: putty.reg function Get-PwPuttyRegFile { param ( - [string]$filePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -23486,11 +23928,22 @@ function Get-PwPuttyRegFile { # If we're processing a new session, save the previous one if ($currentSession -ne "") { $sessionDetails += [pscustomobject]@{ - Session = $currentSession - HostName = $hostName - Port = [int]$portNumber - UserName = $userName - PrivateKeyPath = $privateKeyPath + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = $currentSession + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $hostName + TargetPort = $portNumber + Database = "NA" + Domain = "NA" + Username = $userName + Password = "NA" + PasswordEnc = "NA" + KeyFilePath = $privateKeyPath } } @@ -23526,23 +23979,40 @@ function Get-PwPuttyRegFile { # After the loop, add the last session if it exists if ($currentSession -ne "") { $sessionDetails += [pscustomobject]@{ - Session = $currentSession - HostName = $hostName - Port = [int]$portNumber - UserName = $userName - PrivateKeyPath = $privateKeyPath + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = $currentSession + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $hostName + TargetPort = $portNumber + Database = "NA" + Domain = "NA" + Username = $userName + Password = "NA" + PasswordEnc = "NA" + KeyFilePath = $privateKeyPath } } # Return the session details return $sessionDetails } +# Get-PwPuttyRegFile -FilePath "C:\tools\Sample Configuration Files\configs\putty.reg" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Inteded input: server.xml function Get-PwServerXml { param ( - [string]$filePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Load the XML file @@ -23554,9 +24024,22 @@ function Get-PwServerXml { # Parse basicRegistry user credentials $xmlContent.server.basicRegistry.user | ForEach-Object { $credentials += [pscustomobject]@{ - User = $_.name - Password = $_.password - Source = 'basicRegistry' + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = 'basicRegistry' + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $_.name + Password = $_.password + PasswordEnc = "NA" + KeyFilePath = "NA" } } @@ -23566,40 +24049,84 @@ function Get-PwServerXml { if ($dbUser -and $dbPass) { $credentials += [pscustomobject]@{ - User = $dbUser.value - Password = $dbPass.value - Source = 'variable' + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = 'variable' + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $dbUser.value + Password = $dbPass.value + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Parse containerAuthData credentials $xmlContent.server.dataSource.containerAuthData | ForEach-Object { $credentials += [pscustomobject]@{ - User = $_.user - Password = $_.password - Source = 'containerAuthData' + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = 'containerAuthData' + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $_.user + Password = $_.password + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Parse authData credentials $xmlContent.server.authData | ForEach-Object { $credentials += [pscustomobject]@{ - User = $_.user - Password = $_.password - Source = 'authData' + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = 'authData' + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $_.user + Password = $_.password + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Return the collected credentials as an array of objects return $credentials } +# Get-PwServerXml -FilePath "C:\tools\Sample Configuration Files\configs\server.xml" -ComputerName 'computer' -ShareName 'share' -FileName 'file.txt' -UncFilePath '\\computer\share\file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: pureftpd.passwd function Get-PwPureFtpConfig { param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -23626,8 +24153,22 @@ function Get-PwPureFtpConfig { # Create a custom object for each user $credentialObject = [PSCustomObject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" Username = $username - PasswordHash = $passwordHash + Password = "NA" + PasswordEnc = $passwordHash + KeyFilePath = "NA" } # Add the object to the credentials array @@ -23640,14 +24181,19 @@ function Get-PwPureFtpConfig { # Output the results as a PowerShell object array return $credentials } +# Get-PwPureFtpConfig -FilePath "C:\tools\Sample Configuration Files\configs\pureftpd.passwd" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: php.ini function Get-PwPhpIni { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Initialize a hashtable to store extracted values @@ -23685,16 +24231,36 @@ function Get-PwPhpIni { # Output the extracted configuration as a PowerShell object [PSCustomObject]@{ - Username = $configData.Username - Password = $configData.Password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $configData.Username + Password = $configData.Password + PasswordEnc = "NA" + KeyFilePath = "NA" } } +# Get-PwPhpIni -FilePath "C:\tools\Sample Configuration Files\configs\php.ini" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: my.cnf function Get-PwMySQLConfig { param ( - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -23724,8 +24290,22 @@ function Get-PwMySQLConfig { if ($username -and $password) { # Create a custom PowerShell object to return the credentials $credentials = [PSCustomObject]@{ - Username = $username - Password = $password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } return $credentials } else { @@ -23733,40 +24313,62 @@ function Get-PwMySQLConfig { return $null } } +# Get-PwMySQLConfig -FilePath "C:\tools\Sample Configuration Files\configs\my.cnf" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: machine.config # Function to parse configuration files for credentials function Get-PwMachineConfig { param ( - [string]$configFilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) + # Set path + $configFilePath = $FilePath + # Load the config file as XML [xml]$configXml = Get-Content $configFilePath # Initialize a DataTable to store results $dtCredentials = New-Object System.Data.DataTable - $null = $dtCredentials.Columns.Add("Name", [string]) + $null = $dtCredentials.Columns.Add("ComputerName", [string]) + $null = $dtCredentials.Columns.Add("ShareName", [string]) + $null = $dtCredentials.Columns.Add("UncFilePath", [string]) + $null = $dtCredentials.Columns.Add("FileName", [string]) $null = $dtCredentials.Columns.Add("Section", [string]) - $null = $dtCredentials.Columns.Add("URL", [string]) - $null = $dtCredentials.Columns.Add("Server", [string]) - $null = $dtCredentials.Columns.Add("Port", [string]) - $null = $dtCredentials.Columns.Add("UserName", [string]) + $null = $dtCredentials.Columns.Add("ObjectName", [string]) + $null = $dtCredentials.Columns.Add("TargetURL", [string]) + $null = $dtCredentials.Columns.Add("TargetServer", [string]) + $null = $dtCredentials.Columns.Add("TargetPort", [string]) + $null = $dtCredentials.Columns.Add("Database", [string]) + $null = $dtCredentials.Columns.Add("Domain", [string]) + $null = $dtCredentials.Columns.Add("Username", [string]) $null = $dtCredentials.Columns.Add("Password", [string]) + $null = $dtCredentials.Columns.Add("PasswordEnc", [string]) + $null = $dtCredentials.Columns.Add("KeyFilePath", [string]) # Helper function to add rows to DataTable function Add-CredentialsToDataTable { param ( - [string]$name, + [string]$computerName, + [string]$shareName, + [string]$uncFilePath, + [string]$fileName, [string]$section, + [string]$name, [string]$url, [string]$server, [string]$port, [string]$username, - [string]$password + [string]$password, + [string]$passwordEnc = "NA" ) - $null = $dtCredentials.Rows.Add($name, $section, $url, $server, $port, $username, $password) + $null = $dtCredentials.Rows.Add($computerName, $shareName, $uncFilePath, $fileName, $section, $name, $url, $server, $port, $database, $domain, $username, $password, $passwordEnc) } # Dictionary to temporarily store related credentials @@ -23791,7 +24393,7 @@ function Get-PwMachineConfig { # If both username and password are available, add them to the DataTable if ($credentialPairs[$name]["UserName"] -and $credentialPairs[$name]["Password"]) { - Add-CredentialsToDataTable -name $name -section $credentialPairs[$name]["Section"] ` + Add-CredentialsToDataTable -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name $name -section $credentialPairs[$name]["Section"] ` -url $credentialPairs[$name]["URL"] -server $credentialPairs[$name]["Server"] ` -port $credentialPairs[$name]["Port"] -username $credentialPairs[$name]["UserName"] ` -password $credentialPairs[$name]["Password"] @@ -23811,17 +24413,17 @@ function Get-PwMachineConfig { # Handle specific cases for OAuth, API, and WebClient settings switch ($key) { - "OAuthServiceUrl" { Add-CredentialPair -name "OAuth" -section $section -key "URL" -value $value } - "ClientId" { Add-CredentialPair -name "OAuth" -section $section -key "UserName" -value $value } - "ClientSecret" { Add-CredentialPair -name "OAuth" -section $section -key "Password" -value $value } - "ServiceUrl" { Add-CredentialPair -name "WebClient" -section $section -key "URL" -value $value } - "ServiceUserName" { Add-CredentialPair -name "WebClient" -section $section -key "UserName" -value $value } - "ServicePassword" { Add-CredentialPair -name "WebClient" -section $section -key "Password" -value $value } - "ApiEndpoint" { Add-CredentialPair -name "API" -section $section -key "URL" -value $value } - "ApiUserName" { Add-CredentialPair -name "API" -section $section -key "UserName" -value $value } - "ApiPassword" { Add-CredentialPair -name "API" -section $section -key "Password" -value $value } - "ApplicationUsername" { Add-CredentialPair -name "Application" -section $section -key "UserName" -value $value } - "ApplicationPassword" { Add-CredentialPair -name "Application" -section $section -key "Password" -value $value } + "OAuthServiceUrl" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "OAuth" -section $section -key "URL" -value $value } + "ClientId" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "OAuth" -section $section -key "UserName" -value $value } + "ClientSecret" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "OAuth" -section $section -key "Password" -value $value } + "ServiceUrl" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "WebClient" -section $section -key "URL" -value $value } + "ServiceUserName" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "WebClient" -section $section -key "UserName" -value $value } + "ServicePassword" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "WebClient" -section $section -key "Password" -value $value } + "ApiEndpoint" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "API" -section $section -key "URL" -value $value } + "ApiUserName" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "API" -section $section -key "UserName" -value $value } + "ApiPassword" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "API" -section $section -key "Password" -value $value } + "ApplicationUsername" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "Application" -section $section -key "UserName" -value $value } + "ApplicationPassword" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "Application" -section $section -key "Password" -value $value } } } } @@ -23836,9 +24438,9 @@ function Get-PwMachineConfig { # Handle specific cases for custom service credentials switch ($key) { - "ServiceUrl" { Add-CredentialPair -name "CustomService" -section $section -key "URL" -value $value } - "UserName" { Add-CredentialPair -name "CustomService" -section $section -key "UserName" -value $value } - "Password" { Add-CredentialPair -name "CustomService" -section $section -key "Password" -value $value } + "ServiceUrl" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "CustomService" -section $section -key "URL" -value $value } + "UserName" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "CustomService" -section $section -key "UserName" -value $value } + "Password" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "CustomService" -section $section -key "Password" -value $value } } } } @@ -23879,7 +24481,7 @@ function Get-PwMachineConfig { # Add row to the DataTable if username and password exist if ($user -and $password) { - Add-CredentialsToDataTable -name $name -section "ConnectionStrings ($providerName)" -url $url -server $server -port $port -username $user -password $password + Add-CredentialsToDataTable -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name $name -section "ConnectionStrings ($providerName)" -url $url -server $server -port $port -username $user -password $password } } } @@ -23894,7 +24496,7 @@ function Get-PwMachineConfig { $url = "smtp://${smtpServer}:${smtpPort}" if ($smtpUser -and $smtpPass) { - Add-CredentialsToDataTable -name "SMTP Configuration" -section "SMTP" -url $url -server $smtpServer -port $smtpPort -username $smtpUser -password $smtpPass + Add-CredentialsToDataTable -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "SMTP Configuration" -section "SMTP" -url $url -server $smtpServer -port $smtpPort -username $smtpUser -password $smtpPass } } } @@ -23903,17 +24505,22 @@ function Get-PwMachineConfig { if ($dtCredentials.Rows.Count -eq 0) { Write-Host "No credentials found." -ForegroundColor Red } else { - $dtCredentials | select Name, Section, URL, Server, Port, UserName, Password + $dtCredentials | select ComputerName, ShareName, UncFilePath, FileName, Section, ObjectName, TargetURL, TargetServer, TargetPort, Database, Domain, Username, Password, PasswordEnc } } +# Get-PwMachineConfig -FilePath "C:\tools\Sample Configuration Files\configs\machine.config" -ComputerName 'computer' -ShareName 'share' -FileName 'file.txt' -UncFilePath '\\computer\share\file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: krb5.conf function Get-Pwkrb5Conf { [CmdletBinding()] param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Initialize a hashtable to store extracted values @@ -23969,19 +24576,37 @@ function Get-Pwkrb5Conf { # Output the extracted configuration as a PowerShell object [PSCustomObject]@{ - Domain = $configData.Domain - Server = $configData.Server - Username = $configData.Username - Password = $configData.Password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $configData.Server + TargetPort = "NA" + Database = "NA" + Domain = $configData.Domain + Username = $configData.Username + Password = $configData.Password + PasswordEnc = "NA" + KeyFilePath = "NA" } } +# Get-Pwkrb5Conf -FilePath "C:\tools\Sample Configuration Files\configs\krb5.conf" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: jboss-cli.xml # Define the function to extract username and password from a jboss-cli.xml file and return an object function Get-PwJbossCliConfig { param ( - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -23999,16 +24624,36 @@ function Get-PwJbossCliConfig { # Return a PowerShell object with the username and password return [pscustomobject]@{ - Username = $username - Password = $password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } } +# Get-PwJbossCliConfig -FilePath "C:\tools\Sample Configuration Files\configs\jboss-cli.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: .htpasswd function Get-PwHtpasswd { param ( - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -24030,8 +24675,22 @@ function Get-PwHtpasswd { if ($parts.Length -eq 2) { # Create a custom object for each user $userObj = [pscustomobject]@{ - Username = $parts[0] - PasswordHash = $parts[1] + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $parts[0] + Password = "NA" + PasswordEnc = $parts[1] + KeyFilePath = "NA" } # Add the user object to the array $users += $userObj @@ -24041,13 +24700,19 @@ function Get-PwHtpasswd { # Output the results return $users } +# Get-PwHtpasswd -FilePath "C:\tools\Sample Configuration Files\configs\.htpasswd" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: dbxdrivers.ini and generic # Function to extract credentials from the file function Get-PwDbxDriverIni { param ( - [string]$filePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -24074,9 +24739,22 @@ function Get-PwDbxDriverIni { # If we have collected both a username and password, store the credentials if ($currentUsername -and $currentPassword) { $credentials += [PSCustomObject]@{ - Section = $currentSection - Username = $currentUsername - Password = $currentPassword + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = $currentSection + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $currentUsername + Password = $currentPassword + PasswordEnc = "NA" + KeyFilePath = "NA" } } @@ -24100,24 +24778,46 @@ function Get-PwDbxDriverIni { # If the last section contains credentials, add them to the array if ($currentUsername -and $currentPassword) { $credentials += [PSCustomObject]@{ - Section = $currentSection - Username = $currentUsername - Password = $currentPassword + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = $currentSection + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $currentUsername + Password = $currentPassword + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Return the results return $credentials } +# Get-PwDbxDriverIni -FilePath $filePath "C:\tools\Sample Configuration Files\configs\dbxdrivers.ini" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: context.xml # Function to extract credentials from a given context.xml file function Get-PwContextXML { param ( - [string]$contextXmlPath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) + # Set file path + $contextXmlPath = $FilePath + # Check if the file exists if (-Not (Test-Path $contextXmlPath)) { Write-Host "File not found: $contextXmlPath" @@ -24133,20 +24833,39 @@ function Get-PwContextXML { # Create a PowerShell object to hold the extracted information $credentials = [PSCustomObject]@{ - Username = $username - Password = $password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } # Return the credentials object return $credentials } +# Get-PwContextXML -FilePath "C:\tools\Sample Configuration Files\configs\context.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: config.xml function Get-PwJenkinsConfig { param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Ensure the file exists @@ -24172,95 +24891,214 @@ function Get-PwJenkinsConfig { # Create and return the result as a PowerShell object $result = [PSCustomObject]@{ - Username = $fullName - PasswordHash = $passwordHash + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $fullName + Password = $passwordHash + PasswordEnc = "NA" + KeyFilePath = "NA" } return $result } +# Get-PwJenkinsConfig -FilePath "C:\tools\Sample Configuration Files\configs\config.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: bootstrap.ini function Get-PwBootstrapConfig { param ( - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Read all lines from the provided file path $iniContent = Get-Content -Path $FilePath - # Initialize a hash table to store key-value pairs - $fields = @{ - Username = $null - Password = $null - Public = $null - Private = $null - Key = $null - Secret = $null - } + # Initialize an array to store custom objects for each key-value pair + $output = @() # Loop through each line and look for the required fields foreach ($line in $iniContent) { if ($line -match 'username\s*=\s*(.*)') { - $fields['Username'] = $matches[1].Trim() + $Username = $matches[1].Trim() } + if ($line -match 'password\s*=\s*(.*)') { - $fields['Password'] = $matches[1].Trim() + $output += [PSCustomObject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $Username + Password = $matches[1].Trim() + PasswordEnc = "NA" + KeyFilePath = "NA" + } } + if ($line -match 'public\s*=\s*(.*)') { - $fields['Public'] = $matches[1].Trim() + $output += [PSCustomObject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = 'Public' + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = "NA" + Password = $matches[1].Trim() + PasswordEnc = "NA" + KeyFilePath = "NA" + } } if ($line -match 'private\s*=\s*(.*)') { - $fields['Private'] = $matches[1].Trim() + $output += [PSCustomObject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = 'Private' + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = "NA" + Password = $matches[1].Trim() + PasswordEnc = "NA" + KeyFilePath = "NA" + } } if ($line -match 'key\s*=\s*(.*)') { - $fields['Key'] = $matches[1].Trim() + $output += [PSCustomObject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = 'Key' + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = "NA" + Password = $matches[1].Trim() + PasswordEnc = "NA" + KeyFilePath = "NA" + } } if ($line -match 'secret\s*=\s*(.*)') { - $fields['Secret'] = $matches[1].Trim() + $output += [PSCustomObject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = 'Secret' + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = "NA" + Password = $matches[1].Trim() + PasswordEnc = "NA" + KeyFilePath = "NA" + } } } - # Convert the hash table into a custom PowerShell object - $configObject = [PSCustomObject]$fields - - # Output the custom object - return $configObject + # Output the array of custom objects + return $output } +# Get-PwBootstrapConfig -FilePath "C:\tools\Sample Configuration Files\configs\bootstrap.ini" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: app.config # Function to parse configuration files for credentials function Get-PwAppconfig { param ( - [string]$configFilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) + # Set filepath + $configFilePath = $FilePath + # Load the config file as XML [xml]$configXml = Get-Content $configFilePath # Initialize a DataTable to store results $dtCredentials = New-Object System.Data.DataTable - $null = $dtCredentials.Columns.Add("Name", [string]) + $null = $dtCredentials.Columns.Add("ComputerName", [string]) + $null = $dtCredentials.Columns.Add("ShareName", [string]) + $null = $dtCredentials.Columns.Add("UncFilePath", [string]) + $null = $dtCredentials.Columns.Add("FileName", [string]) $null = $dtCredentials.Columns.Add("Section", [string]) - $null = $dtCredentials.Columns.Add("URL", [string]) - $null = $dtCredentials.Columns.Add("Server", [string]) - $null = $dtCredentials.Columns.Add("Port", [string]) - $null = $dtCredentials.Columns.Add("UserName", [string]) + $null = $dtCredentials.Columns.Add("ObjectName", [string]) + $null = $dtCredentials.Columns.Add("TargetURL", [string]) + $null = $dtCredentials.Columns.Add("TargetServer", [string]) + $null = $dtCredentials.Columns.Add("TargetPort", [string]) + $null = $dtCredentials.Columns.Add("Database", [string]) + $null = $dtCredentials.Columns.Add("Domain", [string]) + $null = $dtCredentials.Columns.Add("Username", [string]) $null = $dtCredentials.Columns.Add("Password", [string]) + $null = $dtCredentials.Columns.Add("PasswordEnc", [string]) + $null = $dtCredentials.Columns.Add("KeyFilePath", [string]) # Helper function to add rows to DataTable function Add-CredentialsToDataTable { param ( - [string]$name, + [string]$computerName, + [string]$shareName, + [string]$uncFilePath, + [string]$fileName, [string]$section, + [string]$name, [string]$url, [string]$server, [string]$port, [string]$username, - [string]$password + [string]$password, + [string]$passwordEnc = "NA" ) - $null = $dtCredentials.Rows.Add($name, $section, $url, $server, $port, $username, $password) + $null = $dtCredentials.Rows.Add($computerName, $shareName, $uncFilePath, $fileName, $section, $name, $url, $server, $port, $database, $domain, $username, $password, $passwordEnc) } # Dictionary to temporarily store related credentials @@ -24285,7 +25123,7 @@ function Get-PwAppconfig { # If both username and password are available, add them to the DataTable if ($credentialPairs[$name]["UserName"] -and $credentialPairs[$name]["Password"]) { - Add-CredentialsToDataTable -name $name -section $credentialPairs[$name]["Section"] ` + Add-CredentialsToDataTable -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name $name -section $credentialPairs[$name]["Section"] ` -url $credentialPairs[$name]["URL"] -server $credentialPairs[$name]["Server"] ` -port $credentialPairs[$name]["Port"] -username $credentialPairs[$name]["UserName"] ` -password $credentialPairs[$name]["Password"] @@ -24305,17 +25143,17 @@ function Get-PwAppconfig { # Handle specific cases for OAuth, API, and WebClient settings switch ($key) { - "OAuthServiceUrl" { Add-CredentialPair -name "OAuth" -section $section -key "URL" -value $value } - "ClientId" { Add-CredentialPair -name "OAuth" -section $section -key "UserName" -value $value } - "ClientSecret" { Add-CredentialPair -name "OAuth" -section $section -key "Password" -value $value } - "ServiceUrl" { Add-CredentialPair -name "WebClient" -section $section -key "URL" -value $value } - "ServiceUserName" { Add-CredentialPair -name "WebClient" -section $section -key "UserName" -value $value } - "ServicePassword" { Add-CredentialPair -name "WebClient" -section $section -key "Password" -value $value } - "ApiEndpoint" { Add-CredentialPair -name "API" -section $section -key "URL" -value $value } - "ApiUserName" { Add-CredentialPair -name "API" -section $section -key "UserName" -value $value } - "ApiPassword" { Add-CredentialPair -name "API" -section $section -key "Password" -value $value } - "ApplicationUsername" { Add-CredentialPair -name "Application" -section $section -key "UserName" -value $value } - "ApplicationPassword" { Add-CredentialPair -name "Application" -section $section -key "Password" -value $value } + "OAuthServiceUrl" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "OAuth" -section $section -key "URL" -value $value } + "ClientId" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "OAuth" -section $section -key "UserName" -value $value } + "ClientSecret" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "OAuth" -section $section -key "Password" -value $value } + "ServiceUrl" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "WebClient" -section $section -key "URL" -value $value } + "ServiceUserName" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "WebClient" -section $section -key "UserName" -value $value } + "ServicePassword" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "WebClient" -section $section -key "Password" -value $value } + "ApiEndpoint" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "API" -section $section -key "URL" -value $value } + "ApiUserName" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "API" -section $section -key "UserName" -value $value } + "ApiPassword" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "API" -section $section -key "Password" -value $value } + "ApplicationUsername" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "Application" -section $section -key "UserName" -value $value } + "ApplicationPassword" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "Application" -section $section -key "Password" -value $value } } } } @@ -24330,9 +25168,9 @@ function Get-PwAppconfig { # Handle specific cases for custom service credentials switch ($key) { - "ServiceUrl" { Add-CredentialPair -name "CustomService" -section $section -key "URL" -value $value } - "UserName" { Add-CredentialPair -name "CustomService" -section $section -key "UserName" -value $value } - "Password" { Add-CredentialPair -name "CustomService" -section $section -key "Password" -value $value } + "ServiceUrl" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "CustomService" -section $section -key "URL" -value $value } + "UserName" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "CustomService" -section $section -key "UserName" -value $value } + "Password" { Add-CredentialPair -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "CustomService" -section $section -key "Password" -value $value } } } } @@ -24373,7 +25211,7 @@ function Get-PwAppconfig { # Add row to the DataTable if username and password exist if ($user -and $password) { - Add-CredentialsToDataTable -name $name -section "ConnectionStrings ($providerName)" -url $url -server $server -port $port -username $user -password $password + Add-CredentialsToDataTable -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name $name -section "ConnectionStrings ($providerName)" -url $url -server $server -port $port -username $user -password $password } } } @@ -24388,7 +25226,7 @@ function Get-PwAppconfig { $url = "smtp://${smtpServer}:${smtpPort}" if ($smtpUser -and $smtpPass) { - Add-CredentialsToDataTable -name "SMTP Configuration" -section "SMTP" -url $url -server $smtpServer -port $smtpPort -username $smtpUser -password $smtpPass + Add-CredentialsToDataTable -computer $ComputerName -shareName $ShareName -fileName $FileName -uncFilePath $UncFilePath -name "SMTP Configuration" -section "SMTP" -url $url -server $smtpServer -port $smtpPort -username $smtpUser -password $smtpPass } } } @@ -24397,16 +25235,22 @@ function Get-PwAppconfig { if ($dtCredentials.Rows.Count -eq 0) { Write-Host "No credentials found." -ForegroundColor Red } else { - $dtCredentials | select Name, Section, URL, Server, Port, UserName, Password + $dtCredentials | select ComputerName, ShareName, UncFilePath, FileName, Section, ObjectName, TargetURL, TargetServer, TargetPort, Database, Domain, Username, Password, PasswordEnc } } +# Get-PwAppconfig -FilePath "C:\tools\Sample Configuration Files\configs\app.config" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: .pgpass function Get-PwPgPass { param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required + ) # Ensure the file exists @@ -24434,11 +25278,22 @@ function Get-PwPgPass { if ($fields.Length -eq 5) { # Create a custom object for each entry $credential = [PSCustomObject]@{ - Hostname = $fields[0] - Port = $fields[1] - Database = $fields[2] - Username = $fields[3] - Password = $fields[4] + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $fields[0] + TargetPort = $fields[1] + Database = $fields[2] + Domain = "NA" + Username = $fields[3] + Password = $fields[4] + PasswordEnc = "NA" + KeyFilePath = "NA" } # Add the credential object to the list @@ -24452,6 +25307,8 @@ function Get-PwPgPass { # Output the results as a PowerShell object return $credentialsList } +# Get-PwPgPass -FilePath "C:\tools\Sample Configuration Files\configs\.pgpass" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # This is for parsing group policy preference files and should support groups.xml, datasources.xml, drives.xml, printers.xml, scheduletasks.xml, and services.xml @@ -24469,10 +25326,16 @@ function Get-PwGPP { #> [CmdletBinding()] Param( - [Parameter(Mandatory=$false)] - [string]$InputFilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) + # Set path + $InputFilePath = $FilePath + # ---------------------------------------------------------------- # Function to decrypt cpassword # ---------------------------------------------------------------- @@ -24507,13 +25370,21 @@ function Get-PwGPP { # Setup data table to store GPP Information # ---------------------------------------------------------------- if ($InputFilePath) { - $TableGPPPasswords = New-Object System.Data.DataTable - $TableGPPPasswords.Columns.Add('NewName') | Out-Null - $TableGPPPasswords.Columns.Add('Changed') | Out-Null - $TableGPPPasswords.Columns.Add('UserName') | Out-Null - $TableGPPPasswords.Columns.Add('CPassword') | Out-Null - $TableGPPPasswords.Columns.Add('Password') | Out-Null - $TableGPPPasswords.Columns.Add('File') | Out-Null + $dtCredentials = New-Object System.Data.DataTable + $null = $dtCredentials.Columns.Add("ComputerName", [string]) + $null = $dtCredentials.Columns.Add("ShareName", [string]) + $null = $dtCredentials.Columns.Add("UncFilePath", [string]) + $null = $dtCredentials.Columns.Add("FileName", [string]) + $null = $dtCredentials.Columns.Add("Section", [string]) + $null = $dtCredentials.Columns.Add("ObjectName", [string]) + $null = $dtCredentials.Columns.Add("TargetURL", [string]) + $null = $dtCredentials.Columns.Add("TargetServer", [string]) + $null = $dtCredentials.Columns.Add("TargetPort", [string]) + $null = $dtCredentials.Columns.Add("Database", [string]) + $null = $dtCredentials.Columns.Add("Username", [string]) + $null = $dtCredentials.Columns.Add("Password", [string]) + $null = $dtCredentials.Columns.Add("PasswordEnc", [string]) + $null = $dtCredentials.Columns.Add("KeyFilePath", [string]) # ---------------------------------------------------------------- # Find, parse, decrypt, and display results from XML files @@ -24543,8 +25414,24 @@ function Get-PwGPP { [string]$CPassword = $_.Properties.cpassword [string]$Password = Get-DecryptedCpassword $CPassword [datetime]$Changed = $_.Changed - [string]$NewName = "" - $TableGPPPasswords.Rows.Add($NewName, $Changed, $Username, $CPassword, $Password, $FileFullName) | Out-Null + [string]$NewName = "" + $dtCredentials.Rows.Add( + $ComputerName, # For "ComputerName" + $ShareName, # For "ShareName" + $UncFilePath, # For "UncFilePath" + $FileName, # For "FileName" + "NA", # For "Section" + "NA", # For "ObjectName" + "NA", # For "TargetURL" + "NA", # For "TargetServer" + "NA", # For "TargetPort" + "NA", # For "Database" + $Username, # For "Username" + $Password, # For "Password" + $CPassword, # For "PasswordEnc" + "NA" # For "KeyFilePath" + ) | Out-Null + } } @@ -24556,7 +25443,22 @@ function Get-PwGPP { [string]$Password = Get-DecryptedCpassword $CPassword [datetime]$Changed = $_.Changed [string]$NewName = $_.Properties.newname - $TableGPPPasswords.Rows.Add($NewName, $Changed, $Username, $CPassword, $Password, $FileFullName) | Out-Null + $dtCredentials.Rows.Add( + $ComputerName, # For "ComputerName" + $ShareName, # For "ShareName" + $UncFilePath, # For "UncFilePath" + $FileName, # For "FileName" + "NA", # For "Section" + "NA", # For "ObjectName" + "NA", # For "TargetURL" + "NA", # For "TargetServer" + "NA", # For "TargetPort" + "NA", # For "Database" + $Username, # For "Username" + $Password, # For "Password" + $CPassword, # For "PasswordEnc" + "NA" # For "KeyFilePath" + ) | Out-Null } } @@ -24568,7 +25470,22 @@ function Get-PwGPP { [string]$Password = Get-DecryptedCpassword $CPassword [datetime]$Changed = $_.Changed [string]$NewName = "" - $TableGPPPasswords.Rows.Add($NewName, $Changed, $Username, $CPassword, $Password, $FileFullName) | Out-Null + $dtCredentials.Rows.Add( + $ComputerName, # For "ComputerName" + $ShareName, # For "ShareName" + $UncFilePath, # For "UncFilePath" + $FileName, # For "FileName" + "NA", # For "Section" + "NA", # For "ObjectName" + "NA", # For "TargetURL" + "NA", # For "TargetServer" + "NA", # For "TargetPort" + "NA", # For "Database" + $Username, # For "Username" + $Password, # For "Password" + $CPassword, # For "PasswordEnc" + "NA" # For "KeyFilePath" + ) | Out-Null } } @@ -24580,7 +25497,22 @@ function Get-PwGPP { [string]$Password = Get-DecryptedCpassword $CPassword [datetime]$Changed = $_.Changed [string]$NewName = "" - $TableGPPPasswords.Rows.Add($NewName, $Changed, $Username, $CPassword, $Password, $FileFullName) | Out-Null + $dtCredentials.Rows.Add( + $ComputerName, # For "ComputerName" + $ShareName, # For "ShareName" + $UncFilePath, # For "UncFilePath" + $FileName, # For "FileName" + "NA", # For "Section" + "NA", # For "ObjectName" + "NA", # For "TargetURL" + "NA", # For "TargetServer" + "NA", # For "TargetPort" + "NA", # For "Database" + $Username, # For "Username" + $Password, # For "Password" + $CPassword, # For "PasswordEnc" + "NA" # For "KeyFilePath" + ) | Out-Null } } @@ -24592,7 +25524,22 @@ function Get-PwGPP { [string]$Password = Get-DecryptedCpassword $CPassword [datetime]$Changed = $_.Changed [string]$NewName = "" - $TableGPPPasswords.Rows.Add($NewName, $Changed, $Username, $CPassword, $Password, $FileFullName) | Out-Null + $dtCredentials.Rows.Add( + $ComputerName, # For "ComputerName" + $ShareName, # For "ShareName" + $UncFilePath, # For "UncFilePath" + $FileName, # For "FileName" + "NA", # For "Section" + "NA", # For "ObjectName" + "NA", # For "TargetURL" + "NA", # For "TargetServer" + "NA", # For "TargetPort" + "NA", # For "Database" + $Username, # For "Username" + $Password, # For "Password" + $CPassword, # For "PasswordEnc" + "NA" # For "KeyFilePath" + ) | Out-Null } } @@ -24604,7 +25551,22 @@ function Get-PwGPP { [string]$Password = Get-DecryptedCpassword $CPassword [datetime]$Changed = $_.Changed [string]$NewName = "" - $TableGPPPasswords.Rows.Add($NewName, $Changed, $Username, $CPassword, $Password, $FileFullName) | Out-Null + $dtCredentials.Rows.Add( + $ComputerName, # For "ComputerName" + $ShareName, # For "ShareName" + $UncFilePath, # For "UncFilePath" + $FileName, # For "FileName" + "NA", # For "Section" + "NA", # For "ObjectName" + "NA", # For "TargetURL" + "NA", # For "TargetServer" + "NA", # For "TargetPort" + "NA", # For "Database" + $Username, # For "Username" + $Password, # For "Password" + $CPassword, # For "PasswordEnc" + "NA" # For "KeyFilePath" + ) | Out-Null } } } @@ -24616,7 +25578,7 @@ function Get-PwGPP { } # Display results - $TableGPPPasswords + $dtCredentials } # Allow users to encrypt passwords @@ -24643,13 +25605,23 @@ function Get-PwGPP { return $EncryptedCpassword } } +# Get-PwGPP -FilePath "C:\tools\Sample Configuration Files\configs\Drives.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' +# Get-PwGPP -FilePath "C:\tools\Sample Configuration Files\configs\DataSources.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' +# Get-PwGPP -FilePath "C:\tools\Sample Configuration Files\configs\Groups.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' +# Get-PwGPP -FilePath "C:\tools\Sample Configuration Files\configs\Services.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' +# Get-PwGPP -FilePath "C:\tools\Sample Configuration Files\configs\ScheduledTasks.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' +# Get-PwGPP -FilePath "C:\tools\Sample Configuration Files\configs\Printers.xml" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: *dtsx function Get-PwSsisDtsx { param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -24680,11 +25652,22 @@ function Get-PwSsisDtsx { $connString = $dbConnection.SelectSingleNode("DTS:Property[@DTS:Name='ConnectionString']", $namespaceManager).'#text' if ($connString -match "Data Source=([^;]+);.*User ID=([^;]+);.*Password=([^;]+);") { $credentials += [pscustomobject]@{ - ConnectionType = "Database" - Server = $matches[1] - Port = "N/A" # OLEDB typically does not specify a port - Username = $matches[2] - Password = $matches[3] + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "Database" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $matches[1] + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $matches[2] + Password = $matches[3] + PasswordEnc = "NA" + KeyFilePath = "NA" } } } @@ -24698,11 +25681,22 @@ function Get-PwSsisDtsx { $password = $ftpConnection.SelectSingleNode("DTS:Property[@DTS:Name='ServerPassword']", $namespaceManager).'#text' $credentials += [pscustomobject]@{ - ConnectionType = "FTP" - Server = $server - Port = $port - Username = $username - Password = $password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "FTP" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $server + TargetPort = $port + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } } @@ -24715,24 +25709,40 @@ function Get-PwSsisDtsx { $password = $smtpConnection.SelectSingleNode("DTS:Property[@DTS:Name='Password']", $namespaceManager).'#text' $credentials += [pscustomobject]@{ - ConnectionType = "SMTP" - Server = $server - Port = $port - Username = $username - Password = $password + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "SMTP" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = $server + TargetPort = $port + Database = "NA" + Domain = "NA" + Username = $username + Password = $password + PasswordEnc = "NA" + KeyFilePath = "NA" } } # Return all credentials return $credentials } +# Get-PwSsisDtsx -FilePath "C:\tools\Sample Configuration Files\configs\example.dtsx" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + # Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) # Intended input: all .rdp function Get-PwRdpInfo { param ( - [Parameter(Mandatory = $true)] - [string]$FilePath + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required ) # Check if the file exists @@ -24768,7 +25778,7 @@ function Get-PwRdpInfo { # Use DPAPI to decrypt the password $decryptedPassword = [System.Text.Encoding]::Unicode.GetString([System.Security.Cryptography.ProtectedData]::Unprotect($passwordBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)) } catch { - Write-Warning "Unable to decrypt password: $_" + # Write-Warning "Unable to decrypt password: $_" $decryptedPassword = "Unable to decrypt; must run on target system" } } else { @@ -24778,10 +25788,66 @@ function Get-PwRdpInfo { # Create a PowerShell object to return the results $result = [PSCustomObject]@{ - Username = $username - EncryptedPassword = $encryptedPassword - DecryptedPassword = $decryptedPassword + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = $username + Password = $decryptedPassword + PasswordEnc = $encryptedPassword + KeyFilePath = "NA" } return $result } +# Get-PwRdpInfo -FilePath "C:\tools\Sample Configuration Files\configs\example.rdp" -ComputerName 'computer' -ShareName 'sharename' -UncFilePath '\\computer\sharename\file.txt' -FileName 'file.txt' + +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) +# Intended input: all private key files +function Get-PrivateKeyFilePath { + param ( + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required + ) + + # Check if the file exists + if (-not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Create a PowerShell object to return the results + $result = [PSCustomObject]@{ + + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = "NA" + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = "NA" + Password = "NA" + PasswordEnc = "NA" + KeyFilePath = $FilePath + } + + return $result +} + +