Sign PowerShell script on non-Windows platform?
Asked Answered
A

2

7

I'm working on a project where we are remotely deploying software using a configuration management, part of which delivers PowerShell scripts to Windows servers, which are then executed in order to perform parts of our setup and/or configuration.

The current deployment method writes the scripts to disk, but doesn't close the file handle. This was done to make the script more "secure" by preventing any other process from tampering with the file prior to it being executed. In order to run the script, PowerShell must read it from stdin, since it doesn't run a script if it cannot get exclusive access. The invocation looks something like this:

powershell.exe -Command - < C:\temp\some_name.ps1

This has a number of drawbacks, primarily that I can't pass parameters to the script. Additionally, reading large scripts from stdin gets funky with bad characters, line returns, etc.

I'd like to invoke the scripts in a more traditional method, e.g.

powershell.exe -File C:\temp\some_name.ps1 -Param value ...

but also keep in the spirit of making sure nothing can tamper with the script prior to it being executed. To that end I want to sign the powershell script and run powershell with the "AllSigned" execution policy.

The issue lies is that I can't really sign the script on the target server, as it has the same issue as PowerShell running the script...I have to release the exclusive lock to let PowerShell sign the file, but it could get tampered with.

I then decided that if I could sign the script on the server that is delivering it to the target machine that would work much better. However, our configuration management software servers are all Linux, and I have been stumped trying to find some way of signing PowerShell scripts on Linux. Mono has support for Authenticode, but out of the box it's only for exes and dlls. I've tried digging into the PowerShell .Net functions but found they use Cryptui.dll, which is Windows-specific.

At this point I'm grasping for anyway I can get the signature added to the scripts, or else I'll have to fallback to some other way of running the scripts that isn't really native. If possible I'd like to be able to compute the signature in-memory on a string representation of the script, but I'll take a file-based method if that is all I can get.

Alsup answered 8/1, 2016 at 6:10 Comment(9)
We had to sign text files on publication and used a VBox Windows VM (with a SHA hashed file-based volume copied at startup), spin it up on the build machine, and used WinRb to execute Set-AuthenticodeSignature on the files, shut it down and threw away the file-based volume copy... really ugly but it work really well... eventually it was replaced with a custom version of osslsigncodeCymbal
I've been diving into the mono Authenticode classes and I think I have enough figured out to make a modified version that works on a data from stdin. I figured I'd have my configuration management software invoke the mono exe, pass the string in, and then read stdout for the signed version. Our configuration management software runs natively in ruby, so I'm tempted to try and build a ruby class using the openssl library to replicate the mono code.Alsup
Could you not prevent tampering by using folder security to block other accounts from having write access, or by hosting the script on a web server then executing with iex((New-Object System.Net.WebClient).DownloadString('https://myServer/myScript.ps1'))? You'd only need that in your signing script, which could then pull back the script and sign it as required; after which you can use per your description.Unkindly
I ended up extending the Authenticode capabilities in mono to allow it to sign files in addition to executables. It runs on our Linux deployment server and we can sign the scripts on the fly before pushing them to clients.Alsup
@AresonDeladious, have you published details of your solution in a blog or a GitHub project? I would be interested to see how you solved this problem, and I think I am not the only one interested! Thanks!Baumbaugh
@JayHaybatov Unfortunately no. At the time I was working for a company that was pretty tightfisted when it came to code written on company time, so publishing it was a no-no. The mono code-base has a tool that signs executables. From their you follow the classes/methods. It took me a day or two but you can alter it so the checks for being an .exe are ignored and it applies the signing to the file itself properly.Alsup
@JayHaybatov Actually, looking at the tool, it may have been updated such that you can just run it on a file? I'd give it a shot and go from there.Alsup
Unless something has changed recently, the execution policy can be bypassed by using the -bypassexecutionpolicy parameter, so signing your scripts and requiring scripts to be signed is a false sense of security anyway.Viole
@LarsPanzerbjrn I think in this case the deployment tool is calling Powershell itself with the "AllSigned" parameter so it should be fine. The issue was less about the scripts being called and the signature being bypassed as it was making sure the script wasn't modified on disk before it was called by the deployment tool.Alsup
P
1

Not sure if this will work for you, but any time I am getting signature errors, I just add this to the bottom of the script:

# SIG # Begin signature block
# SIG # End signature block

I know it looks benign, but this works for me.

Perjured answered 29/9, 2021 at 13:48 Comment(0)
M
0

What about compiling your script to .exe ?

ps2exe, or even some builtin .net calls can do that for you.

Mottled answered 22/6, 2017 at 18:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.