For those of us that work with the PowerShell console daily, it’s the little things that matter. One of the littlest is the humble up-arrow key. Small though it may be, it delivers our console history and thereby saves us untold thousands of keystrokes inserting previously-typed code into the session when we need it – with just a little push. But nothing is perfect and, since the history was stored in memory, all our recent commands were lost when the console window was closed. But all things change and, with Windows 10 and Windows 2012, we got PowerShell v5. This gave us a PowerShell console with a whole bunch of new and improved features. One of those features was a module loaded by default named PSReadline.
The PSReadline module is great in many ways. It expands the use of color in the console and generally gives more control over console behavior than we ever had before. There’s even a neat little ‘beep’ that you can turn on if you are into beeps. I mean, most people hate it. But if that’s your thing, go nuts. No judgments. Anyway, one of the more impactful features of the PSReadline module is having a console history that’s persistent — and I mean really persistent. Unlike before where closing the console window meant your command history was lost forever, now you can close and reopen the console session and your history is still there; just a mere up-arrow away. If you use the Clear-History command, the history remains. How about logging out? Yep, still there. Taking the nuclear option and rebooting the system will surely clear it, right? Not so much — your command history survives. Pretty neat right? Well, kind of.
But what if you don’t want to save your command history? This is where the titular ‘Danger’ comes into play. Perhaps you fudged the rules a little and used your own password in a plain text string (for shame!). Or maybe you thought it would be cute to name a function using a NSFW verb and now want to erase the evidence before HR finds out. Or maybe you are just a security nerd like me and feel better clearing the table after dinner, so to speak. Whatever the reason, there is one thing you should know:
By default, the PSReadline module saves every console command you enter to a text file.
That’s right. Saving the command history to a text file is the default setting since PowerShell v5. You don’t have to do a thing…the commands just accumulate there. With most applications, something like this would present little more than a marginal risk. But, given that PowerShell console work is done, almost exclusively, by users with administrator-level permissions, the risk is (IMO) very high. All it would take is one mistake. Just one. You inadvertently enter your domain admin password in the wrong place and that’s it. The password is silently saved to the file and just sits there, waiting to be found.
“Okay,” you say. “that’s good to know. What do I do about it?”
That’s a great question. I like your attitude. It’s refreshing in these troubled times. But I digress. The first line of defense in mitigating any possible security vulnerability is information gathering. So let’s gather us up some information, shall we?
The default name of the log file is ConsoleHost_history.txt but the location can be different based on a few different factors (e.g. remote session, GPO). Before doing anything else, you should confirm the location on your system by running the Get-PSReadlineOption like this:
You can call the value of the HistorySavePath property to see where the command log is being saved on your system.
So we know where the log is. Now what? Well, you have a few options for mitigating this vulnerability.
Note: All of the options listed here require making modifications to your PowerShell profile. If you are not familiar with PowerShell profiles, stop right now and read more about them here. Go ahead, I’ll wait. Done? Super. Let’s continue.
- Change the log path location using the Set-PSReadlineOption command:
- You can change the default location to somewhere less snoopable.If you go this route, I’d recommend you map the log file to a removable drive with Bitlocker enabled. This will give you, and only you, access to your logged commands but in such a way that no one else can see them. It’s also important to remember that this change is specific to the session where the change was made. If you want to make it (sort of) permanent, add the same command to your PowerShell profile so it executes automatically whenever a console session starts.
- Change the HistorySaveStyle parameter using the Set-PSReadlineOption command:
- Change the value of HistorySaveStyle to “SaveNothing” to, well, save nothing.This tells the PSReadline module to behave in a way similar to before — only maintain a command history in memory; saving nothing to a file. This is the option I prefer as it leaves the other features of PSReadline intact, while completely removing the potential security problem that comes with saving command history to disk. Just as the first option, this would be added to your PowerShell profile and automatically invoked for each new console session.
- Remove the PSReadline module using Remove-Module:
- Note the PSReadline module listed but after Remove-Module used, it’s not. This is a good thing.Short of downgrading your version of PowerShell (not recommended), this is the most drastic option. By adding the command to your PowerShell profile, the entire PSReadline module will be removed. Note that this will also do away with other features of the module like that you might actually like.
So there you have the skinny on PSReadline. It’s always a good idea to examine new features closely and try to think ‘how could this be exploited?’. Most of the time, the effort involved in exploiting some vulnerability far exceeds any conceivable benefit. But, in this case, I think it is quite the opposite.