PowerShell Transcription to a file share breaks everything, and how to fix it

There’s been a bit of noise about PowerShell-based malware recently, and given the “assume breach” security mindset, I thought it was about time I enabled some of the PowerShell logging features in Windows. The basis behind “assume breach” is that you assume that your network security has already been breached and there are unauthorised things going on in your environment. The trick is to put in place suitable logging and monitoring to be able to detect and trace that activity.

The definitive source for PowerShell security config seems to still be the PowerShell (heart) the Blue Team blog post from mid-2015. This gives a lot of good info about what security features are available in PowerShell 5.0 and how to enable them in a sensible way. Most of them can be configured by Group Policy, e.g. transcription is enabled and configured via “Turn on PowerShell Transcription” in Windows Components – Administrative Templates – Windows PowerShell.

Based on that, and other things I’d read, PowerShell transcription to a network share seemed like exactly what I should have turned on. It gives you a detailed text log of everything that occurs in a PowerShell session, logged to an off-the-box location. Very handy.

So I turned it on.

And lots of things broke.

Enter-PSSession : Processing data from remote server ServerA failed with the following error message:
Could not find a part of the path '\\ServerB.rcmtech.co.uk\PowerShellTranscript$'. For more information, see the
about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ enter-pssession -ComputerName ServerA
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (Server01:String) [Enter-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : CreateRemoteRunspaceFailed

The problem seems to be with how I admin my servers (remotely, not on the console) and how the transcription feature works.

The root of my problems seem to be Kerberos double-hop authentication.

Consider how you might have done similar things in the past:

  • From your PC, remote desktop onto ServerA, access a share on ServerB. No problems.
  • From your PC, run PSExec to get a remote command prompt on ServerA, access a share on ServerB. No problems.
  • Set the logging folder of a service running as NT Authority\System on ServerA to write to a UNC path on ServerB, having granted the account ServerA$ permission to the share and granted NTFS permissions to the folder. No problems.
  • Forwarded Windows Event Logs from ServerA to ServerB, and noticed how details of people interacting with ServerA appeared in Forwarded Events on ServerB. No problems.

So why is PowerShell transcription different? The transcription is done by delegation of the credentials from my PC by ServerA and using those to try to access the share on ServerB. This won’t work: assume I’m running PowerShell as an admin on my PC (OK, not best practice, but fixing that is going to take a long time) and that I then run the following command:

Invoke-Command -ComputerName ServerA -ScriptBlock {Get-ChildItem -Path \\ServerB\c$}

This will fail with an Access is Denied (PermissionDenied) error.

There are various ways to make the double-hop work. As far as I can tell, the best balance of security and ease of use is to use Resource-Based Kerberos Constrained Delegation.

This works by configuring the Active Directory computer object of ServerB to allow it to accept delegated credentials via ServerA:

Set-ADComputer -Identity ServerB -PrincipalsAllowedToDelegateToAccount (Get-ADComputer -Identity ServerA)

Possibly followed by running the following on ServerA:

klist purge -li 0x3e7

but only if you’d tried and failed to use delegated credentials from ServerA in the past 15 minutes. If you’d not tried to do that, the klist command is unecessary.

Also, annoyingly, this method will not allow you to enter a remote session from your PC to ServerA and then create a remote session from ServerA to ServerB. Resource-based Kerberos constrained delegation does not support WinRM, you’ll get a 0x8009030e error (a specified logon session does not exist).

So if you want all your servers to send their PowerShell transcripts to ServerB, you need to add all your servers to the list of PrincipalsAllowedToDelegateToAccount for ServerB, and keep adding new servers to that list as they are created. Pain in the neck.

How I’d like transcription to work is that the transcripts are written by the computer account where the PowerShell is being executed. I would have thought that this was possible, because the computer account is the NT Authority\System account, and that is as powerful and privileged an account as you can get in Windows. That way I would just configure the transcripts file share to have write access for the Domain Computers group, and everything would be well with the world.

This entry was posted in PowerShell, Security and tagged , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.