Monday, November 16, 2015

Powershell: Script injection with ScriptBlock.CheckRestrictedLanguage Method

I just had a post about importing hashtables from files. It basically loads the file into a script block and executes it. 

$content = Get-Content -Path $Path -Raw -ErrorAction Stop
$scriptBlock = [scriptblock]::Create($content)
$scriptBlock.CheckRestrictedLanguage([string[]]@(), [string[]]@(), $false)
Write-Output (& $scriptBlock

If that sounds dangerous, that is because it is. Your module or script my be trusted, but it may be loading files that are not trusted. This could be a stealthy way for an attacker to use your script.

I took the extra step of using $scriptBlock.CheckRestrictedLanguage([string[]]@(), [string[]]@(), $false) to make sure the hashtable is not containing Powershell commands. There is one important gotcha to be aware of with this command. The arguments are not intuitive. 

Lets take this command. Here is how the function is defined using a C# sample:

public:
void CheckRestrictedLanguage (
        IEnumerable allowedCommands,
        IEnumerable allowedVariables,
        bool allowEnvironmentVariables
)

The first argument is the allowed commands and the second is the allowed variables. One could reasonably assume that a $null value for the allowed commands would mean that nothing is allowed.

If you look at my code, I create an empty string array. That may look like a very strange thing to do and I kind of agree. This is because a $null value indicates that it should allow some default commands to execute. The only way to know this one is to read the documentation very closely. https://msdn.microsoft.com/en-us/library/system.management.automation.scriptblock.checkrestrictedlanguage(v=vs.85).aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-2

By using an empty list of strings, I do not allow any Powershell commands. When importing a hashtable, this is exactly what I want.

No comments: