diff --git a/Scripts/ConfigParsers/parser-cisco-config.ps1 b/Scripts/ConfigParsers/parser-cisco-config.ps1 new file mode 100644 index 0000000..d848712 --- /dev/null +++ b/Scripts/ConfigParsers/parser-cisco-config.ps1 @@ -0,0 +1,316 @@ +# 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 + ) + + # 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 + } + + # 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 +} + +# Command Example +# Get-PwGrubConfig -FilePath "C:\temp\runing-config" -ComputerName "MyComputer" -ShareName "MyShare" -FileName runing-config + +<# Example startup config + +! +! Cisco IOS Software, C3560 Software (C3560-IPBASEK9-M), Version 15.0(2)SE11 +! Compiled Mon 28-Mar-21 08:55 by prod_rel_team +! +version 15.0 +service timestamps debug datetime msec +service timestamps log datetime msec +no service password-recovery +service password-encryption +! +hostname Router1 +! +enable secret 5 $1$DkGh$XSdDk6LdoqM0eO67V0lJ71 +enable password mycleartextpassword +! +no aaa new-model +! +! +username admin privilege 15 password 0 cleartext123 +username cisco privilege 15 password 7 12140A05171F15142F7C343F +username secureadmin secret 5 $1$lpb1$kGc1R/tGbT6aYZEXw5lqa0 +! +ip ssh version 2 +ip domain-name example.com +! +interface GigabitEthernet0/0 + description Uplink to ISP + ip address 192.168.1.1 255.255.255.0 + duplex auto + speed auto +! +interface GigabitEthernet0/1 + description Internal LAN + ip address 192.168.2.1 255.255.255.0 + duplex auto + speed auto +! +ip route 0.0.0.0 0.0.0.0 192.168.1.254 +! +snmp-server community public RO +snmp-server community private RW +! +line con 0 + exec-timeout 0 0 + password consolepassword123 + logging synchronous + login +! +line vty 0 4 + password 7 02050D4808091B385C4B5E1A09121319 + logging synchronous + login + transport input ssh +! +interface Vlan1 + ip address 192.168.3.1 255.255.255.0 + no shutdown +! +dot11 ssid MySSID + authentication open + authentication key-management wpa + wpa-psk ascii 0 cleartextkeywifipassword +! +banner motd ^C +*********************************************** + Unauthorized access is prohibited! +*********************************************** +^C +! +end + + + +#> + +<# 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 +} +#>