Confusion about PowerShell Script Signing

I’ve been having fun writing about my adventures in PowerShell. I would like to thank everyone for their encouragement and feedback. Something that I haven’t explicitly stated – which should go without saying as this is a blog – is that I am not a PowerShell expert. This is one man’s journey learning about PowerShell. I consider myself an expert on C#, .NET, and many other things, but as for PowerShell, I am a hacker. I learn enough to get the job done.

Yes, I wrote psake, which is a cool little PowerShell-based build tool, if I do say so myself. I wrote it in part to learn more about PowerShell and what was possible. (I surprised myself that I was able to write a task-based build system in a few hours with about 100 lines of PowerShell, ignoring comments.)

If you’re looking for PowerShell gospel, I would recommend checking out the Windows PowerShell Blog (the blog of Jeffrey Snover and the rest of the PowerShell team), Windows PowerShell in Action by Bruce Payette, the PowerScripting Podcast, or any of the myriad PowerShell MVP blogs. They are the experts. I’m just a hacker having fun.

With that disclaimer, I hope that by documenting my PowerShell learnings in public, I will help other developers learn PowerShell. I know that I am learning great things about PowerShell from my readers. In Getting Started with PowerShell – Developer Edition, I lamented the lack of grep. My friend, Chris Tavares – known for his work on Unity and ASP.NET MVC – pointed out that Select-String can perform similar functions. Awesome! Then in PowerShell, Processes, and Piping, Jeffrey Snover himself pointed out that PowerShell supports KB, MB, and GB – with TB and PB in v2 – so that you can write:

get-process | where { $_.PrivateMemorySize –gt 200MB }

rather than having to translate 200MB into 200*1024*1024 as I originally did. Fantastic!

In Writing Re-usable Scripts with PowerShell, wekempf, Peter, and Josh discussed the merits of setting your execution policy to Unrestricted. I corrected the post to use RemoteSigned, which means that downloaded PowerShell scripts have to be unblocked before running, but local scripts can run without requiring signing/re-signing. Thanks, guys. I agree that RemoteSigned is a better option.

Let’s talk security for a second. I am careful about security. I run as a normal user on Vista and have a separate admin account. When setting up teamcity.codebetter.com, the build agent runs under a least privilege account, which is why we can’t run NCover on the build server yet. (NCover currently requires admin privs, though Gnoso is working on fixing that in short order.) (Imagine if we did run builds as an Administrator or Local System. Someone could write a unit test that added a new user with admin privs to the box, log in remotely and start installing bots, malware, and other evil.) So I tend to be careful about security.

Now for my real question… What is the threat model for PowerShell that requires script signing? Maybe I’m being really dense here, but I don’t get it. Let’s say I want to do something really evil like formatting your hard drive. I create a PowerShell script with “format c:” in it, exploit a security vulnerability to drop it onto your box, and exploit another security vulnerability to launch PowerShell to execute the script. (Or I name it the same as a common script, but earlier in your search path, and wait for you to execute it.) But you’ve been anal-retentive about security and only allow signed scripts. So the script won’t execute. Damn! Foiled again! But wait! Let me just rename it from foo.ps1 to foo.cmd or foo.bat and execute it from cmd.exe. If I can execute code on your computer, there are easier ways for me to do bad things than writing PowerShell scripts. Given that we can’t require signing for *.cmd and *.bat files as this would horribly break legacy compatibility, what is the advantage of requiring PowerShell scripts to be signed by default? Dear readers, please enlighten me!

UPDATE: Joel “Jaykul” Bennett provided a good explanation in the comments. I would recommend reading:

http://blogs.msdn.com/powershell/archive/2008/09/30/powershell-s-security-guiding-principles.aspx

as it exlains the PowerShell Team’s design decision. The intention wasn’t to force everyone to sign scripts, but to disable script execution for most users (as they won’t use PowerShell), but allow PowerShell users to opt into RemoteSigned or Unrestricted as they so choose. Script signing is meant for administrators to set group policy and use signed scripts for administration (as one example use case of script signing).

Thanks again, Joel! That was faster than sifting through the myriad posts on script signing trying to find the reasoning behind it. Once again, the advantages of learning as a community!

About James Kovacs

James Kovacs is a Technical Evangelist for JetBrains. He is passionate in sharing his knowledge about OO, SOLID, TDD/BDD, testing, object-relational mapping, dependency injection, refactoring, continuous integration, and related techniques. He blogs on CodeBetter.com as well as his own blog, is a technical contributor for Pluralsight, writes articles for MSDN Magazine and CoDe Magazine, and is a frequent speaker at conferences and user groups. He is the creator of psake, a PowerShell-based build automation tool, intended to save developers from XML Hell. James is the Ruby Track Chair for DevTeach, one of Canada’s largest independent developer conferences. He received his Bachelors degree from the University of Toronto and his Masters degree from Harvard University.
This entry was posted in PowerShell. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://HuddledMasses.org Joel "Jaykul" Bennett

    You can pass the CONTENTS of a script as a -Command parameter to PowerShell. The purpose of signed scripts is about which scripts you trust. If a malicious user can execute a process on your computer, they own you already — this isn’t meant to prevent that.

    http://blogs.msdn.com/powershell/archive/2008/09/30/powershell-s-security-guiding-principles.aspx

    The scenario script signing protects against is where you’re using a network share, or you’ve shared out a folder … and someone copies a script there — maybe even overwriting one of your scripts (like your Profile.ps1), or putting something like “notepad.ps1″ in your path environment.

    Script signing keeps YOU from accidentally running someone else’s script that you didn’t intentionally trust. It doesn’t keep someone else from running a script on your PC.

  • http://www.jameskovacs.com james.kovacs

    @wekempf – I’m not taking you to task for pointing it out. You rightly questioned my post about changing to Unrestricted rather than RemoteSigned.

    I’m just honestly confused about what evil script signing is preventing. Is the plan to remove *.cmd and *.bat support from Windows? Or require those to be signed? As for email, probably not a good idea, as you mentioned. Scripts on a share make more sense, but I would then argue that RemoteSigned should be the default rather than Restricted.

    Why do I feel like they’ve installed an industrial-strength bank-grade door in back, but left the front door wide open?

  • http://wekempf.spaces.live.com wekempf

    Incremental improvement? Yes, cmd and bat scripts can be run unsigned. So they shouldn’t be “executable” in many “environments” such as from an e-mail. However, since ps1 scripts can be signed, an e-mail program *could* allow ps1 scripts to be run. Not saying it should, only that it could. Another scenario is scripts on a network share. To be executed, I believe these would need to allow RemoteSigned was would protect you from code dropped to a compromised machine when your own hasn’t been. Just some thoughts.

    I’m not defending the PS security model. Nor am I claiming to be an expert on security. My original comment was only that if you tell people to turn it off, you should at least explain that this bypasses what ever security model PS did have, and warn that the user should make such a decision for themselves. IOW, just tell them there’s various options and point them at a resource to figure it out for themselves, then say we’re going to take the easy way out and turn it off.