I read an interesting article on a flight back home yesterday which detailed a brazen bank heist in Russia in which the bank robbers used remote PowerShell commands to instruct an ATM to spit out hundreds of thousands of dollars in cash. Interestingly the ATM itself wasn’t hacked in a way that I expected where someone gained access to an input panel and loaded up some malware, instead the hackers had managed to get into the broader bank network, create a series of tunnels to eventually get to the ATM network and issue the commands. This specific attack used malware that self deleted, but either by mistake or code error left some logs behind which allowed security researchers to back track and figure out what went wrong. You can read the full article here.
This got me wondering, in a world of secure network deployments – where there may be some tunneling from other networks, how can I protect systems from executing malicious code from a remote source. The most obvious answer is to block the PowerShell Remoting and WinRM ports on the firewall from the broader network (Ports 5985 and 5986 for HTTP and HTTP/s respectively). That should generally protect the systems unless the Firewall is compromised, or physical access to the servers is obtained. This is a nice solution since it doesn’t restrict me from being able to use Remote PowerShell sessions when an authorized party has access to the system.
I can also change these from the default to obfuscate them somewhat from the outside. This is a good security practice since using default ports just makes things easy for an attacker – and the more road blocks we put up the less likely they are to be successful. We can change the port for WinRM using the following command
Set-Item WSMan:\localhost\listener\*\Port 8282
You’ll want to replace * with the auto-completed Listener name (if you have an HTTP and an HTTP/s listener), and you’ll have to run it once for the HTTP listener, then run it again with a different port for the HTTP/s listener if one exists. In my case I don’t yet have an HTTP/s WinRM listener configured so I can get away with using the wildcard.
Restarting the WinRM service is required, and can be done with the following command
Now when I’m initiating a Remote PowerShell session, I need to ensure I’m specifying the now non-standard port by using the -Port switch in Enter-PSSession
Enter-PSSession -ComputerName MyServer -Port 8282
This puts me in a fairly comfortable position now in the event that someone does gain access to my closed network and attempts to do some PowerShell remoting. My final step to really help me sleep at night is to make sure that when I am using PowerShell remote sessions I’m doing so securely, lest a pesky network sniffer gain valuable intel on the system based on my administrative work. To do this, I’m going to use a couple Group Policy objects to ensure the WinRM Service isn’t accepting insecure connections, in case I forget to connect securely during a 3AM emergency service call.
Within my default domain policy, I’ll configure a couple settings:
Computer Configuration\Policies\Administrative Templates\Windows Components\Windows Remote Management (WinRM)\WinRM Service\Allow Basic Authentication -> Disabled
Computer Configuration\Policies\Administrative Templates\Windows Components\Windows Remote Management (WinRM)\WinRM Service\Allow CredSSP Authentication -> Disabled
Computer Configuration\Policies\Administrative Templates\Windows Components\Windows Remote Management (WinRM)\WinRM Service\Allow Unencrypted Traffic -> Disabled
Now that we’ve made these changes in the GPO, I’ll have to go configure WinRM for HTTP/s on my original server. There’s a great Microsoft Support article on the subject here but for brevity, here’s the steps
- Launch the Certificates Snapin for Local Computer
- Ensure within Personal\Certificates a Server Authenticating certificate exists, if not request one through your domain CA
- Use this command to quick configure WinRM
winrm quickconfig -transport:https
Now when I connect I’ll need to ensure that I use the following command
Enter-PSSession -ComputerName MyServer -Port 8282 -UseSSL
It’s not perfect, and it wont stop everyone, but as my father used to say it’s just enough to keep the honest people honest. For those going the less than honest route, I also found this white paper from the Black Hat USA 2014 conference on Investigating PowerShell Attacks to be extremely interesting.
There’s a few good resources out there on the security considerations of remote PowerShell sessions, specifically this one from JuanPablo Jofre on MSDN, and this one from Ed Wilson, of Scripting Guys.