2

I have the below powershell myscript.ps1 which I use to ask for username and password and depending on it it copies a file to a certain destination. I wanted to make this myscript.ps1 protected so no one can edit it and see the username and password and I found the solution found here which converts the powershell script to an .exe file. When I originally run the script using powershell the below credentials form appears allowing me to enter the username and password. But after the .exe is generated and when I run it the credentials form no longer appears, instead the cosole appears saying "Credential:" I don't know why? I want the credentials form to still appear when running the exe. Anythoughts please?

$credentials = Get-Credential
if ($credentials.Username -eq "user1" -And $credentials.GetNetworkCredential().password -eq "pass1") 
{ Copy-Item "test1.pdf" "\test\test1.pdf"; } 
else 
{ Copy-Item "test2.pdf" "\test\test2.pdf"; }

Output when running the script through powershell: enter image description here

Output when running the generated exe file:

enter image description here

5 Answers 5

4

Keeping passwords secret within source code

First, I'll try to address your direct question:

I wanted to make this myscript.ps1 protected so no one can edit it and see the username and password

I assume you don't really care about people actually editing/changing the script, but only want to keep the password secure. As Ben said, transforming it into an exe really doesn't do much to prevent extraction because you are still embedding the password in it.

What you really want is a password hash, which is a one-way function that transforms a password into a hash you can embed. Given only the hash, an attacker cannot reverse the process, but you can verify a password attempt by hashing the entered password and comparing it with the known hash of the correct password.

For example, pseudocode:

$authorisedHash = 'thehashedpassword';
$password = (Get-Credential).Password;
if ((Get-Hash $password) -eq $authorisedHash)
{
    echo 'Password correct';
}

Where $authorisedHash is the precalculated result of (pseudocode) Get-Hash that you store for later comparison.

Ideally, you'd use an algorithm such as Bcrypt or PBKDF2, with a high work factor (i.e. slow it down) so brute force attacks (guessing by trying every possible password) take too long to be feasible.

By this method, the only string you ever store in your code is the original output of whichever "Get-Hash" (pseudocode) function you happen to use, which makes it very difficult if not impossible to get the original password out of your source code.


Protecting a file with a password

However, while this keeps the password secret, it really doesn't offer any security advantage. As Ben said, there's really nothing stopping the user from manually running the Copy-Item, or even just copying the file themselves with Windows Explorer.

For this kind of security, you'd need to use Windows' Access Control Lists and a separate user account that's actually authenticated elsewhere (e.g. via Windows OS login/runas commands). You need an external service or account to perform the copy, because you need to make sure the user doesn't have direct access to bypass the script.

If this isn't possible for you (e.g. because you distribute the files along with the script, but you are not an admin of the machine), then what you should be doing is encrypting the file. By encrypting the file with the password, you make sure the file is useless without the password (and therefore copying the file is useless because it remains unreadable until decrypted).

Now, this could be done via PowerShell, but there are other, easier, ways. An easy generic method is to store the file within an encrypted archive, such as ZIP1, RAR, 7z, etc., where the user must provide the password to extract. Alternatively, PDFs themselves include support for encryption, requiring a password before they can be read.


1 Note that Windows' built-in crypto support for ZIP in XP to 7, possibly 8 and 10, does not support AES. It only supports the insecure legacy ZIP encryption. So you'll need third-party tools to extract, or a self-extracting archive (exe).

0

