Protecting Against Malicious Code Injection

Protecting Against Malicious Code Injection

Rate This
  • Comments 3

If you are writing scripts that accept input from users - you need to be aware of the potential dangers of Malicious Code-Injection.  Below is a good good article on this topic:

http://www.site-reference.com/articles/Website-Development/Malicious-Code-Injection-It-s-Not-Just-for-SQL-Anymore.html

Here is a line from that article: 

All code injection attacks work on the same principle: a hacker piggybacks malicious code onto good code through an input field in the application. Therefore, the protection instead has to come from the code within the application itself.

The basic idea is that you write a program or script which takes input from the user and then uses that input in a command.  An evil user pjrovides input which includes a statement terminator and then an evil command.  If the program/script doesn't protect against this - bad things can and do happen. 

The historical problem with protecting against code injection is that it relies upon the scripter to do this work and it is sometimes difficult to write this protection code.  PowerShell's parser was written to specifically protect you against Malicious Code Injection attacks (with no work on your part!).  There is one exception ("Invoke-Expression") that you need to be aware of and treat with the utmost of respect.  

Remember that the semicolon (";") is PowerShell's statement seperator.  The following illustrates how that works:
PS> Write-Host Message1; Write-Host Message2
Message1
Message2

When the parser sees the ";" it considers that the end of the first command and starts to parse the second command and then executes both of them.  For the next examples, I'll try to get PowerShell to run the evil command:  "Write-Host Busted".  Image that I have a script which takes user input and assigns it to $x and then uses $x as a parameter to a command (in this case we'll just use the Write-Host command but the principle works everywhere).

PS> $x = "this is a test"
PS> Write-host $x
this is a test

Now imagine a evil user tries to use inject some code:

PS> $x="Message1" ; Write-Host $x
Message1
PS> $x="Message1;Write-Host Busted" ; Write-Host $x
Message1;Write-Host Busted

Notice that it did not work - the entire string (statement terminator and all) was output.  The reason for this is that PowerShell's parser binds the value to the parameter - it doesn't replace the text in-line and THEN do the parse.  If you think about it - it has to.  Many of PowerShell parameters are OBJECTS (i.e. not strings) therefore it cannot do put the text in-line and parse - there is no text to put in-line.

NOTE:  The exception to this rule is INVOKE-EXPRESSION.  This will expand all variables and then do the parse (and thus is subject to Code Injection attacks).   Now Invoke-Expression can be extraordinarily powerful so it is not that you want to never use it but you need to be VERY VERY careful about using it.  In particular, you are probably on safe ground if the data ONLY comes from the program itself.  If you include any data provided from the user - you need to protect yourself from Code Injection.  Here is an example of the danger.


PS> $x="Write-Host Message1;Write-Host Busted" ; Invoke-Expression $x
Message1
Busted

The bottom line to all of this is that PowerShell's Parser provides intrinsic protection for a class of problems that use to be difficult to protect against.  We often get asked about the security of PowerShell and I point out a couple things:

  • First is that we are super humble about security.  The bad guys continue to get smarter so while we've done a ton of work and raised the bar signficantly, we'll always invest in security.
  • Second is that this project was started AFTER Bill's famous TrustWorthy Computing Memo so everyone got trained on security and everything was done with an eye towards security.
  • Third is that our security "buddy" is superstar Michael Howard ( http://www.microsoft.com/mspress/books/5957.aspx ).  You just don't get any better than that.  Full stop.

Anyway - there are lots of visible security features/elements in PowerShell (Secure by default, Execution Policies, Digitial Sigatures, warnings on scripts that get downloaded from the internet, double-clicking a script invokes notepad, etc, etc, etc) but there is also a ton of non-visible security features/elements as well. The way our parser protects scripts from malicious code injection is just one of those features. 

 Enjoy!

Jeffrey Snover [MSFT]
Windows PowerShell/MMC Architect
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Leave a Comment
  • Please add 4 and 7 and type the answer here:
  • Post
  • So let's say you have a situation where you _need_ to include user input in an invoke-expression statement.

    What would be the best approach to escaping the input? I imagine the usual characters like " ' ; etc would need to be backticked. Perhaps there needs to be a standard function for this kind of thing?

  • It really depends on what you mean by "include the user input". If you just want to use it as data, put it in a variable and then reference the variable:

    $i = read-host

    invoke-expression 'write-output $i'

    There is no need to quote the user's input since it's just a value. Of course there's also no reason to use invoke-expression in this case since

    write-output $i

    will work fine. Perhaps you can expand on the scenario where you need to include the user's input?

    -bruce

    --------------------------

    Bruce Payette [MSFT]

    PowerShell Technical Lead

    Microsoft Corp.

  • Another thing to keep in mind is what you consider to be your trust boundary.

    Most commonly, improper use of Invoke-Expression will just result in buggy code -- the user might use a semicolon and wonder why they are getting an error message. For that reason, you should avoid Invoke-Expression when dealing with user input unless necessary.

    If the user is running your script on their own machine under their own credentials, then you don't have to worry about the security aspects of Invoke-Expression, as they could just as easily do whatever they wanted to trick your script into anyways. If you've taken input from an untrusted user on the network, an untrusted user on a web page input field, or some other untrusted source, THEN you should be extremely conservative with what input you allow.

    Code injection attacks become attacks once they cross a trust boundary. If they don't cross a trust boundary, they are just a complicated and buggy way of doing what a user could already do.

    Lee

Page 1 of 1 (3 items)