About the risks of executing commands remotely

Edited by: Andrew Leniart
This is a comparison of three common ways to run commands remotely on Windows machines. I will look at the risks, that are involved and make a recommendation based on that.

Target audience: Windows system admins, network admins, security admins
Every admin will sooner or later feel the need to run a script on all client computers: you would like to push a piece of software/update or you are trying to read out the version of a certain driver or whatever you feel your other automated IT tools cannot do for you.

How can you accomplish that?
What ways are possible from remote out of the box, with default settings on cleanly installed clients?

Out of the box, exactly nothing seems possible.
The windows firewall is not pre-configured to offer any way in, even for admins.
Instead, to run a script from remote, we need to open certain ports on the targets.
So let me look at two popular "from remote" ways and their requirements and later compare them to an alternate way, that results in the same scripts being run but this time initiated by the clients, not from remote.

Literally, for ages, PsExec was the very tool to turn to, when you wanted to run commands on remote systems. The 1st version was released about 20 years ago and it still gets updated today! Startable from the command prompt, needing no helper software but a single executable at your disposal, free to download from Microsoft themselves, well-documented, it was hard to beat.

Its requirements were:
  • The account you execute it with had to be admin on the remote system
  • File sharing ("SMB", opened by the service called simply "server") and with it, port 445 needs to be accessible (with a writable share!) on the remote system
A modern, much more comfortable way to run commands from remote is PowerShell.

PowerShell can do "everything and more," and of course, it can initiate sessions on remote systems, enabling you to run all commands as if you sat in front of those.
Its requirements are similar:

  • The account you execute it with has to be admin on the remote system
  • Port(s) 5985(/5986 if going via https) will need to be accessible. The service listening on that port is called windows remote management ("WinRM") and it's not running by default on clients (on server machines, it is!*).

So you'll need to allow windows remote management, first, before you can use remote PowerShell against your clients.

 *In case you wonder why your server has this port open by default - well, Microsoft designed the (local) server manager application to work with this port in order to perform management actions against groups of servers over the network. However, we may tune the firewall rule for it and make that port accessible only from localhost, which will allow the local server manager to work but keep the port inaccessible from remote, which is safer!
Looking back and comparing: for both, we need to be admin on ALL target machines AND we need to either activate file sharing (remote access to local files) or remote management, which allows so many things, PowerShell just being one of them. Like this siteputs it;
you can effortlessly start and and stop processes, check configurations and system status, perform maintenance, install or remove services.. just about anything!

Be aware that this is very risky. 
Imagine, you needed to occasionally run commands from remote, would you dare to open up these ports for good and keep them open?

I wouldn't. As soon as someone compromises the admin account and uses it on the right machine, the whole network may fall with it.

If you are a fan of these two remoting techniques already, please verify:
Did you make sure that you configured these ports to be accessible only from your administrative workstation?

Let's not fly over this last one. Again: If your network is set up using no firewall and these services run, that's very dangerous.

If however your firewall is active and will only allow access to WinRM or SMB based on IP-Addresses, that's still dangerous, since an attacker in the know could simply spoof that IP address, so even when the attacker has not managed to compromise your admin credentials, he might still be able to exploit 0-day vulnerabilities of these services, effectively entering "god-mode" on all machines. This has happened before and will happen again!

So please, if you insist to continue and use these ways of remote commands, do yourself a favor and use firewall rules with authentication (like those, that the windows firewall calls "secure connections") instead of using IP-based rules!
Did I scare you? I hope so! :-) And I have not even begun to talk you out of the ill concept of using those two with accounts, that have admin status anywhere... But rather than doing that, I will now describe the alternative, which is able to execute the same scripts without needing any open ports at the clients and even without using administrative accounts. 

While the aforementioned two ways are both "push mechanisms" initiated from remote, let's look at a "pull mechanism", initiated at the targets. You don't need to run a script, that targets remote machines on your administrative workstation, but instead you let the remote machine itself run it.

This concept is so simple, but still, I am under the impression, that hardly anyone uses it.

So let me show you in detail.
In my domain network, I simply use a GPO for remote maintenance, let's call it "Maintenance". Inside the GPO, in the computer configuration part within the preferences section, you find a section "Scheduled Tasks" below "Control Panel Settings".

Now what many don't seem to know is the option to configure clients to run an "immediate task", a task, that runs as soon as the GPO applies.

And we may configure that task action to run as a system account, which is at least as powerful as a local admin account.

[We may even trigger clients to apply the task right now by enforcing a gpupdate right at the DC (in GPMC, right-click the OU, select "Group Policy Update"), if, yes if (you might have guessed it) a certain port (TCP 135) is open, so, well, let's not get tempted again, will we?]
OK, now you try this. Start with something simple, a one-liner PowerShell script, that displays a local pop-up message "test".

Please note: "Immediate Task (at least Windows 7)" is the one, not "...Windows XP"

Make sure to set the system account as executor

           It's important, that the arguments are put into the arguments line, NOT into the                           Program/Script line!

I suggest using this line as example code for \\server\scriptshare\test.ps1:

msg /time:0 * test

               On the "Common" tab, you may select to run the task only once, if you don't intend to repeat it. Use item level targeting, if you intend to run the command at certain machines only as opposed to the whole OU.
               Example for an item-level targeting filter

At the next GPO background refresh, the task runs and your script is executed.
So in our example, the message box "test" is displayed. Be aware, that the immediate tasks do show up in task scheduler only for about one minute, then their trigger expires and they auto-delete (see next screenshot)

GPO refresh intervals are adjustable. By default, they are set to 90 minutes with randomization (so not exactly 90 minutes, but sometimes 30 minutes later, sometimes 30 minutes earlier),

Can you wait that long? Why shouldn't you, which task is so urgent, that it couldn't wait another 90 minutes?

But let's assume you really wanted to apply the policy, that runs the script, immediately. In this case, you would need to notify anyone "please restart your machine now", which will trigger a GPO refresh on reboot! For those of you who consider this to be a disadvantage - let me remind you, that for Remote PowerShell / PsExec, all machines need to be turned on at the time of script execution (can you guarantee that, with all your remote users?), while the task gets them all, without you having to turn on a single machine!
I think this demonstration will have convinced you, that it works.
Now let us come back to a different aspect:
How do we set which machines this will run on?

With PowerShell/PsExec, you would possibly run the script against a list of computer names, if you only wanted to target a few. Can we do the same here?
Yes, of course. If you have security groups already at hand, that you want to target (like for example a group "accounting" which holds the computers of accountants), you would use GPP item-level targeting and only let the task be created on those.
Within item level targeting, there are several other filters possible, that will help you.
Of course, you may also apply the task to all machines and simply let the script-logic decide whether to run or jump to the end of the script.
Finally, since security is the main aspect, let me point out one more thing:
Since these tasks run as the system account, it should be obvious, that the script needs to be placed on a share, that is accessible by system accounts (group: "domain computers") read-only! Never let anyone but domain admins write to these scripts.
So let me show you how the share ACL should look like in case you are in doubt:

Remote PowerShell and PsExec are tools, that make the admin's life easier. Still, they are hard to use without being global admin and rely on ports, that are too dangerous to be kept open if you don't have to... and you don't!
I have described an alternative, that eliminates this risk while it maintains the same functionality.


Comments (1)

NVITEnd-user support

Thanks for this, McKnife. Task runs as System. Thinking... If script needs to write to shared log, may need NET USE to connect, which needs a password. Maybe best to write to local TEMP?

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.

Get access with a 7-day free trial.
You Belong in the World's Smartest IT Community