If a user can execute a script, they can read its contents. (You can only execute a script if you know what is says, otherwise you wouldn't know what to run.) Therefore, it is not possible to have a user simultaneously able to use your script and unable to read the password out of it. You could include the password as a cryptographic hash, but if that script runs as a normal user, the user could just bypass the script and copy test1.pdf to the destination without running your script at all.

Instead, you should apply file access controls to the destination files/folders to require the privileged operation run as an authenticated user. Then, you could supply the user-provided credential as Start-Job's -Credential parameter.

6
  • Thanks for your answer. I actually find a solution where the script can be converted to an exe as shown here: gallery.technet.microsoft.com/… but after I convert my script and run the resulted .exe file instead of the credentials appearing, the console appear saying "credintial:" not sure why the credentials form no longer appears? I'll updated my question
    – Tak
    Commented Oct 24, 2016 at 1:12
  • @Tak That converter hosts the script in a lightweight PowerShell host, which has fewer features than the real one. Also note that the resulting assembly "contains the source script encoded in Base64", which can be easily reversed to obtain any secrets therein.
    – Ben N
    Commented Oct 24, 2016 at 2:09
  • So it can't be edited to make it runs the real one?
    – Tak
    Commented Oct 24, 2016 at 2:11
  • @Tak It looks like the -noConsole switch for the generator script might enable a fancier credential prompt, but you still won't get all the features of the real PowerShell host. And, of course, the password will still be recoverable if it is usable by your script, no matter how obfuscated it is.
    – Ben N
    Commented Oct 24, 2016 at 2:15
  • > Therefore, it is not possible to have a user simultaneously able to use your script and unable to read the password out of it. -- it is possible, by means of a one-way hash (bcrypt, PBKDF2, etc.) instead of the direct string comparison currently used. But that would be rather meaningless as you say in your next sentence - without external authentication/access control, the user could simply copy the file directly. Actually, a better solution might be to encrypt the file using the password as the key. Which can be done within the PDF itself, too.
    – Bob
    Commented Oct 24, 2016 at 2:19
0

I don't think this is possible as I am also looking for the same solution. Certainly by converting your powershell script to an executable may prevent naked users from accessing your code directly however, like Bob said, it adds on complexity but does not deter users from disassembling the executable for the password. From security aspect, running non-approved executables on whitelisted computers will result in an event logged and forwarded to SIEM. Some organisations have powershell scripting disabled by GPO by default so I think we can appreciate the freedom.

Now trying to be constructive, I have two ideas.

1.I am thinking that maybe we can use DAC secure the file therefore only the Creator Owner, Administrator and System have RWX whereas other users will not have any access. The folder can also be configured to not inherit permission from its parent.

  1. We encrypt the content of the entire script using RSA and generate ourself a private key. Only the authentication script will be in plaintext and we must present a private key for powershell to decrypt and run. This can also be a red flag because EDR and administrators are unable to scan or decipher what you have encrypted. Depending on the length of script, decryption may be slow unless an efficient algorithm is chosen.
2
0

First, secrets of any kind should NEVER be stored in ANY SCRIPT using ANY language. Second, even making a PowerShell script an executable, it can be decoded and any secrets contained within are no longer secure.

All this being said, if a script needs to be prevented from being changed, it should be signed with a code signing certificate. If secrets are required to be use with the script, then the end user should provide them. If predefined credentials should be used, then they should be stored in an encrypted form and the script should have a method to retrieve those contents and decrypt them.

Being able to do this programmatically has challenges based on the method. Keeping the PowerShell in its original form, and simply asking for credentials in order to be used is standard script behavior.

-2

This site appears to protect a powershell script from being edited/modified.

I tested a couple of .ps1 scripts on a Windows 10 machine. These are my findings:

  1. Able to execute the protected scripts
  2. Protected scripts abort execution if an unauthorized change is detected

While this site does protect against modifications, there is a relatively common consensus out there that suggests any "protected" code by any entity out there in the wild, can always be hacked. Something to keep in mind. I have not tried to hack the test scripts I submitted (outside of attempting to modify them).

2
  • Obfuscating does not prevent editing, which is what OP was looking for. Commented Apr 4, 2022 at 1:06
  • actually, obfuscation does in fact prevent edits. when a script is obfuscated, and it is later edited or modified, it will stop functioning. It will essentially become useless to the person editing it. You can modify it all you want, it wont produce the results you're expecting. Why? Because, it is obfuscated. Converting a script into exe introduces portability problems.
    – Upendio
    Commented Apr 4, 2022 at 16:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .