diff --git a/Scripts/ConfigParsers/parse-gppfiles.ps1 b/Scripts/ConfigParsers/parse-gppfiles.ps1 new file mode 100644 index 0000000..f3de552 --- /dev/null +++ b/Scripts/ConfigParsers/parse-gppfiles.ps1 @@ -0,0 +1,695 @@ +# 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 + +function Get-GPPPasswordMod { +<# +.SYNOPSIS + Retrieves plaintext passwords from specified Group Policy XML files and provides functionality to encrypt passwords. + +.DESCRIPTION + This function processes specified GPP XML files and retrieves plaintext passwords for accounts pushed through Group Policy Preferences. + It also provides a method to encrypt passwords for use in XML files. + +.EXAMPLE + PS C:\> Get-GPPPasswordMod -InputFilePath "\\192.168.1.1\sysvol\demo.com\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\USER\Preferences" +#> + [CmdletBinding()] + Param( + [Parameter(Mandatory=$false)] + [string]$InputFilePath + ) + + # ---------------------------------------------------------------- + # Function to decrypt cpassword + # ---------------------------------------------------------------- + function Get-DecryptedCpassword { + [CmdletBinding()] + Param ( + [string] $Cpassword + ) + + try { + # Append padding + $Mod = ($Cpassword.length % 4) + switch ($Mod) { + '1' { $Cpassword = $Cpassword.Substring(0,$Cpassword.Length -1) } + '2' { $Cpassword += ('=' * (4 - $Mod)) } + '3' { $Cpassword += ('=' * (4 - $Mod)) } + } + $Base64Decoded = [Convert]::FromBase64String($Cpassword) + $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider + [Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b) + $AesIV = New-Object Byte[]($AesObject.IV.Length) + $AesObject.IV = $AesIV + $AesObject.Key = $AesKey + $DecryptorObject = $AesObject.CreateDecryptor() + [Byte[]] $OutBlock = $DecryptorObject.TransformFinalBlock($Base64Decoded, 0, $Base64Decoded.length) + return [System.Text.UnicodeEncoding]::Unicode.GetString($OutBlock) + } catch { Write-Error $Error[0] } + } + + + # ---------------------------------------------------------------- + # 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 + + # ---------------------------------------------------------------- + # Find, parse, decrypt, and display results from XML files + # ---------------------------------------------------------------- + $XmlFiles = Get-ChildItem -Path $InputFilePath -Recurse -ErrorAction SilentlyContinue -Include 'Groups.xml','Services.xml','ScheduledTasks.xml','DataSources.xml','Printers.xml','Drives.xml' + + # Parse GPP config files + $XmlFiles | ForEach-Object { + $FileFullName = $_.FullName + $FileName = $_.Name + + # Read the file content as a string + $fileContentString = Get-Content -Path "$FileFullName" -Raw + + try { + # Attempt to load the XML content + [xml]$FileContent = [xml]$fileContentString + } catch { + Write-Error "Failed to parse XML in file '$FileFullName'. Error: $_" + return + } + + # Process Drives.xml + if ($FileName -eq "Drives.xml") { + $FileContent.Drives.Drive | ForEach-Object { + [string]$Username = $_.Properties.username + [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 + } + } + + # Process Groups.xml + if ($FileName -eq "Groups.xml") { + $FileContent.Groups.User | ForEach-Object { + [string]$Username = $_.Properties.username + [string]$CPassword = $_.Properties.cpassword + [string]$Password = Get-DecryptedCpassword $CPassword + [datetime]$Changed = $_.Changed + [string]$NewName = $_.Properties.newname + $TableGPPPasswords.Rows.Add($NewName, $Changed, $Username, $CPassword, $Password, $FileFullName) | Out-Null + } + } + + # Process Services.xml + if ($FileName -eq "Services.xml") { + $FileContent.NTServices.NTService | ForEach-Object { + [string]$Username = $_.Properties.accountname + [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 + } + } + + # Process ScheduledTasks.xml + if ($FileName -eq "ScheduledTasks.xml") { + $FileContent.ScheduledTasks.Task | ForEach-Object { + [string]$Username = $_.Properties.runas + [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 + } + } + + # Process DataSources.xml + if ($FileName -eq "DataSources.xml") { + $FileContent.DataSources.DataSource | ForEach-Object { + [string]$Username = $_.Properties.username + [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 + } + } + + # Process Printers.xml + if ($FileName -eq "Printers.xml") { + $FileContent.Printers.SharedPrinter | ForEach-Object { + [string]$Username = $_.Properties.username + [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 + } + } + } + + # Check if anything was found + if (-not $XmlFiles) { + throw 'No preference files found.' + return + } + + # Display results + $TableGPPPasswords + } + + # Allow users to encrypt passwords + function Set-EncryptedCpassword { + [CmdletBinding()] + Param ( + [Parameter(Mandatory=$true)] + [string]$Password + ) + + # Create a new AES .NET Crypto Object + $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider + [Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b) + $AesIV = New-Object Byte[]($AesObject.IV.Length) + $AesObject.IV = $AesIV + $AesObject.Key = $AesKey + $EncryptorObject = $AesObject.CreateEncryptor() + + # Convert password to byte array and encrypt + [Byte[]] $InputBytes = [System.Text.Encoding]::Unicode.GetBytes($Password) + [Byte[]] $EncryptedBytes = $EncryptorObject.TransformFinalBlock($InputBytes, 0, $InputBytes.Length) + $EncryptedCpassword = [Convert]::ToBase64String($EncryptedBytes) + + return $EncryptedCpassword + } +} + +# Example path to the directory containing the GPP XML files +$pathToGPPFiles = "c:\temp\configs\ScheduledTasks.xml" + +# Call the function +$gppPasswords = Get-GPPPasswordMod -InputFilePath $pathToGPPFiles + +# Display the results +$gppPasswords + + +<# Bonus function for encrypting password + + # ---------------------------------------------------------------- + # Function to encrypt a password + # ---------------------------------------------------------------- + function Set-EncryptedCpassword { + [CmdletBinding()] + Param ( + [Parameter(Mandatory=$true)] + [string]$Password + ) + + # Create a new AES .NET Crypto Object + $AesObject = New-Object System.Security.Cryptography.AesCryptoServiceProvider + [Byte[]] $AesKey = @(0x4e,0x99,0x06,0xe8,0xfc,0xb6,0x6c,0xc9,0xfa,0xf4,0x93,0x10,0x62,0x0f,0xfe,0xe8,0xf4,0x96,0xe8,0x06,0xcc,0x05,0x79,0x90,0x20,0x9b,0x09,0xa4,0x33,0xb6,0x6c,0x1b) + $AesIV = New-Object Byte[]($AesObject.IV.Length) + $AesObject.IV = $AesIV + $AesObject.Key = $AesKey + $EncryptorObject = $AesObject.CreateEncryptor() + + # Convert password to byte array and encrypt + [Byte[]] $InputBytes = [System.Text.Encoding]::Unicode.GetBytes($Password) + [Byte[]] $EncryptedBytes = $EncryptorObject.TransformFinalBlock($InputBytes, 0, $InputBytes.Length) + $EncryptedCpassword = [Convert]::ToBase64String($EncryptedBytes) + + return $EncryptedCpassword + } + + $plainTextPassword = "MyAwesomePassword!" + $encryptedPassword = Set-EncryptedCpassword -Password $plainTextPassword + Write-Output $encryptedPassword + +#> + +<# Printers.xml + + + + + + + + + + + + + + +#> + + +<# ScheduledTasks.xml + + + + + + + + + + + + + + + + + + + + + + + WIN-P3LTV7KC6IO\Administrator + Demo + + + + %LogonDomain%\%LogonUser + InteractiveToken + LeastPrivilege + + + + + PT10M + PT1H + true + true + + IgnoreNew + true + true + true + true + true + true + true + false + true + true + P3D + 7 + + PT1M + 3 + + + + + 2008-05-28T14:06:04 + true + + + 2008-05-28T14:06:08 + true + + 1 + + + + 2008-05-28T14:06:11 + true + + 1 + + + + + + + + 2008-05-28T14:06:16 + true + + + 1 + + + + + + + + true + + + true + + + true + + + true + + + true + RemoteConnect + + + true + RemoteConnect + + + true + SessionLock + + + true + SessionUnlock + + + + + a + b + c + + + a + b + c + d + + + e + + f + + + aa + bb + + + + + + + + + + + + WIN-P3LTV7KC6IO\Administrator + Demo ImdTask + + + + %LogonDomain%\%LogonUser + InteractiveToken + HighestAvailable + + + + + PT10M + PT1H + true + false + + IgnoreNew + true + true + true + false + false + true + true + false + false + false + P3D + 7 + + + calc.exe + + + + + + + +#> + +<# Services.xml + + + + + + + + + +#> + +<# Drives.xml + + + + + + + + +#> + +<# Groups.xml + + + + + + + + + +#> + +<# DataSources.xml + + + + + + + + + + + + + + + + + + + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-.pgpass.ps1 b/Scripts/ConfigParsers/parser-.pgpass.ps1 new file mode 100644 index 0000000..95ebcf2 --- /dev/null +++ b/Scripts/ConfigParsers/parser-.pgpass.ps1 @@ -0,0 +1,74 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-PgPassCredentials { + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Ensure the file exists + if (-Not (Test-Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the .pgpass file + $pgpassEntries = Get-Content -Path $FilePath + + # Array to store the extracted credentials + $credentialsList = @() + + # Loop through each line in the .pgpass file + foreach ($entry in $pgpassEntries) { + # Skip comments and empty lines + if ($entry -match '^\s*#' -or $entry -match '^\s*$') { + continue + } + + # Split the line by colon, expecting the format: hostname:port:database:username:password + $fields = $entry -split ':' + + 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] + } + + # Add the credential object to the list + $credentialsList += $credential + } + else { + Write-Warning "Invalid format in entry: $entry" + } + } + + # Output the results as a PowerShell object + return $credentialsList +} + +# Example usage: +$pgpassCredentials = Get-PgPassCredentials -FilePath "c:\temp\configs\.pgpass" +$pgpassCredentials + +<# .pgpass file - used for postgres + +# Format: hostname:port:database:username:password + +# Local database connection +localhost:5432:mydatabase:myuser:mypassword + +# Remote database connection +remote.server.com:5432:anotherdb:anotheruser:anotherpassword + +# Default connection for any database on localhost +localhost:*:*:defaultuser:defaultpassword + +# Wildcard example: Any database and any user connecting to localhost +localhost:*:*:*:supersecretpassword + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-SiteManager.xml.ps1 b/Scripts/ConfigParsers/parser-SiteManager.xml.ps1 new file mode 100644 index 0000000..3f864a8 --- /dev/null +++ b/Scripts/ConfigParsers/parser-SiteManager.xml.ps1 @@ -0,0 +1,111 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +# Function to check if a string is a valid base64-encoded string +function IsBase64String { + param ([string]$string) + if ($string -match '^[a-zA-Z0-9\+/]*={0,2}$' -and ($string.Length % 4 -eq 0)) { + return $true + } + return $false +} + +# Function to process the SiteManager.xml file and extract server information +function Get-SiteManagerServerInfo { + param ( + [string]$xmlFilePath + ) + + # Check if the file exists + if (-not (Test-Path $xmlFilePath)) { + Write-Error "File not found: $xmlFilePath" + return + } + + # Load the XML file + $xml = [xml](Get-Content $xmlFilePath) + + # Iterate through each server entry and extract relevant information + $xml.FileZilla3.Servers.Server | ForEach-Object { + $decodedPassword = "Invalid or not present" + + # Access the Pass element's inner text, ensuring it's properly treated as a string + [string]$base64Pass = $_.Pass.InnerText + # Check if the password is a valid base64 string before decoding + if ($base64Pass) { + try { + # Trim any extra whitespace from the base64 string + $cleanPass = $base64Pass.Trim() + $decodedPassword = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($cleanPass)) + } catch { + $decodedPassword = "Error decoding password: $_" + } + } + + # Output the server details + [pscustomobject]@{ + Server = $_.Host + Port = $_.Port + Username = $_.User + Password = $decodedPassword + } + } +} + +# Example usage +$xmlFilePath = "c:\temp\configs\SiteManager.xml" +Get-SiteManagerServerInfo -xmlFilePath $xmlFilePath + + + + +<# SiteManager.xml + + + + + + ftp.example.com + 21 + 0 + 0 + username + SGVsbG9QYXNzd29yZA== + 1 + 0 + MODE_DEFAULT + 0 + Auto + 0 + My FTP Site + Sample FTP site for demonstration + + + 0 + 0 + + + + sftp.example.com + 22 + 1 + 1 + sftpuser + SGVsbG9QYXNzd29yZA== + 1 + 0 + MODE_DEFAULT + 1 + Auto + 0 + My SFTP Site + Sample SFTP site + + + 0 + 0 + + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-app.config.ps1 b/Scripts/ConfigParsers/parser-app.config.ps1 new file mode 100644 index 0000000..c00ceb1 --- /dev/null +++ b/Scripts/ConfigParsers/parser-app.config.ps1 @@ -0,0 +1,288 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +# Function to parse configuration files for credentials +function Get-CredentialsFromConfigFile { + 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 + } +} + +# Example of calling the function with a file path +Get-CredentialsFromConfigFile -configFilePath "c:\temp\configs\app.config" + + +<# app.config + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-bootstrap.ini.ps1 b/Scripts/ConfigParsers/parser-bootstrap.ini.ps1 new file mode 100644 index 0000000..83aa03e --- /dev/null +++ b/Scripts/ConfigParsers/parser-bootstrap.ini.ps1 @@ -0,0 +1,79 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-BootstrapConfig { + param ( + [string]$FilePath + ) + + # 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 + } + + # 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() + } + if ($line -match 'password\s*=\s*(.*)') { + $fields['Password'] = $matches[1].Trim() + } + if ($line -match 'public\s*=\s*(.*)') { + $fields['Public'] = $matches[1].Trim() + } + if ($line -match 'private\s*=\s*(.*)') { + $fields['Private'] = $matches[1].Trim() + } + if ($line -match 'key\s*=\s*(.*)') { + $fields['Key'] = $matches[1].Trim() + } + if ($line -match 'secret\s*=\s*(.*)') { + $fields['Secret'] = $matches[1].Trim() + } + } + + # Convert the hash table into a custom PowerShell object + $configObject = [PSCustomObject]$fields + + # Output the custom object + return $configObject +} + +# Example call using the example file path +$bootstrapIniPath = "c:\temp\configs\bootstrap.ini" +$config = Get-BootstrapConfig -FilePath $bootstrapIniPath + +# Output the result +$config + + +<# bootstrap.ini + +[GeneralSettings] +username=adminUser +password=P@ssw0rd123 +timeout=30 +loglevel=info +public=public +private=mysecret +secret=mysecret +key=mykey + +[DatabaseSettings] +db_name=my_database +db_host=localhost +db_port=3306 + +[NetworkSettings] +protocol=http +port=8080 + +#> diff --git a/Scripts/ConfigParsers/parser-config.xml.ps1 b/Scripts/ConfigParsers/parser-config.xml.ps1 new file mode 100644 index 0000000..10afd79 --- /dev/null +++ b/Scripts/ConfigParsers/parser-config.xml.ps1 @@ -0,0 +1,60 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-JenkinsUserCredentials { + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Ensure the file exists + if (-Not (Test-Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the XML content as plain text + $xmlText = Get-Content -Path $FilePath -Raw + + # Replace XML version 1.1 with 1.0 + $xmlText = $xmlText -replace "version='1.1'", "version='1.0'" + + # Now parse the XML + [xml]$xmlContent = [xml]$xmlText + + # Extract the full name (username) + $fullName = $xmlContent.user.fullName + + # Extract the password hash + $passwordHash = $xmlContent.user.properties.'hudson.security.HudsonPrivateSecurityRealm_-Details'.passwordHash + + # Create and return the result as a PowerShell object + $result = [PSCustomObject]@{ + Username = $fullName + PasswordHash = $passwordHash + } + + return $result +} + + +# Example usage: +$userCredentials = Get-JenkinsUserCredentials -FilePath "c:\temp\configs\config.xml" +$userCredentials + + +<# config.xml - jenkins - hudson.security.HudsonPrivateSecurityRealm - stored in $JENKINS_HOME/users/username/config.xml + +$JENKINS_HOME/users/username/config.xml + + + + John Doe + + + + #jbcrypt:$2a$10$D6wVozrLhk.TIq.jBBKZluIh/EqzpjCUJFT/mWUnyAO4EYmxk5.aK + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-context.xml.ps1 b/Scripts/ConfigParsers/parser-context.xml.ps1 new file mode 100644 index 0000000..c42c1ff --- /dev/null +++ b/Scripts/ConfigParsers/parser-context.xml.ps1 @@ -0,0 +1,53 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +# Function to extract credentials from a given context.xml file +function Get-CredentialsFromContextXml { + param ( + [string]$contextXmlPath + ) + + # Check if the file exists + if (-Not (Test-Path $contextXmlPath)) { + Write-Host "File not found: $contextXmlPath" + return + } + + # Load the XML file + [xml]$xml = Get-Content $contextXmlPath + + # Extract username and password from the Resource element + $username = $xml.Context.Resource | Where-Object { $_.name -eq 'jdbc/MyDB' } | Select-Object -ExpandProperty username + $password = $xml.Context.Resource | Where-Object { $_.name -eq 'jdbc/MyDB' } | Select-Object -ExpandProperty password + + # Create a PowerShell object to hold the extracted information + $credentials = [PSCustomObject]@{ + Username = $username + Password = $password + } + + # Return the credentials object + return $credentials +} + +# Example usage of the function +$exampleFilePath = "c:\temp\configs\context.xml" +$credentials = Get-CredentialsFromContextXml -contextXmlPath $exampleFilePath + +# Display the credentials +$credentials + +<# context.xml + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-db.ini.ps1 b/Scripts/ConfigParsers/parser-db.ini.ps1 new file mode 100644 index 0000000..64e2642 --- /dev/null +++ b/Scripts/ConfigParsers/parser-db.ini.ps1 @@ -0,0 +1,376 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +# Function to extract credentials from the file +function Get-CredentialsFromConfig { + param ( + [string]$filePath + ) + + # Check if the file exists + if (-Not (Test-Path $filePath)) { + Write-Host "File not found: $filePath" + return + } + + # Read the content of the file + $fileContent = Get-Content -Path $filePath + + # Create an array to hold the results + $credentials = @() + + # Initialize variables for the current section and credentials + $currentSection = "" + $currentUsername = "" + $currentPassword = "" + + # Loop through each line of the file + foreach ($line in $fileContent) { + # Check if the line indicates a new section (e.g., [DB2], [MySQL]) + if ($line -match '^\[.*\]$') { + # If we have collected both a username and password, store the credentials + if ($currentUsername -and $currentPassword) { + $credentials += [PSCustomObject]@{ + Section = $currentSection + Username = $currentUsername + Password = $currentPassword + } + } + + # Start a new section + $currentSection = $line.Trim('[]') + $currentUsername = "" + $currentPassword = "" + } + + # Check if the line contains a User_Name field + if ($line -match '^User_Name=(.*)$') { + $currentUsername = $matches[1].Trim() + } + + # Check if the line contains a Password field + if ($line -match '^Password=(.*)$') { + $currentPassword = $matches[1].Trim() + } + } + + # If the last section contains credentials, add them to the array + if ($currentUsername -and $currentPassword) { + $credentials += [PSCustomObject]@{ + Section = $currentSection + Username = $currentUsername + Password = $currentPassword + } + } + + # Return the results + return $credentials +} + +# Example call to the function with a sample file path +$filePath = "c:\temp\configs\dbxdrivers.ini" +$credentials = Get-CredentialsFromConfig -filePath $filePath + +# Display the results +$credentials | Format-Table -AutoSize + + +<# dbxdrivers.ini + +[Installed Drivers] +DB2=1 +Interbase=1 +MySQL=1 +Oracle=1 +Informix=1 +MSSQL=1 +UIB Interbase6=1 +UIB Interbase65=1 +UIB Interbase7=1 +UIB Interbase71=1 +UIB FireBird102=1 +UIB FireBird103=1 +UIB FireBird15=1 +UIB Yaffil=1 + +[DB2] +GetDriverFunc=getSQLDriverDB2 +LibraryName=dbexpdb2.dll +VendorLib=db2cli.dll +Database=DBNAME +User_Name=user +Password=password +BlobSize=-1 +ErrorResourceFile= +LocaleCode=0000 +DB2 TransIsolation=ReadCommited + +[Interbase] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpint.dll +VendorLib=gds32.dll +Database=database.gdb +RoleName=RoleName +User_Name=sysdba +Password=masterkey +ServerCharSet= +SQLDialect=1 +BlobSize=-1 +CommitRetain=False +WaitOnLocks=True +ErrorResourceFile= +LocaleCode=0000 +Interbase TransIsolation=ReadCommited +Trim Char=False + +[MySQL] +GetDriverFunc=getSQLDriverMYSQL +LibraryName=dbexpmysql.dll +VendorLib=libmysql.dll +HostName=localhost +Database=DBNAME +User_Name=root +Password= +BlobSize=-1 +ErrorResourceFile= +LocaleCode=0000 + +[Oracle] +GetDriverFunc=getSQLDriverORACLE +LibraryName=dbexpora.dll +VendorLib=oci.dll +DataBase=Database Name +User_Name=user +Password=password +BlobSize=-1 +ErrorResourceFile= +LocaleCode=0000 +Oracle TransIsolation=ReadCommited +RowsetSize=20 +OS Authentication=False +Multiple Transaction=False +Trim Char=False + +[Informix] +GetDriverFunc=getSQLDriverINFORMIX +LibraryName=dbexpinf.dll +VendorLib=isqlb09a.dll +HostName=ServerName +DataBase=Database Name +User_Name=user +Password=password +BlobSize=-1 +ErrorResourceFile= +LocaleCode=0000 +Informix TransIsolation=ReadCommited +Trim Char=False + +[MSSQL] +GetDriverFunc=getSQLDriverMSSQL +LibraryName=dbexpmss.dll +VendorLib=oledb +HostName=ServerName +DataBase=Database Name +User_Name=user +Password=password +BlobSize=-1 +ErrorResourceFile= +LocaleCode=0000 +MSSQL TransIsolation=ReadCommited +OS Authentication=False + + +[AutoCommit] +False=0 +True=1 + +[BlockingMode] +False=0 +True=1 + +[WaitOnLocks] +False=1 +True=0 + +[CommitRetain] +False=0 +True=1 + +[OS Authentication] +False=0 +True=1 + +[Multiple Transaction] +False=0 +True=1 + +[Trim Char] +False=0 +True=1 + +[DB2 TransIsolation] +DirtyRead=0 +ReadCommited=1 +RepeatableRead=2 + +[Interbase TransIsolation] +ReadCommited=1 +RepeatableRead=2 + +[Oracle TransIsolation] +DirtyRead=0 +ReadCommited=1 +RepeatableRead=2 + +[Informix TransIsolation] +DirtyRead=0 +ReadCommited=1 +RepeatableRead=2 + +[MSSQL TransIsolation] +DirtyRead=0 +ReadCommited=1 +RepeatableRead=2 + +[SQLDialect] +1=0 +2=1 +3=2 + +[UIB Interbase6] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpUIBint6.dll +VendorLib=GDS32.DLL +BlobSize=-1 +CommitRetain=False +Database=database.ib +ErrorResourceFile= +LocaleCode=0000 +Password=masterkey +RoleName=RoleName +ServerCharSet= +SQLDialect=3 +Interbase TransIsolation=ReadCommited +User_Name=SYSDBA +WaitOnLocks=True + +[UIB Interbase65] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpUIBint65.dll +VendorLib=GDS32.DLL +BlobSize=-1 +CommitRetain=False +Database=database.ib +ErrorResourceFile= +LocaleCode=0000 +Password=masterkey +RoleName=RoleName +ServerCharSet= +SQLDialect=3 +Interbase TransIsolation=ReadCommited +User_Name=SYSDBA +WaitOnLocks=True + +[UIB Interbase7] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpUIBint7.dll +VendorLib=GDS32.DLL +BlobSize=-1 +CommitRetain=False +Database=database.ib +ErrorResourceFile= +LocaleCode=0000 +Password=masterkey +RoleName=RoleName +ServerCharSet= +SQLDialect=3 +Interbase TransIsolation=ReadCommited +User_Name=SYSDBA +WaitOnLocks=True + +[UIB Interbase71] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpUIBint71.dll +VendorLib=GDS32.DLL +BlobSize=-1 +CommitRetain=False +Database=database.ib +ErrorResourceFile= +LocaleCode=0000 +Password=masterkey +RoleName=RoleName +ServerCharSet= +SQLDialect=3 +Interbase TransIsolation=ReadCommited +User_Name=SYSDBA +WaitOnLocks=True + +[UIB FireBird102] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpUIBfire102.dll +VendorLib=GDS32.DLL +BlobSize=-1 +CommitRetain=False +Database=database.fb +ErrorResourceFile= +LocaleCode=0000 +Password=masterkey +RoleName=RoleName +ServerCharSet= +SQLDialect=3 +Interbase TransIsolation=ReadCommited +User_Name=SYSDBA +WaitOnLocks=True + +[UIB FireBird103] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpUIBfire103.dll +VendorLib=GDS32.DLL +BlobSize=-1 +CommitRetain=False +Database=database.fb +ErrorResourceFile= +LocaleCode=0000 +Password=masterkey +RoleName=RoleName +ServerCharSet= +SQLDialect=3 +Interbase TransIsolation=ReadCommited +User_Name=SYSDBA +WaitOnLocks=True + +[UIB FireBird15] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpUIBfire15.dll +VendorLib=fbclient.dll +BlobSize=-1 +CommitRetain=False +Database=database.fb +ErrorResourceFile= +LocaleCode=0000 +Password=masterkey +RoleName=RoleName +ServerCharSet= +SQLDialect=3 +Interbase TransIsolation=ReadCommited +User_Name=SYSDBA +WaitOnLocks=True + +[UIB Yaffil] +GetDriverFunc=getSQLDriverINTERBASE +LibraryName=dbexpUIByaffil.dll +VendorLib=GDS32.DLL +BlobSize=-1 +CommitRetain=False +Database=database.gdb +ErrorResourceFile= +LocaleCode=0000 +Password=masterkey +RoleName=RoleName +ServerCharSet= +SQLDialect=3 +Interbase TransIsolation=ReadCommited +User_Name=SYSDBA +WaitOnLocks=True + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-example.rdp.ps1 b/Scripts/ConfigParsers/parser-example.rdp.ps1 new file mode 100644 index 0000000..8607aa1 --- /dev/null +++ b/Scripts/ConfigParsers/parser-example.rdp.ps1 @@ -0,0 +1,78 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-RdpCredentials { + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Check if the file exists + if (-not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the RDP file contents + $rdpContent = Get-Content -Path $FilePath + + # Initialize variables to store username and password + $username = "" + $encryptedPassword = "" + $decryptedPassword = "" + + # Parse the RDP file for username and encrypted password fields + foreach ($line in $rdpContent) { + if ($line -match "^username:s:(.+)$") { + $username = $matches[1] + } + if ($line -match "^password 51:b:(.+)$") { + $encryptedPassword = $matches[1] + } + } + + # Attempt to decrypt the password if it exists + if ($encryptedPassword) { + try { + # Convert the encrypted password from Base64 to byte array + $passwordBytes = [Convert]::FromBase64String($encryptedPassword) + + # 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: $_" + $decryptedPassword = "Unable to decrypt" + } + } else { + $encryptedPassword = "No password found" + $decryptedPassword = "No password found" + } + + # Create a PowerShell object to return the results + $result = [PSCustomObject]@{ + Username = $username + EncryptedPassword = $encryptedPassword + DecryptedPassword = $decryptedPassword + } + + return $result +} + + +# Example usage: +$credentials = Get-RdpCredentials -FilePath "c:\temp\configs\example.rdp" +$credentials + + +<# example.rdp - decryption needs to be done on the target system using dpapi + +screen mode id:i:2 +desktopwidth:i:1920 +desktopheight:i:1080 +session bpp:i:32 +winposstr:s:0,3,0,0,800,600 +full address:s:yourserver.com +username:s:YourUsername +password 51:b:encrypted_password_value + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-htpasswd.ps1 b/Scripts/ConfigParsers/parser-htpasswd.ps1 new file mode 100644 index 0000000..e6415ad --- /dev/null +++ b/Scripts/ConfigParsers/parser-htpasswd.ps1 @@ -0,0 +1,50 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-HtpasswdContent { + param ( + [string]$FilePath + ) + + # Check if the file exists + if (-Not (Test-Path $FilePath)) { + Write-Error "File not found at path: $FilePath" + return + } + + # Read the file contents + $lines = Get-Content $FilePath + + # Initialize an array to store user objects + $users = @() + + # Process each line + foreach ($line in $lines) { + # Split each line into username and hashed password + $parts = $line -split ':', 2 + if ($parts.Length -eq 2) { + # Create a custom object for each user + $userObj = [pscustomobject]@{ + Username = $parts[0] + PasswordHash = $parts[1] + } + # Add the user object to the array + $users += $userObj + } + } + + # Output the results + return $users +} + +# Example usage +$result = Get-HtpasswdContent -FilePath "c:\temp\configs\.htpasswd" +$result + +<# .htpasswd + +user1:$apr1$5lRQ1y3v$pmOQf9/fNVE5dTtQDBl9D1 +user2:$apr1$Jd9UE91p$J/H8G9HSvj5l8LKQ2qfd3. +admin:$apr1$GZJoqjNF$wl8IjDhZC84z5Bb4wHOv50 + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-jboss-cli.xml.ps1 b/Scripts/ConfigParsers/parser-jboss-cli.xml.ps1 new file mode 100644 index 0000000..c8fce0b --- /dev/null +++ b/Scripts/ConfigParsers/parser-jboss-cli.xml.ps1 @@ -0,0 +1,73 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +# Define the function to extract username and password from a jboss-cli.xml file and return an object +function Get-JbossCredentials { + param ( + [string]$FilePath + ) + + # Check if the file exists + if (-not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return $null + } + + # Load the XML file + [xml]$jbossCliXml = Get-Content -Path $FilePath + + # Extract the username and password + $username = $jbossCliXml."jboss-cli".authentication.username + $password = $jbossCliXml."jboss-cli".authentication.password + + # Return a PowerShell object with the username and password + return [pscustomobject]@{ + Username = $username + Password = $password + } +} + +# Example usage +$xmlFilePath = "c:\temp\configs\jboss-cli.xml" +$credentials = Get-JbossCredentials -FilePath $xmlFilePath + +# Output the returned object (optional for testing) +$credentials + +<# jboss-cli.xml + + + + + 127.0.0.1 + 9990 + + + + + admin + password + + + + + false + + + + + + + + + + + + + + + true + 500 + + + +#> diff --git a/Scripts/ConfigParsers/parser-krb5.conf.ps1 b/Scripts/ConfigParsers/parser-krb5.conf.ps1 new file mode 100644 index 0000000..31d8e21 --- /dev/null +++ b/Scripts/ConfigParsers/parser-krb5.conf.ps1 @@ -0,0 +1,115 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-ConfigCredentials { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Initialize a hashtable to store extracted values + $configData = @{ + Domain = $null + Server = $null + Username = $null + Password = $null + } + + # Check if the file exists + if (-Not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the configuration file + $configFile = Get-Content -Path $FilePath + + # Parse the configuration file line by line + foreach ($line in $configFile) { + # Ignore comment lines and empty lines + if ($line -match '^\s*#' -or $line -match '^\s*$') { + continue + } + + # Extract the domain (e.g., default_realm or ad_domain or similar) + if ($line -match 'default_realm\s*=\s*(.+)') { + $configData.Domain = $matches[1].Trim() + } + + # Extract the server (e.g., kdc or krb5_server or similar) + if ($line -match 'kdc\s*=\s*(.+)') { + $configData.Server = $matches[1].Trim() + } + + # Extract the username (e.g., principal or ldap_default_bind_dn or similar) + if ($line -match 'principal\s*=\s*(.+)') { + $configData.Username = $matches[1].Trim() + } + elseif ($line -match 'ldap_default_bind_dn\s*=\s*(.+)') { + $configData.Username = $matches[1].Trim() + } + + # Extract the password (e.g., password or ldap_default_authtok or similar) + if ($line -match 'password\s*=\s*(.+)') { + $configData.Password = $matches[1].Trim() + } + elseif ($line -match 'ldap_default_authtok\s*=\s*(.+)') { + $configData.Password = $matches[1].Trim() + } + } + + # Output the extracted configuration as a PowerShell object + [PSCustomObject]@{ + Domain = $configData.Domain + Server = $configData.Server + Username = $configData.Username + Password = $configData.Password + } +} + +# Example usage: +$config = Get-ConfigCredentials -FilePath "c:\temp\configs\krb5.conf" +$config | Format-List + + +<# krb5.conf - use for kerberos authention on linux systems + +[libdefaults] + default_realm = EXAMPLE.COM + dns_lookup_realm = false + dns_lookup_kdc = true + rdns = false + ticket_lifetime = 24h + forwardable = yes + +[realms] + EXAMPLE.COM = { + kdc = ad.example.com + admin_server = ad.example.com + default_domain = example.com + } + +[domain_realm] + .example.com = EXAMPLE.COM + example.com = EXAMPLE.COM + +# Insecure: Exposing credentials in krb5.conf for automated ticket retrieval (NOT recommended) +[login] + krb5_get_init_creds_keytab = false + +# Insecure: Plaintext credentials for AD principal +[appdefaults] + kinit = { + principal = admin@EXAMPLE.COM + password = P@ssw0rd123 + } + + pam = { + debug = false + ticket_lifetime = 36000 + renew_lifetime = 36000 + forwardable = true + } + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-machine.config.ps1 b/Scripts/ConfigParsers/parser-machine.config.ps1 new file mode 100644 index 0000000..3547754 --- /dev/null +++ b/Scripts/ConfigParsers/parser-machine.config.ps1 @@ -0,0 +1,374 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +# Function to parse configuration files for credentials +function Get-CredentialsFromConfigFile { + 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 + } +} + +# Example of calling the function with a file path +Get-CredentialsFromConfigFile -configFilePath "c:\temp\configs\machine.config" + + +<# machine.config + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-my.cnf.ps1 b/Scripts/ConfigParsers/parser-my.cnf.ps1 new file mode 100644 index 0000000..f06fa0c --- /dev/null +++ b/Scripts/ConfigParsers/parser-my.cnf.ps1 @@ -0,0 +1,89 @@ + +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-MySQLCredentials { + param ( + [string]$FilePath + ) + + # Check if the file exists + if (-Not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return $null + } + + # Read the file content + $fileContent = Get-Content -Path $FilePath + + # Initialize variables to store username and password + $username = $null + $password = $null + + # Parse the file content + foreach ($line in $fileContent) { + if ($line -match '^\s*user\s*=\s*(.+)$') { + $username = $matches[1].Trim() + } + elseif ($line -match '^\s*password\s*=\s*(.+)$') { + $password = $matches[1].Trim() + } + } + + # Check if both username and password are found + if ($username -and $password) { + # Create a custom PowerShell object to return the credentials + $credentials = [PSCustomObject]@{ + Username = $username + Password = $password + } + return $credentials + } else { + Write-Warning "Username or password not found in the file." + return $null + } +} + +# Example usage: +$credentials = Get-MySQLCredentials -FilePath "c:\temp\configs\my.cnf" +$credentials + + +<# my.cnf + +[client] +# Client configuration options +user=yourusername +password=yourpassword +port=3306 +socket=/var/run/mysqld/mysqld.sock + +[mysqld] +# MySQL server configuration +user=mysql +pid-file=/var/run/mysqld/mysqld.pid +socket=/var/run/mysqld/mysqld.sock +port=3306 +basedir=/usr +datadir=/var/lib/mysql +tmpdir=/tmp +log-error=/var/log/mysql/error.log +bind-address=127.0.0.1 +max_connections=100 +skip-external-locking + +# Buffer pool size for InnoDB +innodb_buffer_pool_size=256M + +# Other MySQL server settings +max_allowed_packet=16M +query_cache_limit=1M +query_cache_size=16M +log_bin=/var/log/mysql/mysql-bin.log + +[mysql] +# Client-specific settings for the MySQL command-line tool +user=yourusername +password=yourpassword +no-auto-rehash + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-php.ini.ps1 b/Scripts/ConfigParsers/parser-php.ini.ps1 new file mode 100644 index 0000000..b810f8f --- /dev/null +++ b/Scripts/ConfigParsers/parser-php.ini.ps1 @@ -0,0 +1,86 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-PhpIniCredentials { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Initialize a hashtable to store extracted values + $configData = @{ + Username = $null + Password = $null + } + + # Check if the file exists + if (-Not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the configuration file + $configFile = Get-Content -Path $FilePath + + # Parse the configuration file line by line + foreach ($line in $configFile) { + # Ignore comment lines and empty lines + if ($line -match '^\s*;' -or $line -match '^\s*$') { + continue + } + + # Extract the username (e.g., mysql.default_user) + if ($line -match '^\s*mysql\.default_user\s*=\s*"(.+)"') { + $configData.Username = $matches[1].Trim() + } + + # Extract the password (e.g., mysql.default_password) + if ($line -match '^\s*mysql\.default_password\s*=\s*"(.+)"') { + $configData.Password = $matches[1].Trim() + } + } + + # Output the extracted configuration as a PowerShell object + [PSCustomObject]@{ + Username = $configData.Username + Password = $configData.Password + } +} + +# Example usage: +$credentials = Get-PhpIniCredentials -FilePath "c:\temp\configs\php.ini" +$credentials | Format-List + + +<# php.ini - storing mysql credentials + + +[PHP] +; Basic PHP settings + +; Maximum size of POST data allowed +post_max_size = 8M + +; Maximum allowed size for uploaded files +upload_max_filesize = 2M + +; INSECURE: Storing database credentials in php.ini (not recommended) +; This exposes credentials to anyone with access to php.ini or via phpinfo() if not secured. + +mysql.default_user = "dbuser" +mysql.default_password = "P@ssw0rd123" +mysql.default_host = "localhost" +mysql.default_database = "example_db" + +; Log errors to a file +log_errors = On +error_log = /var/log/php_errors.log + +; Ensure that this option is Off to avoid disclosing sensitive configuration details +expose_php = Off + +; Ensure that phpinfo() is secured or disabled to prevent exposure of configuration data +disable_functions = phpinfo + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-pureftpd.passwd.ps1 b/Scripts/ConfigParsers/parser-pureftpd.passwd.ps1 new file mode 100644 index 0000000..526a23a --- /dev/null +++ b/Scripts/ConfigParsers/parser-pureftpd.passwd.ps1 @@ -0,0 +1,59 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-PureFtpCredentials { + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Check if the file exists + if (-Not (Test-Path $FilePath)) { + Write-Error "The file at path $FilePath does not exist." + return + } + + # Initialize an array to store user credentials + $credentials = @() + + # Read the file line by line + Get-Content $FilePath | ForEach-Object { + # Skip empty lines + if ($_ -match '^\s*$') { return } + + # Split the line into components using ':' as delimiter + $fields = $_ -split ':' + + # Check if we have at least the username and password fields + if ($fields.Length -ge 2) { + $username = $fields[0] + $passwordHash = $fields[1] + + # Create a custom object for each user + $credentialObject = [PSCustomObject]@{ + Username = $username + PasswordHash = $passwordHash + } + + # Add the object to the credentials array + $credentials += $credentialObject + } else { + Write-Error "The line '$_' does not contain enough fields." + } + } + + # Output the results as a PowerShell object array + return $credentials +} + + +$ftpCredentials = Get-PureFtpCredentials -FilePath "c:\temp\configs\pureftpd.passwd" +$ftpCredentials | Format-Table + + +<# pureftpd.passwd - used by pureftpd, passwords stored as MD5 or SHA-1 hash + +username:$1$X9p2ER8W$M7P5CxX5CHPxuAiB5BBJq/:1001:1001::/home/ftp/username:/bin/false:: +user2:$1$XYz3ERzW$G9P7CxF6CPxxuAiB6BBJq/:1002:1002::/home/ftp/user2:/bin/false:: + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-putty.reg.ps1 b/Scripts/ConfigParsers/parser-putty.reg.ps1 new file mode 100644 index 0000000..46941ac --- /dev/null +++ b/Scripts/ConfigParsers/parser-putty.reg.ps1 @@ -0,0 +1,135 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) +# Putty.reg does not store passwords, but can point to private keys + +function Parse-PuttyRegFile { + param ( + [string]$filePath + ) + + # Check if the file exists + if (-not (Test-Path $filePath)) { + Write-Host "File not found: $filePath" + return + } + + # Read the contents of the .reg file + $regContent = Get-Content -Path $filePath + + # Create a list to store extracted session details + $sessionDetails = @() + + # Variables to hold extracted data for each session + $currentSession = "" + $hostName = "" + $portNumber = "" + $userName = "" + $privateKeyPath = "" + + # Iterate through the lines of the file + foreach ($line in $regContent) { + # Detect session headers (e.g., "[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\My%20SSH%20Session]") + if ($line -match '^\[HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions\\(.+?)\]') { + # 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 + } + } + + # Reset variables for the new session + $currentSession = $matches[1] + $hostName = "" + $portNumber = "" + $userName = "" + $privateKeyPath = "" + } + + # Extract HostName + if ($line -match '"HostName"="(.+?)"') { + $hostName = $matches[1] + } + + # Extract PortNumber (convert hex to decimal) + if ($line -match '"PortNumber"=dword:(\w{8})') { + $portNumber = [convert]::ToInt32($matches[1], 16) + } + + # Extract UserName + if ($line -match '"UserName"="(.+?)"') { + $userName = $matches[1] + } + + # Extract PrivateKeyFile (path to the private key) + if ($line -match '"PublicKeyFile"="(.+?)"') { + $privateKeyPath = $matches[1] + } + } + + # 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 + } + } + + # Return the session details + return $sessionDetails +} + +# Example usage: +$puttySessions = Parse-PuttyRegFile -filePath "c:\temp\configs\putty.reg" + +# Display the results +$puttySessions | Format-Table -AutoSize + + +<# putty.reg + +Windows Registry Editor Version 5.00 + +[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY] +"TermWidth"=dword:00000050 +"TermHeight"=dword:00000018 +"WinTitle"="PuTTY" + +[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\Default%20Settings] +"HostName"="" +"PortNumber"=dword:00000016 +"Protocol"="ssh" +"TerminalType"="xterm" +"Font"="Courier New" +"FontHeight"=dword:0000000a +"WinHeight"=dword:00000018 +"WinWidth"=dword:00000050 +"ConnectionSharing"=dword:00000001 + +[HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\My%20SSH%20Session] +"HostName"="192.168.1.100" +"PortNumber"=dword:00000016 +"Protocol"="ssh" +"TerminalType"="xterm" +"Font"="Courier New" +"FontHeight"=dword:0000000a +"WinHeight"=dword:00000018 +"WinWidth"=dword:00000050 +"Compression"=dword:00000001 +"ConnectionSharing"=dword:00000001 +"PublicKeyFile"="C:\\Users\\YourUsername\\.ssh\\id_rsa.ppk" +"LogFileName"="C:\\putty_logs\\my_session.log" +"LogType"=dword:00000001 +"LogFileClash"=dword:00000001 +"LogFlush"=dword:00000001 +"LogOmitPasswords"=dword:00000001 +"LogOmitData"=dword:00000000 +"UserName"="myusername" ; Username stored here + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-server.xml.ps1 b/Scripts/ConfigParsers/parser-server.xml.ps1 new file mode 100644 index 0000000..08ec8ae --- /dev/null +++ b/Scripts/ConfigParsers/parser-server.xml.ps1 @@ -0,0 +1,179 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Parse-UserPasswordFromXML { + param ( + [string]$filePath + ) + + # Load the XML file + [xml]$xmlContent = Get-Content -Path $filePath + + # Define an array to store the user credentials + $credentials = @() + + # Parse basicRegistry user credentials + $xmlContent.server.basicRegistry.user | ForEach-Object { + $credentials += [pscustomobject]@{ + User = $_.name + Password = $_.password + Source = 'basicRegistry' + } + } + + # Parse variable-based credentials (DB_USER and DB_PASS) + $dbUser = $xmlContent.server.variable | Where-Object { $_.name -eq "DB_USER" } + $dbPass = $xmlContent.server.variable | Where-Object { $_.name -eq "DB_PASS" } + + if ($dbUser -and $dbPass) { + $credentials += [pscustomobject]@{ + User = $dbUser.value + Password = $dbPass.value + Source = 'variable' + } + } + + # Parse containerAuthData credentials + $xmlContent.server.dataSource.containerAuthData | ForEach-Object { + $credentials += [pscustomobject]@{ + User = $_.user + Password = $_.password + Source = 'containerAuthData' + } + } + + # Parse authData credentials + $xmlContent.server.authData | ForEach-Object { + $credentials += [pscustomobject]@{ + User = $_.user + Password = $_.password + Source = 'authData' + } + } + + # Return the collected credentials as an array of objects + return $credentials +} + +# Example usage: +$parsedCredentials = Parse-UserPasswordFromXML -filePath "c:\temp\configs\server.xml" + +# Display the results +$parsedCredentials | Format-Table -AutoSize + + +<# server.xml + + + + + + + componenttest-1.0 + restConnector-2.0 + jdbc-4.2 + mpOpenApi-1.0 + + + + + + + + + + + + + adminuser + + + reader + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SET CURRENT SCHEMA = APP + SET CURRENT SQLID = APP + + + + + + + + + + + + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-settings.ini.ps1 b/Scripts/ConfigParsers/parser-settings.ini.ps1 new file mode 100644 index 0000000..4ed87e1 --- /dev/null +++ b/Scripts/ConfigParsers/parser-settings.ini.ps1 @@ -0,0 +1,105 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-IniCredentials { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Initialize an array to store the credentials + $credentials = @() + + # Check if the file exists + if (-Not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the INI file content + $iniFile = Get-Content -Path $FilePath + + # Initialize variables to track current section and credentials + $currentSection = "" + $username = $null + $password = $null + + # Parse the INI file line by line + foreach ($line in $iniFile) { + # Ignore comment lines and empty lines + if ($line -match '^\s*;' -or $line -match '^\s*$') { + continue + } + + # Detect section headers (e.g., [DatabaseSettings]) + if ($line -match '^\s*\[(.+)\]\s*$') { + # 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 + } + } + # Reset username and password for the new section + $username = $null + $password = $null + + # Update current section + $currentSection = $matches[1].Trim() + continue + } + + # Match username and password in the lines + if ($line -match '^\s*username\s*=\s*(.+)$') { + $username = $matches[1].Trim() + } elseif ($line -match '^\s*password\s*=\s*(.+)$') { + $password = $matches[1].Trim() + } elseif ($line -match '^\s*user\s*=\s*(.+)$') { + $username = $matches[1].Trim() + } elseif ($line -match '^\s*pass\s*=\s*(.+)$') { + $password = $matches[1].Trim() + } + } + + # Capture any remaining username/password pair after the last section + if ($username -and $password) { + $credentials += [PSCustomObject]@{ + Section = $currentSection + Username = $username + Password = $password + } + } + + # Output the credentials as PowerShell objects + return $credentials +} + +# Example usage: +$parsedCredentials = Get-IniCredentials -FilePath "c:\temp\configs\setting.ini" +$parsedCredentials | Format-Table -AutoSize + + + +<# setting.ini + +[GeneralSettings] +app_name = MyApp +version = 1.0.0 +theme = dark + +[DatabaseSettings] +host = localhost +port = 3306 +username = dbuser +password = dbpass + +[CustomSettings] +user = myuser +pass = mypass + +[Logging] +log_level = DEBUG +log_file = /var/log/myapp.log + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-shadow.ps1 b/Scripts/ConfigParsers/parser-shadow.ps1 new file mode 100644 index 0000000..f2f9af3 --- /dev/null +++ b/Scripts/ConfigParsers/parser-shadow.ps1 @@ -0,0 +1,63 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + + +function Get-ShadowFileCredentials { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Initialize an array to store extracted user data + $credentials = @() + + # Check if the file exists + if (-Not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the shadow file + $shadowFile = Get-Content -Path $FilePath + + # Parse each line in the shadow file + foreach ($line in $shadowFile) { + # Ignore empty lines or comments (if any) + if ($line -match '^\s*$' -or $line -match '^\s*#') { + continue + } + + # Split the line into fields using colon as a delimiter + $fields = $line -split ':' + + # Extract username and password hash + $username = $fields[0] + $passwordHash = $fields[1] + + # Create an object to store the extracted information + $userObject = [PSCustomObject]@{ + Username = $username + PasswordHash = $passwordHash + } + + # Add the object to the array + $credentials += $userObject + } + + # Output the array of credentials + return $credentials +} + +# Example usage: +$shadowData = Get-ShadowFileCredentials -FilePath "c:\temp\configs\shadow" +$shadowData | Format-Table -AutoSize + + +<# shadow - linux password file + +root:$6$examplehash$E5iNRLtC5/j/kCkRhYlOro.Y9PzE0Gv8jlsfLZUNwlEm7HMBZSO9.mUvefOrKT6BjKSO4obQ.EtCZKhQgmgwV0:19000:0:99999:7::: +user1:$6$examplehash$OwhxlyS5hoxfFE4tmtyOR8Hw1k8PLqokP9FYxYP8QMG3wO0u.0Xvd4g/0Udr6BQZilJk4k7XwlxJ6p0RJ2IL5/:19000:0:99999:7::: +nobody:*:19000:0:99999:7::: +daemon:*:19000:0:99999:7::: + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-smb.conf.ps1 b/Scripts/ConfigParsers/parser-smb.conf.ps1 new file mode 100644 index 0000000..bd719f5 --- /dev/null +++ b/Scripts/ConfigParsers/parser-smb.conf.ps1 @@ -0,0 +1,105 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-SmbConfCredentials { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Initialize a hashtable to store extracted values + $configData = @{ + Username = $null + Password = $null + } + + # Check if the file exists + if (-Not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the configuration file + $configFile = Get-Content -Path $FilePath + + # Parse the configuration file line by line + foreach ($line in $configFile) { + # Ignore comment lines and empty lines + if ($line -match '^\s*#' -or $line -match '^\s*$') { + continue + } + + # Extract the username + if ($line -match '^\s*username\s*=\s*(.+)') { + $configData.Username = $matches[1].Trim() + } + + # Extract the password + if ($line -match '^\s*password\s*=\s*(.+)') { + $configData.Password = $matches[1].Trim() + } + } + + # Output the extracted configuration as a PowerShell object + [PSCustomObject]@{ + Username = $configData.Username + Password = $configData.Password + } +} + +# Example usage: +$credentials = Get-SmbConfCredentials -FilePath "c:\temp\configs\smb.conf" +$credentials | Format-List + + +<# smb.conf + +[global] + # General server settings + workgroup = EXAMPLE + realm = EXAMPLE.COM + server string = Samba Server Version %v + security = ads + encrypt passwords = yes + kerberos method = secrets and keytab + log file = /var/log/samba/log.%m + max log size = 50 + + # Domain and authentication settings + idmap config * : backend = tdb + idmap config EXAMPLE : backend = rid + idmap config EXAMPLE : range = 10000-20000 + template shell = /bin/bash + winbind use default domain = yes + winbind offline logon = yes + winbind enum users = yes + winbind enum groups = yes + + # INSECURE: Credentials for binding to Active Directory (avoid plaintext credentials) + # This exposes the AD admin account and password directly in the smb.conf file + username = ad-admin + password = P@ssw0rd123 + + # Kerberos keytab file location (more secure than plaintext credentials) + dedicated keytab file = /etc/krb5.keytab + kerberos method = secrets and keytab + +[homes] + comment = Home Directories + browseable = no + writable = yes + +[printers] + comment = All Printers + path = /var/spool/samba + printable = yes + guest ok = no + writable = no + browseable = no + +[shared] + path = /srv/samba/shared + browseable = yes + read only = no + valid users = @staff +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-sssd.conf.ps1 b/Scripts/ConfigParsers/parser-sssd.conf.ps1 new file mode 100644 index 0000000..662768f --- /dev/null +++ b/Scripts/ConfigParsers/parser-sssd.conf.ps1 @@ -0,0 +1,133 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-ConfigCredentials { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Initialize a hashtable to store extracted values + $configData = @{ + Domain = $null + Server = $null + Username = $null + Password = $null + } + + # Check if the file exists + if (-Not (Test-Path -Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the configuration file + $configFile = Get-Content -Path $FilePath + + # Parse the configuration file line by line + foreach ($line in $configFile) { + # Ignore comment lines and empty lines + if ($line -match '^\s*#' -or $line -match '^\s*$') { + continue + } + + # Extract the domain (e.g., ad_domain or similar) + if ($line -match 'ad_domain\s*=\s*(.+)') { + $configData.Domain = $matches[1].Trim() + } + + # Extract the server (e.g., krb5_server or similar) + if ($line -match 'krb5_server\s*=\s*(.+)') { + $configData.Server = $matches[1].Trim() + } + + # Extract the username (e.g., ldap_default_bind_dn or similar) + if ($line -match 'ldap_default_bind_dn\s*=\s*(.+)') { + $configData.Username = $matches[1].Trim() + } + + # Extract the password (e.g., ldap_default_authtok or similar) + if ($line -match 'ldap_default_authtok\s*=\s*(.+)') { + $configData.Password = $matches[1].Trim() + } + } + + # Output the extracted configuration as a PowerShell object + [PSCustomObject]@{ + Domain = $configData.Domain + Server = $configData.Server + Username = $configData.Username + Password = $configData.Password + } +} + +# Example usage: +$config = Get-ConfigCredentials -FilePath "c:\temp\configs\sssd.conf" +$config | Format-List + + +<# sssd.conf - used to support kerberos authentication in Linux + + +[sssd] +config_file_version = 2 +services = nss, pam, ssh, sudo +domains = example.com + +[nss] +filter_groups = root +filter_users = root + +[pam] +offline_credentials_expiration = 2 +offline_failed_login_attempts = 3 +offline_failed_login_delay = 5 + +[domain/example.com] +# Basic configuration for connecting to Active Directory +id_provider = ad +auth_provider = ad +access_provider = ad + +# Enable Kerberos for authentication +krb5_realm = EXAMPLE.COM +krb5_server = ad.example.com +krb5_kpasswd = ad.example.com + +# Active Directory server information +ad_domain = example.com +ad_server = ad.example.com +ad_hostname = linuxclient.example.com + +# INSECURE PRACTICE: Hardcoding AD username and password in sssd.conf +# These values will expose the username and password in plaintext +ldap_default_bind_dn = cn=admin,cn=users,dc=example,dc=com +ldap_default_authtok = P@ssw0rd123 + +# Using the above configuration exposes credentials to anyone who can read this file + +# User and group filtering (optional) +ldap_id_mapping = true + +# Performance optimizations +cache_credentials = true +enumerate = false +use_fully_qualified_names = false + +# Access Control (Optional: limit login to users in AD group 'LinuxAdmins') +access_provider = simple +simple_allow_groups = LinuxAdmins + +# Security settings +min_id = 1000 +fallback_homedir = /home/%u + +# Timeout and retry settings for better AD stability +ldap_search_timeout = 10 +ldap_connection_expire_timeout = 60 + +# Debugging options (uncomment for troubleshooting) +# debug_level = 9 + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-standalone.xml-ps1.ps1 b/Scripts/ConfigParsers/parser-standalone.xml-ps1.ps1 new file mode 100644 index 0000000..0b1f2da --- /dev/null +++ b/Scripts/ConfigParsers/parser-standalone.xml-ps1.ps1 @@ -0,0 +1,101 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Parse-DataSourceConfig { + param ( + [string]$ConfigPath + ) + + # Load the XML config + [xml]$configXml = Get-Content -Path $ConfigPath + + # Define a hashtable to store results + $result = @{} + + # Parse the server and port from the connection URL + $connectionUrl = $configXml.server.subsystem.datasources.datasource."connection-url" + if ($connectionUrl -match "jdbc:mysql://([^:/]+)(?::(\d+))?") { + $result.Server = $matches[1] + $result.Port = if ($matches[2]) { $matches[2] } else { "3306" } # Default MySQL port + } + + # Get the username + $result.Username = $configXml.server.subsystem.datasources.datasource.security."user-name" + + # Get the password + $result.Password = $configXml.server.subsystem.datasources.datasource.security.password + + # 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 + + # Convert hashtable to PowerShell object + $resultObject = [PSCustomObject]$result + + # Output the result object + return $resultObject +} + +# Example usage +$parsedConfig = Parse-DataSourceConfig -ConfigPath "c:\temp\configs\standalone.xml" +$parsedConfig + + +<# standalone.xml used by jboss + + + + + + + + + + + + + jdbc:mysql://localhost:3306/mydatabase + mysql + + ${VAULT::vault::mydbuser} + ${VAULT::vault::mydbpassword} + + + 5 + 20 + + + + true + true + + + 5000 + + + false + + + + + + com.mysql.jdbc.jdbc2.optional.MysqlXADataSource + + + + + + + + + + + + + + + + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-sysprep.inf.ps1 b/Scripts/ConfigParsers/parser-sysprep.inf.ps1 new file mode 100644 index 0000000..9faa16b --- /dev/null +++ b/Scripts/ConfigParsers/parser-sysprep.inf.ps1 @@ -0,0 +1,97 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-SysprepCredentials { + param ( + [Parameter(Mandatory=$true)] + [string]$FilePath + ) + + # Check if file exists + if (-Not (Test-Path $FilePath)) { + Write-Error "File does not exist: $FilePath" + return + } + + # Initialize an empty hashtable to store credentials + $credentials = @{ + AdminPassword = $null + JoinDomain = $null + DomainAdmin = $null + DomainAdminPassword = $null + } + + # Read the sysprep.inf file + $fileContent = Get-Content -Path $FilePath + + # Loop through each line and extract relevant credentials + foreach ($line in $fileContent) { + if ($line -match 'AdminPassword\s*=\s*(.+)') { + $credentials['AdminPassword'] = $matches[1].Trim() + } + + if ($line -match 'JoinDomain\s*=\s*(.+)') { + $credentials['JoinDomain'] = $matches[1].Trim() + } + + if ($line -match 'DomainAdmin\s*=\s*(.+)') { + $credentials['DomainAdmin'] = $matches[1].Trim() + } + + 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'] + } + + return $credObject +} + +# Example usage: +$result = Get-SysprepCredentials -FilePath "c:\temp\configs\sysprep.inf" +$result + +<# sysprep.inf + +[Unattended] +OemSkipEula=Yes +InstallFilesPath=C:\sysprep\i386 + +[GuiUnattended] +AdminPassword=YourAdminPassword +EncryptedAdminPassword=NO +OEMSkipRegional=1 +TimeZone=004 +OemSkipWelcome=1 + +[UserData] +ProductKey=XXXXX-XXXXX-XXXXX-XXXXX-XXXXX +FullName="Your Name" +OrgName="Your Organization" +ComputerName=* + +[Display] +BitsPerPel=32 +Xresolution=1024 +YResolution=768 +Vrefresh=60 + +[SetupMgr] +DistFolder=C:\sysprep\i386 +DistShare=windist + +[Identification] +JoinDomain=YourDomain +DomainAdmin=YourDomainAdmin +DomainAdminPassword=YourDomainAdminPassword + +[Networking] +InstallDefaultComponents=Yes + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-tnsnames.ora.ps1 b/Scripts/ConfigParsers/parser-tnsnames.ora.ps1 new file mode 100644 index 0000000..5225135 --- /dev/null +++ b/Scripts/ConfigParsers/parser-tnsnames.ora.ps1 @@ -0,0 +1,99 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Extract-OracleCredentials { + param( + [string]$FilePath + ) + + if (-Not (Test-Path -Path $FilePath)) { + Write-Error "File path does not exist: $FilePath" + return + } + + # Initialize an empty array to store the results + $credentialsList = @() + + # Read the file contents + $fileContent = Get-Content -Path $FilePath + + # Initialize variables to store temporary values + $currentDatabase = $null + $currentUser = $null + $currentPassword = $null + + foreach ($line in $fileContent) { + # Trim the line for easier processing + $line = $line.Trim() + + # Match a database name (lines that don't start with a '(' and end with '=') + if ($line -match '^\w+\s*=\s*$') { + if ($currentDatabase -and $currentUser -and $currentPassword) { + # Store the previous credentials + $credentialsList += [pscustomobject]@{ + Database = $currentDatabase + User = $currentUser + Password = $currentPassword + } + } + + # Reset the user and password for the next database entry + $currentDatabase = $line -replace '\s*=\s*$', '' # Remove the equals sign + $currentUser = $null + $currentPassword = $null + } + + # Match the USER line + if ($line -match 'USER\s*=\s*(.+)$') { + $currentUser = $matches[1] + } + + # Match the PASSWORD line + if ($line -match 'PASSWORD\s*=\s*(.+)$') { + $currentPassword = $matches[1] + } + } + + # Capture the last set of credentials + if ($currentDatabase -and $currentUser -and $currentPassword) { + $credentialsList += [pscustomobject]@{ + Database = $currentDatabase + User = $currentUser + Password = $currentPassword + } + } + + # Output the results as a list of objects + return $credentialsList +} + +# Example usage: +$result = Extract-OracleCredentials -FilePath "c:\temp\configs\tnsnames.ora" +$result | Format-Table + + + +<# tnsnames.ora - oracle + +MYDB = + (DESCRIPTION = + (ADDRESS = (PROTOCOL = TCP)(HOST = mydbserver.example.com)(PORT = 1521)) + (CONNECT_DATA = + (SERVICE_NAME = mydbservice) + ) + ) + (USER = myusername) + (PASSWORD = mypassword) + +MYDB_ALIAS = + (DESCRIPTION = + (ADDRESS_LIST = + (ADDRESS = (PROTOCOL = TCP)(HOST = mydbserver.example.com)(PORT = 1521)) + ) + (CONNECT_DATA = + (SERVICE_NAME = mydbservice) + ) + ) + (USER = anotheruser) + (PASSWORD = anotherpassword) + + #> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-tomcat-users.xml.ps1 b/Scripts/ConfigParsers/parser-tomcat-users.xml.ps1 new file mode 100644 index 0000000..1d86073 --- /dev/null +++ b/Scripts/ConfigParsers/parser-tomcat-users.xml.ps1 @@ -0,0 +1,78 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-TomcatUsers { + param ( + [Parameter(Mandatory = $true)] + [string]$TomcatConfigFile + ) + + # Load the XML file + [xml]$xml = Get-Content -Path $TomcatConfigFile + + # Create an array to store the results + $usersList = @() + + # Select the user nodes from the XML + $users = $xml.'tomcat-users'.user + + # Loop through each user and extract the name and password attributes + foreach ($user in $users) { + # Create a PowerShell object for each user + $userObject = [PSCustomObject]@{ + Username = $user.name + Password = $user.password + } + + # Add the object to the list + $usersList += $userObject + } + + # Display the list of users as a table + return $usersList +} + +# Example usage +$tomcatConfigFilePath = "c:\temp\configs\tomcat-users.xml" +Get-TomcatUsers -TomcatConfigFile $tomcatConfigFilePath | Format-Table -AutoSize + + +<# tomcat-users.xml + + + + + + + + + + + + + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-unattend.xml.ps1 b/Scripts/ConfigParsers/parser-unattend.xml.ps1 new file mode 100644 index 0000000..d1c8f52 --- /dev/null +++ b/Scripts/ConfigParsers/parser-unattend.xml.ps1 @@ -0,0 +1,143 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Parse-UnattendFile { + param ( + [string]$filePath + ) + + # Load the XML file + [xml]$xmlContent = Get-Content -Path $filePath + + # Create an array to store the parsed credentials + $credentials = @() + + # Define namespaces used in the XML file + $namespace = @{ + "unattend" = "urn:schemas-microsoft-com:unattend" + "wcm" = "http://schemas.microsoft.com/WMIConfig/2002/State" + } + + # Function to decode Base64 if password is encoded + function Decode-PasswordIfNeeded { + param ( + [string]$passwordValue, + [bool]$isPlainText + ) + + if ($isPlainText -eq $false) { + try { + # Decode Base64 password + $decodedPassword = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($passwordValue)) + return $decodedPassword + } catch { + Write-Host "Error: Unable to decode Base64 string, returning original value." + return $passwordValue + } + } + else { + return $passwordValue + } + } + + # Parse AutoLogon credentials + $autoLogon = $xmlContent.unattend.settings.component | Where-Object { + $_.name -eq "Microsoft-Windows-Shell-Setup" -and $_.AutoLogon -ne $null + } + if ($autoLogon) { + $username = $autoLogon.AutoLogon.Username + $password = $autoLogon.AutoLogon.Password.Value + $isPlainText = $autoLogon.AutoLogon.Password.PlainText -eq "true" + + # Decode password if necessary + $password = Decode-PasswordIfNeeded -passwordValue $password -isPlainText $isPlainText + + $credentials += [pscustomobject]@{ + User = $username + Password = $password + Source = "AutoLogon" + } + } + + # Parse LocalAccounts credentials + $localAccounts = $xmlContent.unattend.settings.component.UserAccounts.LocalAccounts.LocalAccount | Where-Object { $_ -ne $null } + foreach ($account in $localAccounts) { + $username = $account.Name + $password = $account.Password.Value + $isPlainText = $account.Password.PlainText -eq "true" + + # Decode password if necessary + $password = Decode-PasswordIfNeeded -passwordValue $password -isPlainText $isPlainText + + $credentials += [pscustomobject]@{ + User = $username + Password = $password + Source = "LocalAccount" + } + } + + # Return the collected credentials as an array of objects + return $credentials +} + +# Example usage: +$parsedCredentials = Parse-UnattendFile -filePath "c:\temp\configs\unattend-base64.xml" + +# Display the results +$parsedCredentials | Format-Table -AutoSize + + + +<# unattend.xml + + + + + + * + acme corp. + acme corp. + + false + + + LocalAdmin + true + 10 + + UEBzc3dvcmQxMjMh + false</PlainText> + </Password> + </AutoLogon> + </component> + </settings> + + <settings pass="oobeSystem"> + <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"> + <UserAccounts> + <LocalAccounts> + <LocalAccount wcm:action="add"> + <Password> + <Value>UEBzc3dvcmQxMjMh</Value> <!-- This is Base64 for 'P@ssword123!' --> + <PlainText>false</PlainText> + </Password> + <Group>Administrators</Group> + <Description>Provisioning Admin</Description> + <DisplayName>LocalAdmin</DisplayName> + <Name>LocalAdmin</Name> + </LocalAccount> + </LocalAccounts> + </UserAccounts> + <OOBE> + <HideEULAPage>true</HideEULAPage> + <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> + <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> + <HideOnlineAccountScreens>true</HideOnlineAccountScreens> + <HideLocalAccountScreen>true</HideLocalAccountScreen> + <ProtectYourPC>1</ProtectYourPC> + </OOBE> + </component> + </settings> +</unattend> + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-vnc.ini.ps1 b/Scripts/ConfigParsers/parser-vnc.ini.ps1 new file mode 100644 index 0000000..dad6faf --- /dev/null +++ b/Scripts/ConfigParsers/parser-vnc.ini.ps1 @@ -0,0 +1,110 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) +function Get-VNCPassword { + param ( + [Parameter(Mandatory=$true)] + [string]$VncIniPath + ) + + # Define the fixed DES key used by VNC + $desKey = [byte[]](0x23, 0x52, 0x6A, 0x3B, 0x58, 0x92, 0x67, 0x34) + + # Read the vnc.ini file + if (-Not (Test-Path -Path $VncIniPath)) { + Write-Error "The file path '$VncIniPath' does not exist." + return + } + + $vncIniContent = Get-Content -Path $VncIniPath + + # Extract the encrypted password from the ini file + $encryptedHex = ($vncIniContent | ForEach-Object { + if ($_ -match '^Password=(.+)$') { + return $matches[1] + } + }).Trim() + + if (-not $encryptedHex) { + Write-Output "Password not found in vnc.ini" + return + } + + # Convert the hex string to a byte array + $encryptedBytes = for ($i = 0; $i -lt $encryptedHex.Length; $i += 2) { + [Convert]::ToByte($encryptedHex.Substring($i, 2), 16) + } + + # Create a DES crypto object and set the key and mode + $des = New-Object System.Security.Cryptography.DESCryptoServiceProvider + $des.Key = $desKey # Assign the key as a byte array + $des.Mode = [System.Security.Cryptography.CipherMode]::ECB + $des.Padding = [System.Security.Cryptography.PaddingMode]::None + + # Create a decryptor + $decryptor = $des.CreateDecryptor() + + # Decrypt the encrypted password + $decryptedBytes = $decryptor.TransformFinalBlock($encryptedBytes, 0, $encryptedBytes.Length) + + # Convert the decrypted byte array to a string, trimming null characters + $decryptedPassword = [System.Text.Encoding]::ASCII.GetString($decryptedBytes).Trim("`0") + + # Return the decrypted password as an object + return [pscustomobject]@{ + DecryptedPassword = $decryptedPassword + } +} + +# Example usage +$path = "c:\temp\configs\vnc.ini" +$passwordObject = Get-VNCPassword -VncIniPath $path +$passwordObject + + + + +<# vnc.ini + +[Server] +# The port on which the VNC server listens for connections (default: 5900) +Port=5900 + +# Defines the IP address to bind the VNC server to. Leave blank to bind to all interfaces. +BindTo=0.0.0.0 + +# Enable or disable authentication. If 1, authentication is enabled. +Authentication=1 + +# VNC password (encoded or plain text depending on the software) +Password=01d47b4186dfa5a3 + +# Encryption (optional). Enable or disable encryption for VNC connections. +Encryption=1 + +# Set the idle timeout for client connections (in seconds) +IdleTimeout=600 + +# Maximum number of clients that can connect at once +MaxClients=5 + +[Security] +# Use SSL encryption for communication between VNC clients and server +UseSSL=0 + +# If SSL is enabled, provide the path to the SSL certificate file. +SSLCertificateFile=C:\path\to\ssl\certificate.pem + +# Enable or disable TLS encryption +UseTLS=1 + +[Logging] +# Enable or disable logging. If 1, logging is enabled. +EnableLogging=1 + +# Log file location +LogFile=C:\path\to\log\vncserver.log + +# Log level (INFO, DEBUG, ERROR, etc.) +LogLevel=INFO + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-web.config.ps1 b/Scripts/ConfigParsers/parser-web.config.ps1 new file mode 100644 index 0000000..ee81c6b --- /dev/null +++ b/Scripts/ConfigParsers/parser-web.config.ps1 @@ -0,0 +1,329 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +# Function to parse configuration files for credentials +function Get-CredentialsFromConfigFile { + 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 + } +} + +# Example of calling the function with a file path +Get-CredentialsFromConfigFile -configFilePath "c:\temp\configs\web.config" + + +<# web.config +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <!-- Config Sections for Custom Service Credentials --> + <configSections> + <section name="serviceCredentials" type="System.Configuration.NameValueSectionHandler" /> + <sectionGroup name="system.net"> + <section name="settings" type="System.Net.Configuration.SettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + </sectionGroup> + </configSections> + + <!-- Application Settings for web application --> + <appSettings> + <add key="ApplicationUsername" value="myAppUser" /> + <add key="ApplicationPassword" value="myAppPassword" /> + <add key="OAuthServiceUrl" value="https://oauth.example.com/token" /> + <add key="ClientId" value="myClientId" /> + <add key="ClientSecret" value="myClientSecret" /> + <add key="ServiceUrl" value="https://service.example.com/api" /> + <add key="ServiceUserName" value="serviceUser" /> + <add key="ServicePassword" value="servicePassword" /> + <add key="ApiEndpoint" value="https://api.example.com/endpoint" /> + <add key="ApiUserName" value="apiUser" /> + <add key="ApiPassword" value="apiPassword" /> + </appSettings> + + <!-- Custom service credentials --> + <serviceCredentials> + <add key="ServiceUrl" value="https://customservice.example.com" /> + <add key="UserName" value="customUser" /> + <add key="Password" value="customPassword" /> + </serviceCredentials> + + <!-- Connection strings for various databases --> + <connectionStrings> + <add name="SqlServerConnection" + connectionString="Data Source=localhost;Initial Catalog=myDB;User ID=myUser;Password=myPass;" + providerName="System.Data.SqlClient" /> + <add name="SqlServerIntegratedSecurity" + connectionString="Data Source=localhost;Initial Catalog=myDB;Integrated Security=True;" + providerName="System.Data.SqlClient" /> + <add name="MySqlConnection" + connectionString="Server=localhost;Database=myDB;User=myUser;Password=myPass;" + providerName="MySql.Data.MySqlClient" /> + <add name="PostgreSqlConnection" + connectionString="Host=localhost;Port=5432;Database=myDB;Username=myUser;Password=myPass;" + providerName="Npgsql" /> + <add name="OracleConnection" + connectionString="Data Source=MyOracleDB;User Id=oracleUser;Password=oraclePass;" + providerName="Oracle.ManagedDataAccess.Client" /> + </connectionStrings> + + <!-- Web-specific settings for forms authentication, session state, and errors --> + <system.web> + <!-- Compilation settings --> + <compilation debug="true" targetFramework="4.0" /> + + <!-- Authentication settings for web applications --> + <authentication mode="Forms"> + <forms loginUrl="login.aspx" timeout="30"> + <credentials passwordFormat="Clear"> + <user name="user1" password="password1" /> + <user name="user2" password="password2" /> + </credentials> + </forms> + </authentication> + + <!-- Authorization settings to allow or deny user access --> + <authorization> + <allow users="*" /> <!-- Allow all users --> + <deny users="?" /> <!-- Deny anonymous users --> + </authorization> + + <!-- Custom error pages --> + <customErrors mode="RemoteOnly"> + <error statusCode="404" redirect="404.aspx" /> + <error statusCode="500" redirect="500.aspx" /> + </customErrors> + + <!-- Session State settings (optional) --> + <sessionState mode="InProc" timeout="20" /> + </system.web> + + <!-- SMTP settings for email (relevant for web applications) --> + <system.net> + <mailSettings> + <smtp from="you@example.com"> + <network host="smtp.example.com" port="587" + userName="smtpUser" + password="smtpPassword" + defaultCredentials="false" /> + </smtp> + </mailSettings> + </system.net> + + <!-- WCF (Windows Communication Foundation) Service configuration for web applications --> + <system.serviceModel> + <bindings> + <basicHttpBinding> + <binding name="MyBinding"> + <security mode="Transport"> + <transport clientCredentialType="Basic" /> + </security> + </binding> + </basicHttpBinding> + </bindings> + <client> + <endpoint address="https://example.com/service" + binding="basicHttpBinding" + bindingConfiguration="MyBinding" + contract="IMyService" /> + </client> + <behaviors> + <endpointBehaviors> + <behavior> + <clientCredentials> + <userName userName="serviceUser" password="servicePassword" /> + </clientCredentials> + </behavior> + </endpointBehaviors> + </behaviors> + </system.serviceModel> + + <!-- IIS-specific settings for URL rewriting and other web server configurations --> + <system.webServer> + <!-- Enable URL rewriting (optional) --> + <rewrite> + <rules> + <rule name="RedirectToHTTPS"> + <match url="(.*)" /> + <conditions> + <add input="{HTTPS}" pattern="^OFF$" /> + </conditions> + <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" /> + </rule> + </rules> + </rewrite> + + <!-- Enable static content compression (optional) --> + <staticContent> + <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" /> + </staticContent> + + <!-- HTTP modules and handlers (optional) --> + <modules runAllManagedModulesForAllRequests="true" /> + </system.webServer> + +</configuration> + + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-winscp.ini.ps1 b/Scripts/ConfigParsers/parser-winscp.ini.ps1 new file mode 100644 index 0000000..27adbe5 --- /dev/null +++ b/Scripts/ConfigParsers/parser-winscp.ini.ps1 @@ -0,0 +1,101 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-WinSCPConfig { + param ( + [Parameter(Mandatory = $true)] + [string]$FilePath + ) + + # Check if file exists + if (-not (Test-Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Read the WinSCP.ini file content + $content = Get-Content -Path $FilePath + + # Initialize an empty object for results + $result = [PSCustomObject]@{ + HostName = $null + PortNumber = $null + PrivateKeyFile = $null + UserName = $null + Password = $null + } + + # Parse the .ini file for relevant information + foreach ($line in $content) { + if ($line -match '^HostName=(.*)') { + $result.HostName = $matches[1] + } elseif ($line -match '^PortNumber=(.*)') { + $result.PortNumber = [int]$matches[1] + } elseif ($line -match '^PrivateKeyFile=(.*)') { + $result.PrivateKeyFile = $matches[1] + } elseif ($line -match '^UserName=(.*)') { + $result.UserName = $matches[1] + } elseif ($line -match '^Password=(.*)') { + $result.Password = $matches[1] # Encrypted password in .ini + } + } + + # Return the result object + return $result +} + +# Example usage +$winSCPConfig = Get-WinSCPConfig -FilePath "c:\temp\configs\WinSCP.ini" +$winSCPConfig + +<# winscp decryption function that uses dpapi below + +function ConvertFrom-DPAPI { + param ( + [Parameter(Mandatory = $true)] + [string]$EncryptedPassword + ) + + # Convert the base64 encoded password back to byte array + $passwordBytes = [Convert]::FromBase64String($EncryptedPassword) + + # Use the Windows DPAPI to decrypt the password + $decryptedBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($passwordBytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser) + + # Convert the decrypted byte array back to a string (UTF-8 encoded) + $decryptedPassword = [System.Text.Encoding]::UTF8.GetString($decryptedBytes) + + return $decryptedPassword +} + +# Example usage with an encrypted password from WinSCP.ini +$encryptedPassword = "Base64EncryptedPasswordHere" +$decryptedPassword = ConvertFrom-DPAPI -EncryptedPassword $encryptedPassword +Write-Output "Decrypted Password: $decryptedPassword" + + +#> + + +<# winscp.ini + + +[Configuration\Interface] +Random=4074A9829D979781989E96 + +[Sessions\example] +HostName=ftp.example.com +PortNumber=21 +UserName=myuser +Password=0V5aNH+/kT8= ; Encrypted password +LocalDirectory=C:\Users\myuser\Documents +RemoteDirectory=/public_html +FSProtocol=0 +PostLoginCommands= +PrivateKeyFile= + +[Configuration\Interface\Commander] +LastLocalDirectory=C:\Users\myuser\Documents +LastRemoteDirectory=/public_html + + +#> \ No newline at end of file diff --git a/Scripts/ConfigParsers/parser-wp-config.php.ps1 b/Scripts/ConfigParsers/parser-wp-config.php.ps1 new file mode 100644 index 0000000..1203895 --- /dev/null +++ b/Scripts/ConfigParsers/parser-wp-config.php.ps1 @@ -0,0 +1,121 @@ +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) + +function Get-WPConfigCredentials { + param ( + [string]$FilePath + ) + + # Check if the file exists + if (-Not (Test-Path $FilePath)) { + Write-Error "File not found: $FilePath" + return + } + + # Initialize variables for username and password + $dbUsername = $null + $dbPassword = $null + + # Read the file line by line + Get-Content $FilePath | ForEach-Object { + $line = $_ + + # Match the DB_USER line and extract the username + if ($line -match "define\(\s*'DB_USER'\s*,\s*'([^']+)'\s*\)") { + $dbUsername = $matches[1] + } + + # Match the DB_PASSWORD line and extract the password + if ($line -match "define\(\s*'DB_PASSWORD'\s*,\s*'([^']+)'\s*\)") { + $dbPassword = $matches[1] + } + } + + # Check if both username and password were found + if ($dbUsername -and $dbPassword) { + # Return the results as a PowerShell object + [PSCustomObject]@{ + Username = $dbUsername + Password = $dbPassword + } + } + else { + Write-Error "Username or Password not found in the configuration file." + } +} + +# Example usage +$credentials = Get-WPConfigCredentials -FilePath "c:\temp\configs\wp-config.php" +$credentials + + +<# wp-config.php + +<?php +// ** MySQL settings - You can get this info from your web host ** // +/** The name of the database for WordPress */ +define( 'DB_NAME', 'your_database_name' ); + +/** MySQL database username */ +define( 'DB_USER', 'your_database_username' ); + +/** MySQL database password */ +define( 'DB_PASSWORD', 'your_secure_password_here' ); + +/** MySQL hostname */ +define( 'DB_HOST', 'localhost' ); + +/** Database Charset to use in creating database tables. */ +define( 'DB_CHARSET', 'utf8' ); + +/** The Database Collate type. Don't change this if in doubt. */ +define( 'DB_COLLATE', '' ); + +/**#@+ + * Authentication Unique Keys and Salts. + * + * Change these to different unique phrases! + * You can generate these using the WordPress.org secret-key service + * https://api.wordpress.org/secret-key/1.1/salt/ + * You can change these at any point in time to invalidate all existing cookies. + * This will force all users to have to log in again. + */ +define('AUTH_KEY', 'put_your_unique_phrase_here'); +define('SECURE_AUTH_KEY', 'put_your_unique_phrase_here'); +define('LOGGED_IN_KEY', 'put_your_unique_phrase_here'); +define('NONCE_KEY', 'put_your_unique_phrase_here'); +define('AUTH_SALT', 'put_your_unique_phrase_here'); +define('SECURE_AUTH_SALT', 'put_your_unique_phrase_here'); +define('LOGGED_IN_SALT', 'put_your_unique_phrase_here'); +define('NONCE_SALT', 'put_your_unique_phrase_here'); + +/**#@-*/ + +/** + * WordPress Database Table prefix. + * + * You can have multiple installations in one database if you give each a unique + * prefix. Only numbers, letters, and underscores please! + */ +$table_prefix = 'wp_'; + +/** + * For developers: WordPress debugging mode. + * + * Change this to true to enable the display of notices during development. + * It is strongly recommended that plugin and theme developers use WP_DEBUG + * in their development environments. + */ +define( 'WP_DEBUG', false ); + +/* That's all, stop editing! Happy publishing. */ + +/** Absolute path to the WordPress directory. */ +if ( ! defined( 'ABSPATH' ) ) { + define( 'ABSPATH', __DIR__ . '/' ); +} + +/** Sets up WordPress vars and included files. */ +require_once ABSPATH . 'wp-settings.php'; + + +#> \ No newline at end of file