From 3e7217c2806fc623edf762024aa592b3f775f4b3 Mon Sep 17 00:00:00 2001 From: Scott Sutherland Date: Sun, 6 Oct 2024 10:28:15 -0500 Subject: [PATCH] Update PowerHuntShares.psm1 Added cisco startup / running config parser, and type7 encoder/decoder. --- PowerHuntShares.psm1 | 237 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 1 deletion(-) diff --git a/PowerHuntShares.psm1 b/PowerHuntShares.psm1 index 7bc9276..c5ec91c 100644 --- a/PowerHuntShares.psm1 +++ b/PowerHuntShares.psm1 @@ -4,7 +4,7 @@ #-------------------------------------- # Author: Scott Sutherland, 2024 NetSPI # License: 3-clause BSD -# Version: v1.143 +# Version: v1.144 # References: This script includes custom code and code taken and modified from the open source projects PowerView, Invoke-Ping, and Invoke-Parrell. function Invoke-HuntSMBShares { @@ -1539,6 +1539,8 @@ function Invoke-HuntSMBShares $FileNamePatternsAll.Rows.Add("jboss-logmanager.properties*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("jenkins.model.JenkinsLocationConfiguration.*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("machine.config*","","None.","Secret","Get-PwMachineConfig") | Out-Null + $FileNamePatternsAll.Rows.Add("startup*","","None.","Secret","Get-PwCiscoConfig") | Out-Null + $FileNamePatternsAll.Rows.Add("running*","","None.","Secret","Get-PwCiscoConfig") | Out-Null $FileNamePatternsAll.Rows.Add("my.*","","None.","Secret","Get-PwMySQLConfig") | Out-Null $FileNamePatternsAll.Rows.Add("mysql.user*","","None.","Secret","") | Out-Null $FileNamePatternsAll.Rows.Add("nginx.conf*","","None.","Secret","") | Out-Null @@ -26271,3 +26273,236 @@ function Get-PrivateKeyFilePath { return $result } + +# Author: Scott Sutherland, NetSPI (@_nullbind / nullbind) +# Intended input: cisco configurations files (startup/run) +function Get-PwCiscoConfig { + param ( + [string]$ComputerName = $null, # Optional + [string]$ShareName = $null, # Optional + [string]$UncFilePath = $null, # Optional + [string]$FileName = $null, # Optional + [string]$FilePath # Required + ) + + # Cisco Type 7 encryption key + $xlat = @( + 0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41, 0x2c, 0x2e, 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c, 0x64, + 0x4a, 0x4b, 0x44, 0x48, 0x53, 0x55, 0x42, 0x73, 0x67, 0x76, 0x63, 0x61, 0x36, 0x39, 0x38, 0x33, 0x34, 0x6e, 0x63, + 0x78, 0x76, 0x39, 0x38, 0x37, 0x33, 0x32, 0x35, 0x34, 0x6b, 0x3b, 0x66, 0x67, 0x38, 0x37 + ) + + # Cisco Type 7 Password Decoder + function Decode-Type7 { + param ( + [string]$EncodedPassword + ) + + # Initialize decoded password + $decodedPassword = '' + + # Extract the seed and the encrypted portion + $seed = [convert]::ToInt32($EncodedPassword.Substring(0, 2)) # The first two characters as the seed + $encryptedPart = $EncodedPassword.Substring(2) + + # Loop through the encrypted part and decrypt each byte + for ($i = 0; $i -lt $encryptedPart.Length; $i += 2) { + $currentByte = HexToInt $encryptedPart.Substring($i, 2) + $decodedChar = [char]($currentByte -bxor $xlat[$seed]) + $decodedPassword += $decodedChar + $seed = ($seed + 1) % $xlat.Length # Reset seed if it reaches 51 + } + + return $decodedPassword + } + + # Read the file content + $fileContent = Get-Content -Path $FilePath + + # Regex patterns for different password types and usernames + $regexEnablePassword = '(?<=enable password\s)(\d*)\s*([^\s]+)' # Matches enable password (cleartext or encoded) + $regexEnableSecret = '(?<=enable secret\s5\s)([^\s]+)' # Matches enable secret 5 (encrypted password) + $regexUsernamePassword = 'username\s([^\s]+)\s(?:password|secret)\s(\d)\s([^\s]+)' # Matches username passwords (cleartext, encrypted, or encoded) + $regexGeneralPassword = '(?<=password\s)(\d*)\s*([^\s]+)' # Matches generic password lines, including ones without type indicator + $regexConsolePassword = '(?<=line con 0\s+password\s)(\d*)\s*([^\s]+)' # Matches console passwords + $regexSnmpCommunity = 'snmp-server community\s([^\s]+)\s(RO|RW)' # Matches SNMP community strings + $regexWpaPsk = 'wpa-psk ascii 0\s([^\s]+)' # Matches WPA PSK Wi-Fi passwords + + # Array to store the parsed objects + $parsedPasswords = @() + + foreach ($line in $fileContent) { + $object = [PSCustomObject]@{ + ComputerName = $ComputerName + ShareName = $ShareName + UncFilePath = $UncFilePath + FileName = $FileName + Section = "NA" + ObjectName = 'Secret' + TargetURL = "NA" + TargetServer = "NA" + TargetPort = "NA" + Database = "NA" + Domain = "NA" + Username = "NA" + Password = "NA" + PasswordEnc = "NA" + KeyFilePath = "NA" + } + + # Check for Enable secret 5 (encrypted, non-decodable) + if ($line -match $regexEnableSecret) { + $object.PasswordEnc = $matches[1].Trim() + $object.ObjectName = "EnableSecret (MD5 Encrypted)" + $parsedPasswords += $object + } + + # Check for Enable password (cleartext or Type 7) + if ($line -match $regexEnablePassword) { + if ($matches[1] -eq "0" -or !$matches[1]) { # Handle both cleartext and cases without type indicator + $object.Password = $matches[2].Trim() + $object.ObjectName = "EnablePassword (Cleartext)" + } + elseif ($matches[1] -eq "7") { + $encodedPassword = $matches[2].Trim() + $decodedPassword = Decode-Type7 -EncodedPassword $encodedPassword + $object.Password = $decodedPassword + $object.PasswordEnc = $encodedPassword + $object.ObjectName = "EnablePassword (Type 7 Decrypted)" + } + $parsedPasswords += $object + } + + # Check for Username passwords (cleartext, Type 7, or secret 5/MD5) + if ($line -match $regexUsernamePassword) { + $object.Username = $matches[1].Trim() + if ($matches[2] -eq "0") { + $object.Password = $matches[3].Trim() + $object.ObjectName = "Username Password (Cleartext)" + } + elseif ($matches[2] -eq "7") { + $encodedPassword = $matches[3].Trim() + $decodedPassword = Decode-Type7 -EncodedPassword $encodedPassword + $object.Password = $decodedPassword + $object.PasswordEnc = $encodedPassword + $object.ObjectName = "Username Password (Type 7 Decrypted)" + } + elseif ($matches[2] -eq "5") { + # MD5 encrypted password (not decodable) + $object.PasswordEnc = $matches[3].Trim() + $object.ObjectName = "Username Password (MD5 Encrypted)" + } + $parsedPasswords += $object + } + + # Check for General password lines (cleartext or Type 7) + if ($line -match $regexGeneralPassword) { + if ($matches[1] -eq "0" -or !$matches[1]) { # Handle both cleartext and cases without type indicator + $object.Password = $matches[2].Trim() + $object.ObjectName = "Password (Cleartext)" + } + elseif ($matches[1] -eq "7") { + $encodedPassword = $matches[2].Trim() + $decodedPassword = Decode-Type7 -EncodedPassword $encodedPassword + $object.Password = $decodedPassword + $object.PasswordEnc = $encodedPassword + $object.ObjectName = "Password (Type 7 Decrypted)" + } + $parsedPasswords += $object + } + + # Check for Console password (cleartext or Type 7) + if ($line -match $regexConsolePassword) { + if ($matches[1] -eq "0" -or !$matches[1]) { # Handle both cleartext and cases without type indicator + $object.Password = $matches[2].Trim() + $object.ObjectName = "ConsolePassword (Cleartext)" + } + elseif ($matches[1] -eq "7") { + $encodedPassword = $matches[2].Trim() + $decodedPassword = Decode-Type7 -EncodedPassword $encodedPassword + $object.Password = $decodedPassword + $object.PasswordEnc = $encodedPassword + $object.ObjectName = "ConsolePassword (Type 7 Decrypted)" + } + $parsedPasswords += $object + } + + # Check for SNMP community strings (public/private with RO/RW) + if ($line -match $regexSnmpCommunity) { + $object.Password = $matches[1].Trim() + $object.ObjectName = "SNMP Community String ($($matches[2]))" + $parsedPasswords += $object + } + + # Check for WPA PSK Wi-Fi passwords (cleartext) + if ($line -match $regexWpaPsk) { + $object.Password = $matches[1].Trim() + $object.ObjectName = "Wi-Fi WPA Pre-Shared Key (Cleartext)" + $parsedPasswords += $object + } + } + + # Output the results + return $parsedPasswords +} + +<# Cisco Configuration Bonus Functions - PowerShell Type 7 Encoder/Decoder + +# Cisco Type 7 encryption key +$xlat = @( + 0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41, 0x2c, 0x2e, 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c, 0x64, + 0x4a, 0x4b, 0x44, 0x48, 0x53, 0x55, 0x42, 0x73, 0x67, 0x76, 0x63, 0x61, 0x36, 0x39, 0x38, 0x33, 0x34, 0x6e, 0x63, + 0x78, 0x76, 0x39, 0x38, 0x37, 0x33, 0x32, 0x35, 0x34, 0x6b, 0x3b, 0x66, 0x67, 0x38, 0x37 +) + +# Helper function to convert hex string to int +function HexToInt($hexStr) { + return [convert]::ToInt32($hexStr, 16) +} + +# Cisco Type 7 Password Decoder +function Decode-Type7 { + param ( + [string]$EncodedPassword + ) + + # Initialize decoded password + $decodedPassword = '' + + # Extract the seed and the encrypted portion + $seed = [convert]::ToInt32($EncodedPassword.Substring(0, 2)) # The first two characters as the seed + $encryptedPart = $EncodedPassword.Substring(2) + + # Loop through the encrypted part and decrypt each byte + for ($i = 0; $i -lt $encryptedPart.Length; $i += 2) { + $currentByte = HexToInt $encryptedPart.Substring($i, 2) + $decodedChar = [char]($currentByte -bxor $xlat[$seed]) + $decodedPassword += $decodedChar + $seed = ($seed + 1) % $xlat.Length # Reset seed if it reaches 51 + } + + return $decodedPassword +} + +# Cisco Type 7 Password Encoder +function Encode-Type7 { + param ( + [string]$PlainPassword + ) + + # Generate random seed between 0 and 15 + $seed = Get-Random -Minimum 0 -Maximum 15 + $encodedPassword = "{0:D2}" -f $seed # Append seed in two-digit format + + # Encrypt each character + for ($i = 0; $i -lt $PlainPassword.Length; $i++) { + $charValue = [byte][char]$PlainPassword[$i] + $encodedByte = $charValue -bxor $xlat[$seed] + $encodedPassword += "{0:X2}" -f $encodedByte + $seed = ($seed + 1) % $xlat.Length # Reset seed if it reaches 51 + } + + return $encodedPassword +} + +#>