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
+
+
+
+
+
+
+
+
+
+
+
+ UEBzc3dvcmQxMjMh
+ false
+
+ Administrators
+ Provisioning Admin
+ LocalAdmin
+ LocalAdmin
+
+
+
+
+ true
+ true
+ true
+ true
+ true
+ 1
+
+
+
+
+
+
+#>
\ 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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#>
\ 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
+
+
\ No newline at end of file