New PowerShell History Defense Evasion Technique

Carrie Roberts //

PowerShell incorporates the handy feature of writing commands executed to a file to make them easy to refer back to later. This functionality is provided by the PSReadline module. This feature is helpful from a usability perspective but can be a tool that hackers use against you.

For example, if sensitive information like passwords are entered into the PowerShell command line, they will also be added to the history file and a hacker can review this history to discover that sensitive information.

In an effort to solve this issue, the PSReadline module version v2.0.4+ will skip adding a command line to the history file if it contains sensitive words like (more info here):

  • Password
  • Asplaintext
  • Token
  • Apikey
  • Secret

PowerShell v7.0.11+ ships with a PSReadline version that supports this feature out-of-the-box, but Windows PowerShell version 5.1 ships with PSReadline version 2.0.0 and doesn’t support this feature, however it can easily be updated.

Let’s see the sensitive history scrubbing in action.

In the image above, we ran three commands, one of which contained one of the words that trigger the “sensitive” filter. Notice that the password line is not listed when we “cat” (aka print to screen) the history file.

This is kind of nifty, but it also makes for a really easy defense evasion technique where a hacker can control which of their commands show up in the history file.

In the image above, we were able to keep the second command from being recorded in the history file by simply adding a comment containing one of the “sensitive” words.

This really isn’t an earth-shattering discovery because attackers have always been able to open the history file and individually remove commands from it if they wanted to. Nevertheless, this does make this defense evasion tactic even easier and is a trick that I would use on my next red teaming engagement.

Another interesting option for defense evasion is to define your own code for deciding whether a command is written to the history file. We could disable all history logging for the current session as follows:

  • Set-PSReadLineOption -AddToHistoryHandler { return $false }

The “AddToHistoryHandler” receives the current command as the $line variable and then returns $true if the line should be written to the history file. Here we simply return $false so nothing gets added to the history file for the current session. On the defensive side, we could keep an eye out for any funny business when the AddToHistoryHandler parameter is used. In fact, keeping an eye on the use of all the PSReadLineOption functions would probably be a good idea. Here are a few more examples of defense evasion.

Prevent logging: Set-PSReadlineOption -HistorySaveStyle SaveNothing

Delete history file: Remove-Item (Get-PSReadlineOption).HistorySavePath

Set alternate file path: Set-PSReadLineOption -HistorySavePath $env:TEMP\out.txt

Use ContrainedLanguage mode: $ExecutionContext.SessionState.LanguageMode = “ConstrainedLanguage”

If you are interested in learning more about PowerShell topics such as ‘Just Enough Admin’, PowerShell remoting, language modes and more, check out my 16-hour course called “PowerShell For InfoSec” here.



You can learn more from Carrie in her classes!

Check them out here:

Attack Emulation Tools: Atomic Red Team, CALDERA and More 

PowerShell for InfoSec

Available live/virtual and on-demand!