|
| 1 | +<# |
| 2 | + ScipUtilities provides various utility commandlets. |
| 3 | +
|
| 4 | + Author: Eleanore Young, Michael Schneider, scip AG |
| 5 | + License: MIT |
| 6 | + Copyright: 2017 Eleanore Young, Michael Schneider, scip AG |
| 7 | + Required Dependencies: None |
| 8 | + Optional Dependencies: None |
| 9 | +#> |
| 10 | + |
| 11 | +#Requires -Version 5 |
| 12 | +Set-StrictMode -Version 5 |
| 13 | + |
| 14 | +function New-DomainAccountEntry { |
| 15 | + [CmdletBinding()] |
| 16 | + Param ( |
| 17 | + [ValidateNotNullOrEmpty()] |
| 18 | + [String] |
| 19 | + $Domain, |
| 20 | + |
| 21 | + [ValidateNotNullOrEmpty()] |
| 22 | + [String] |
| 23 | + $Username, |
| 24 | + |
| 25 | + [AllowEmptyString()] |
| 26 | + [String] |
| 27 | + $Password, |
| 28 | + |
| 29 | + [AllowEmptyString()] |
| 30 | + [String] |
| 31 | + $NtlmHash, |
| 32 | + |
| 33 | + [AllowEmptyString()] |
| 34 | + [String] |
| 35 | + $Sha1Hash |
| 36 | + ) |
| 37 | + |
| 38 | + New-Object -TypeName PSObject -Prop @{ |
| 39 | + 'Domain' = $Domain.ToUpper(); |
| 40 | + 'Username' = $Username; |
| 41 | + 'Password' = $Password; |
| 42 | + 'NTLM' = $NtlmHash; |
| 43 | + 'SHA1' = $Sha1Hash; |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | + |
| 48 | +function Select-MimikatzDomainAccounts { |
| 49 | +<# |
| 50 | + .SYNOPSIS |
| 51 | + Extract passwords or password hashes from Mimikatz log files. Developed for Mimikatz version 2.0 alpha. |
| 52 | +
|
| 53 | + .PARAMETER Path |
| 54 | + Choose the path or GLOB pattern that tells the function which files to search. |
| 55 | +
|
| 56 | + .PARAMETER HashcatSelect |
| 57 | + Choose to look for either passwords or hashes (ntlm and sha1). |
| 58 | +
|
| 59 | + .PARAMETER OutputTo |
| 60 | + Output the results either to the console, to a format parseable in hashcat, or to CSV. |
| 61 | +#> |
| 62 | + [CmdletBinding()] |
| 63 | + Param ( |
| 64 | + [ValidateNotNullOrEmpty()] |
| 65 | + [String] |
| 66 | + $Path = "*.log", |
| 67 | + |
| 68 | + [ValidateSet("console", "hashcat", "csv")] |
| 69 | + [String] |
| 70 | + $OutputTo = "console", |
| 71 | + |
| 72 | + [ValidateSet("ntlm", "sha1")] |
| 73 | + [String] |
| 74 | + $HashcatSelect = "ntlm" |
| 75 | + ) |
| 76 | + |
| 77 | + $DomainPasswordRegex = "\s+\*\s+Username\s+:\s+(?<username>[-_a-zA-Z0-9]+)[\r\n]+\s+\*\s+Domain\s+:\s+(?<domain>[a-zA-Z0-9]+)[\r\n]+\s+\*\s+Password\s+:\s+(?<password>(?!\(null\)).*)[\r\n]+" |
| 78 | + $DomainHashRegex = "\s+\*\s+Username\s+:\s+(?<username>[-_a-zA-Z0-9]+)[\r\n]+\s+\*\s+Domain\s+:\s+(?<domain>[a-zA-Z0-9]+)[\r\n]+(\s+\*\sFlags\s+:\s+.*[\r\n]+)?\s+\*\s+NTLM\s+:\s+(?<ntlm>[0-9a-fA-F]+)[\r\n]+\s+\*\sSHA1\s+:\s+(?<sha1>[0-9a-fA-F]+)[\r\n]+" |
| 79 | + |
| 80 | + $DomainAccounts = @{} |
| 81 | + Foreach ($LogFile in Get-ChildItem -Recurse $Path) { |
| 82 | + $Content = Get-Content -Raw -Path $LogFile |
| 83 | + |
| 84 | + $DomainPasswordMatches = Select-String -InputObject $Content -AllMatches -Pattern $DomainPasswordRegex |
| 85 | + if ($DomainPasswordMatches -ne $null) { |
| 86 | + Foreach ($Match in $DomainPasswordMatches.Matches) { |
| 87 | + $g = $Match.Groups |
| 88 | + $Username = $g["username"].Value |
| 89 | + if (!$DomainAccounts.ContainsKey($Username)) { |
| 90 | + $SearchEntry = New-DomainAccountEntry -Domain $g["domain"].Value -Username $Username -Password $g["password"].Value |
| 91 | + $DomainAccounts.Add($Username, $SearchEntry) |
| 92 | + } else { |
| 93 | + $SearchEntry = $DomainAccounts.Get_Item($Username) |
| 94 | + $SearchEntry.Password = $g["password"].Value |
| 95 | + $DomainAccounts.Set_Item($Username, $SearchEntry) |
| 96 | + } |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + $DomainHashMatches = Select-String -InputObject $Content -AllMatches -Pattern $DomainHashRegex |
| 101 | + if ($DomainHashMatches -ne $null) { |
| 102 | + Foreach ($Match in $DomainHashMatches.Matches) { |
| 103 | + $g = $Match.Groups |
| 104 | + $Username = $g["username"].Value |
| 105 | + if (!$DomainAccounts.ContainsKey($Username)) { |
| 106 | + $SearchEntry = New-DomainAccountEntry -Domain $g["domain"].Value -Username $Username -NtlmHash $g["ntlm"].Value -Sha1Hash $g["sha1"].Value |
| 107 | + $DomainAccounts.Add($Username, $SearchEntry) |
| 108 | + } else { |
| 109 | + $SearchEntry = $DomainAccounts.Get_Item($Username) |
| 110 | + $SearchEntry.NTLM = $g["ntlm"].Value |
| 111 | + $SearchEntry.SHA1 = $g["sha1"].Value |
| 112 | + $DomainAccounts.Set_Item($Username, $SearchEntry) |
| 113 | + } |
| 114 | + } |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + if ($DomainAccounts.Count -eq 0) { |
| 119 | + Write-Warning "Could not find any domain accounts." |
| 120 | + } else { |
| 121 | + $DomainAccounts = ($DomainAccounts.Values | Sort-Object -Property Username) |
| 122 | + } |
| 123 | + |
| 124 | + if ($OutputTo -eq "csv") { |
| 125 | + $DomainAccounts | ConvertTo-Csv -NoTypeInformation |
| 126 | + } elseif ($OutputTo -eq "hashcat") { |
| 127 | + if ($HashcatSelect -eq "ntlm") { |
| 128 | + Foreach ($Entry in $DomainAccounts) { |
| 129 | + $Entry.Username + ":" + $Entry.NTLM |
| 130 | + } |
| 131 | + } elseif ($HashcatSelect -eq "sha1") { |
| 132 | + Foreach ($Entry in $DomainAccounts) { |
| 133 | + $Entry.Username + ":" + $Entry.SHA1 |
| 134 | + } |
| 135 | + } else { |
| 136 | + throw "Format '$HashcatSelect' doesn't make sense for hashcat output." |
| 137 | + } |
| 138 | + } else { |
| 139 | + $DomainAccounts | Format-Table |
| 140 | + } |
| 141 | +} |
0 commit comments