Disable the debugger when in system lock-down mode (#9645)

Disable the debugger when in system lock-down mode

Fixing master for CVE-2019-0733
This commit is contained in:
Travis Plunk 2019-05-22 15:19:23 -07:00 committed by GitHub
parent dbbb5110bf
commit bb726da6fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 248 additions and 457 deletions

View file

@ -1132,12 +1132,16 @@ namespace System.Management.Automation
internal Breakpoint NewCommandBreakpoint(string path, string command, ScriptBlock action)
{
WildcardPattern pattern = WildcardPattern.Get(command, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
CheckForBreakpointSupport();
return AddCommandBreakpoint(new CommandBreakpoint(path, pattern, command, action));
}
internal Breakpoint NewCommandBreakpoint(string command, ScriptBlock action)
{
WildcardPattern pattern = WildcardPattern.Get(command, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
CheckForBreakpointSupport();
return AddCommandBreakpoint(new CommandBreakpoint(null, pattern, command, action));
}
@ -1175,6 +1179,7 @@ namespace System.Management.Automation
{
Diagnostics.Assert(path != null, "caller to verify path is not null");
CheckForBreakpointSupport();
return AddLineBreakpoint(new LineBreakpoint(path, line, action));
}
@ -1182,6 +1187,7 @@ namespace System.Management.Automation
{
Diagnostics.Assert(path != null, "caller to verify path is not null");
CheckForBreakpointSupport();
return AddLineBreakpoint(new LineBreakpoint(path, line, column, action));
}
@ -1201,11 +1207,13 @@ namespace System.Management.Automation
internal Breakpoint NewVariableBreakpoint(string path, string variableName, VariableAccessMode accessMode, ScriptBlock action)
{
CheckForBreakpointSupport();
return AddVariableBreakpoint(new VariableBreakpoint(path, variableName, accessMode, action));
}
internal Breakpoint NewVariableBreakpoint(string variableName, VariableAccessMode accessMode, ScriptBlock action)
{
CheckForBreakpointSupport();
return AddVariableBreakpoint(new VariableBreakpoint(null, variableName, accessMode, action));
}
@ -1761,12 +1769,6 @@ namespace System.Management.Automation
originalLanguageMode = _context.LanguageMode;
_context.LanguageMode = PSLanguageMode.FullLanguage;
}
else if (System.Management.Automation.Security.SystemPolicy.GetSystemLockdownPolicy() ==
System.Management.Automation.Security.SystemEnforcementMode.Enforce)
{
// If there is a system lockdown in place, enforce it
originalLanguageMode = Utils.EnforceSystemLockDownLanguageMode(this._context);
}
// Update the prompt to the debug prompt
if (hadDefaultPrompt)
@ -2060,6 +2062,17 @@ namespace System.Management.Automation
{
lock (_syncObject)
{
// Disable script debugger when in system lock down mode
if (IsSystemLockedDown)
{
if (_context._debuggingMode != (int)InternalDebugMode.Disabled)
{
_context._debuggingMode = (int)InternalDebugMode.Disabled;
}
return;
}
switch (mode)
{
case InternalDebugMode.InPushedStop:
@ -2086,6 +2099,24 @@ namespace System.Management.Automation
}
}
private static bool IsSystemLockedDown
{
get
{
return (System.Management.Automation.Security.SystemPolicy.GetSystemLockdownPolicy() ==
System.Management.Automation.Security.SystemEnforcementMode.Enforce);
}
}
private static void CheckForBreakpointSupport()
{
if (IsSystemLockedDown)
{
// Local script debugging is not supported in locked down mode
throw new PSNotSupportedException();
}
}
#region Enable debug stepping
[Flags]
@ -2323,6 +2354,15 @@ namespace System.Management.Automation
{
lock (_syncObject)
{
// Restrict local script debugger mode when in system lock down.
// DebugModes enum flags provide a combination of values. To disable local script debugging
// we have to disallow 'LocalScript' and 'Default' flags and only allow 'None' or 'RemoteScript'
// flags exclusively. This allows only no debugging 'None' or remote debugging 'RemoteScript'.
if (IsSystemLockedDown && (mode != DebugModes.None) && (mode != DebugModes.RemoteScript))
{
mode = DebugModes.RemoteScript;
}
base.SetDebugMode(mode);
if (!CanEnableDebugger)

View file

@ -18,10 +18,89 @@ try
$defaultParamValues = $PSDefaultParameterValues.Clone()
$PSDefaultParameterValues["it:Skip"] = !$IsWindows
Describe "Trusted module on locked down machine should not expose private functions to script debugger command processing" -Tags 'CI','RequireAdminOnWindows' {
Describe "Local script debugger is disabled in system lock down mode" -Tags 'CI','RequireAdminOnWindows' {
BeforeAll {
# Invoke-LanguageModeTestingSupportCmdlet definition
$languageModeCmdletDef = @'
using System;
using System.Globalization;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security;
using System.Runtime.InteropServices;
using System.Threading;
using System.Management.Automation;
/// <summary>Adds a new type to the Application Domain</summary>
[Cmdlet("Invoke", "LanguageModeTestingSupportCmdlet")]
public sealed class InvokeLanguageModeTestingSupportCmdlet : PSCmdlet
{
[Parameter()]
public SwitchParameter EnableFullLanguageMode
{
get { return enableFullLanguageMode; }
set { enableFullLanguageMode = value; }
}
private SwitchParameter enableFullLanguageMode;
[Parameter()]
public SwitchParameter SetLockdownMode
{
get { return setLockdownMode; }
set { setLockdownMode = value; }
}
private SwitchParameter setLockdownMode;
[Parameter()]
public SwitchParameter RevertLockdownMode
{
get { return revertLockdownMode; }
set { revertLockdownMode = value; }
}
private SwitchParameter revertLockdownMode;
protected override void BeginProcessing()
{
if(enableFullLanguageMode)
{
SessionState.LanguageMode = PSLanguageMode.FullLanguage;
}
if(setLockdownMode)
{
Environment.SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", EnvironmentVariableTarget.Machine);
}
if(revertLockdownMode)
{
Environment.SetEnvironmentVariable("__PSLockdownPolicy", null, EnvironmentVariableTarget.Machine);
}
}
}
'@
if (-not (Get-Command Invoke-LanguageModeTestingSupportCmdlet -ea Ignore))
{
$languageModeModuleName = "LanguageModeModule"
$modulePath = [System.IO.Path]::GetFileNameWithoutExtension([IO.Path]::GetRandomFileName())
$script:moduleDirectory = join-path "$PSScriptRoot\$modulePath" $languageModeModuleName
if (-not (Test-Path $moduleDirectory))
{
$null = New-Item -ItemType Directory $moduleDirectory -Force
}
try
{
Add-Type -TypeDefinition $languageModeCmdletDef -OutputAssembly $moduleDirectory\TestCmdletForConstrainedLanguage.dll -ErrorAction Ignore
} catch {}
Import-Module -Name $moduleDirectory\TestCmdletForConstrainedLanguage.dll
}
# Debugger test type definition
$debuggerTestTypeDef = @'
using System;
@ -33,29 +112,14 @@ try
public class DebuggerTester
{
private Runspace _runspace;
private readonly string _privateFnName;
[Flags]
public enum TestResults
{
NoResult = 0x0,
DebuggerStopHandled = 0x1,
PrivateFnFound = 0x2
};
public TestResults TestResult
public int DebuggerStopHitCount
{
private set;
get;
}
public Exception ScriptException
{
private set;
get;
}
public DebuggerTester(Runspace runspace, string privateFnName)
public DebuggerTester(Runspace runspace)
{
if (runspace.Debugger == null)
{
@ -63,363 +127,160 @@ try
}
_runspace = runspace;
_privateFnName = privateFnName;
_runspace.Debugger.DebuggerStop += (sender, args) =>
{
try
{
// Within the debugger stop handler, make sure trusted private functions are not accessible.
string commandText = string.Format(@"Get-Command ""{0}""", _privateFnName);
PSCommand command = new PSCommand();
command.AddCommand(new Command(commandText, true));
PSDataCollection<PSObject> output = new PSDataCollection<PSObject>();
_runspace.Debugger.ProcessCommand(command, output);
if ((output.Count > 0) && (output[0].BaseObject is CommandInfo))
{
TestResult |= TestResults.PrivateFnFound;
}
}
catch (Exception e)
{
ScriptException = e;
System.Console.WriteLine(e.Message);
}
TestResult |= TestResults.DebuggerStopHandled;
DebuggerStopHitCount += 1;
};
}
}
}
'@
$modulePath = Join-Path $TestDrive Modules
if (Test-Path -Path $modulePath)
{
try { Remove-Item -Path $modulePath -Recurse -Force -ErrorAction SilentlyContinue } catch { }
}
$script = @'
"Hello"
Wait-Debugger
"Goodbye"
'@
$scriptFilePath = Join-Path $TestDrive TScript.ps1
$script > $scriptFilePath
# Trusted module
$trustedModuleName = "TrustedModule_System32"
$trustedModuleDirectory = Join-Path $modulePath $trustedModuleName
New-Item -ItemType Directory -Path $trustedModuleDirectory -Force -ErrorAction SilentlyContinue
$trustedModuleFilePath = Join-Path $trustedModuleDirectory "$($trustedModuleName).psm1"
$trustedManifestFilePath = Join-Path $trustedModuleDirectory "$($trustedModuleName).psd1"
@'
function PublicFn {
Write-Output PrivateFn "PublicFn"
}
function PrivateFn {
param ([string] $msg)
Write-Output $msg
}
'@ > $trustedModuleFilePath
$modManifest = "@{ ModuleVersion = '1.0'" + ("; RootModule = '{0}'" -f $trustedModuleFilePath) + "; FunctionsToExport = 'PublicFn' }"
$modManifest > $trustedManifestFilePath
# Create test runspace
[runspace] $runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
# Create debugger test object
# Define debugger test type
Add-Type -TypeDefinition $debuggerTestTypeDef
}
AfterAll {
if ($runspace -ne $null) { $runspace.Dispose() }
}
It "Verifies that private trusted module function is not available in script debugger" {
# Run debugger access test
$debuggerTester = [TestRunner.DebuggerTester]::new($runspace, "PrivateFn")
# Script to invoke the script debugger so that $debuggerTester can handle
# the debugger stop event and test for access of private functions within the
# script debugger command processor.
$script = @'
Import-Module -Name HelpersSecurity
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
Import-Module -Name {0} -Force
Set-PSBreakpoint -Command PublicFn
PublicFn
'@ -f $trustedManifestFilePath
[powershell] $ps = [powershell]::Create()
$ps.Runspace = $runspace
try
if (($script:moduleDirectory -ne $null) -and (Test-Path $script:moduleDirectory))
{
$ps.AddScript($script).BeginInvoke()
# Wait for debugger test result for up to ten seconds
$count = 0
while (($debuggerTester.TestResult -eq 0) -and ($count++ -lt 40))
{
Start-Sleep -Milliseconds 250
}
try { Remove-Item -Path $moduleDirectory -Recurse -Force -ErrorAction SilentlyContinue } catch { }
}
finally
{
# Revert lockdown
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
}
# Verify that PrivateFn function name is not accessible
$debuggerTester.TestResult | Should -Match "DebuggerStopHandled"
$debuggerTester.TestResult | Should -Not -Match "PrivateFnFound"
$debuggerTester.ScriptException | Should -BeNullOrEmpty
}
}
Describe "Cross language debugger get-item commands should not have access to FullLanguage trusted functions through provider" -Tags 'Feature','RequireAdminOnWindows' {
BeforeAll {
# Trusted module that will always run in FullLanguage mode
$scriptModuleName = "ImportTrustedModuleForTestA_System32"
$moduleFilePath = Join-Path $TestDrive ($scriptModuleName + ".psm1")
$script = @'
function PublicFn { "PublicFn"; PrivateFn }
function PrivateFn { "PrivateFn" }
Export-ModuleMember -Function PublicFn
'@
$script > $moduleFilePath
# Import and run module function script
$scriptIM = @'
Import-Module -Name {0} -Force
$null = Set-PSBreakpoint -command PublicFn
PublicFn
'@ -f $moduleFilePath
# Debugger stop event handler object.
$type = @'
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
public class DebuggerStopEventHandler
{
private Runspace _runspace;
public object GetItemResult
{
get;
internal set;
}
public object GetChildItemResult
{
get;
internal set;
}
public object CopyItemResult
{
get;
internal set;
}
public object FunctionVariableResult
{
get;
internal set;
}
public object RenameItemResult
{
get;
internal set;
}
public DebuggerStopEventHandler(Runspace runspace)
{
_runspace = runspace;
_runspace.Debugger.DebuggerStop += (sender, args) =>
{
var debugger = sender as Debugger;
PSDataCollection<PSObject> output = new PSDataCollection<PSObject>();
PSCommand command = new PSCommand();
command.AddScript(@"Get-Item -Path function:\PrivateFn 2>&1");
debugger.ProcessCommand(command, output);
GetItemResult = (output.Count > 0) ? (output[0].BaseObject) : null;
command.Clear();
output.Clear();
command.AddScript(@"Get-ChildItem -Path function:\PrivateFn 2>&1");
debugger.ProcessCommand(command, output);
GetChildItemResult = (output.Count > 0) ? (output[0].BaseObject) : null;
command.Clear();
output.Clear();
command.AddScript(@"Copy-Item -Path function:\PrivateFn -Destination function:\MyPrivateFn 2>&1");
debugger.ProcessCommand(command, output);
CopyItemResult = (output.Count > 0) ? (output[0].BaseObject) : null;
command.Clear();
output.Clear();
command.AddScript(@"${function:\PrivateFn}");
debugger.ProcessCommand(command, output);
FunctionVariableResult = (output.Count > 0) ? (output[0].BaseObject): null;
command.Clear();
output.Clear();
command.AddScript(@"Rename-Item -Path function:\PrivateFn -NewName function:\MyPrivateFn -Passthru 2>&1");
debugger.ProcessCommand(command, output);
RenameItemResult = (output.Count > 0) ? (output[0].BaseObject) : null;
};
}
public void Reset() { GetItemResult = null; GetChildItemResult = null; CopyItemResult = null; }
}
'@
try { Add-Type -TypeDefinition $type } catch { }
# Create runspace and debugger event handler
[runspace] $rs = [runspacefactory]::CreateRunspace($host)
$rs.Open()
$rs.Debugger.SetDebugMode(@('LocalScript','RemoteScript'))
$debuggerStopHandler = [DebuggerStopEventHandler]::New($rs)
# Create PowerShell to run module script
[powershell] $ps = [powershell]::Create()
$ps.Runspace = $rs
$ps.AddScript($scriptIM)
}
AfterAll {
if ($rs -ne $null) { $rs.Dispose() }
if ($ps -ne $null) { $ps.Dispose() }
}
It "Verifies that same language mode trusted public functions *are* accessible from debugger through Get-Item, Get-ChildItem, Copy-Item, Rename-Item, Variable" {
# Test
$results = $ps.Invoke()
# Results. Only PublicFn is returned since PrivateFn is renamed.
$results[0] | Should Be "PublicFn"
# Expected Get-Item function:\PrivateFn returns FunctionInfo object
($debuggerStopHandler.GetItemResult -is [System.Management.Automation.FunctionInfo]) | Should Be $true
# Expected Get-ChildItem function:\PrivateFn returns FunctionInfo object
($debuggerStopHandler.GetChildItemResult -is [System.Management.Automation.FunctionInfo]) | Should Be $true
# Expected Copy-Item function:\PrivateFn succeeds with no error output
$debuggerStopHandler.CopyItemResult | Should Be $null
# Expected function variable succeeds
($debuggerStopHandler.FunctionVariableResult -is [scriptblock]) | Should Be $true
# Expected Rename-Item function:\PrivateFn returns FunctionInfo object
($debuggerStopHandler.RenameItemResult -is [System.Management.Automation.FunctionInfo]) | Should Be $true
}
It "Verifies that cross language mode trusted public functions *are not* accessible through Get-Item, Get-ChildItem, Copy-Item, Rename-Item, Variable" {
# Test
$debuggerStopHandler.Reset()
try
{
$rs.LanguageMode = "ConstrainedLanguage"
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
$results = $ps.Invoke()
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
}
# Results
$results[0] | Should Be "PublicFn"
$results[1] | Should Be "PrivateFn"
# Expected Get-Item function:\PrivateFn returns error
$debuggerStopHandler.GetItemResult.FullyQualifiedErrorId | Should Be "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand"
# Expected Get-ChildItem function:\PrivateFn returns error
$debuggerStopHandler.GetChildItemResult.FullyQualifiedErrorId | Should Be "PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand"
# Expected Copy-Item fails with error output
$debuggerStopHandler.CopyItemResult.FullyQualifiedErrorId | Should Be "PathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand"
# Expected function variable fails
$debuggerStopHandler.FunctionVariableResult | Should Be $null
# Expected Rename-Item function:\PrivateFn fails with error
$debuggerStopHandler.RenameItemResult.FullyQualifiedErrorId | Should Be "PathNotFound,Microsoft.PowerShell.Commands.RenameItemCommand"
}
}
Describe "Cross language debugger Action scripts should not have access to FullLanguage trusted functions through provider" -Tags 'Feature','RequireAdminOnWindows' {
BeforeAll {
# Trusted script that will always run in FullLanguage mode
$scriptFileName = "TrustedScriptForTestB_System32"
$scriptFilePath = Join-Path $TestDrive ($scriptFileName + ".ps1")
$script = @'
function PublicFn { PrivateFn -typeDef 'public class Hello { public new static void ToString() { System.Console.WriteLine("Hello!"); } }'; [Hello]::ToString(); }
function PrivateFn { param ([string]$typeDef) Add-Type -TypeDefinition $typeDef }
PublicFn
"Complete"
'@
$script > $scriptFilePath
}
AfterAll {
Get-PSBreakpoint | Remove-PSBreakpoint
}
It "Verifies that debugger stop Action scriptblock cannot access PrivateFn" {
It "Verifies that Set-PSBreakpoint Line is disabled on locked down system" {
try
{
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
# Set breakpoint on script
Set-PSBreakpoint -Script $scriptFilePath -Line 4 -Action {
& (Get-Item -Path function:\PrivateFn) -typeDef @'
public class Foo {
public new static void ToString() {
System.Console.WriteLine("pwnd!");
}
}
'@
}
# Run script
& $scriptFilePath
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
}
try
{
# Verify that Action scriptblock did not create Foo type using PrivateFn
[Foo]::ToString()
Set-PSBreakpoint -Script $scriptFilePath -Line 1
throw "No Exception!"
}
catch
{
$_.FullyQualifiedErrorId | Should Be "TypeNotFound"
$expectedError = $_
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
}
$expectedError.FullyQualifiedErrorId | Should Be 'NotSupported,Microsoft.PowerShell.Commands.SetPSBreakpointCommand'
}
It "Verifies that Set-PSBreakpoint Statement is disabled on locked down system" {
try
{
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
Set-PSBreakpoint -Script $scriptFilePath -Line 1 -Column 1
throw "No Exception!"
}
catch
{
$expectedError = $_
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
}
$expectedError.FullyQualifiedErrorId | Should Be 'NotSupported,Microsoft.PowerShell.Commands.SetPSBreakpointCommand'
}
It "Verifies that Set-PSBreakpoint Command is disabled on locked down system" {
try
{
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
Set-PSBreakpoint -Command $scriptFilePath
throw "No Exception!"
}
catch
{
$expectedError = $_
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
}
$expectedError.FullyQualifiedErrorId | Should Be 'NotSupported,Microsoft.PowerShell.Commands.SetPSBreakpointCommand'
}
It "Verifies that Set-PSBreakpoint Variable is disabled on locked down system" {
try
{
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
Set-PSBreakpoint -Variable HelloVar
throw "No Exception!"
}
catch
{
$expectedError = $_
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
}
$expectedError.FullyQualifiedErrorId | Should Be 'NotSupported,Microsoft.PowerShell.Commands.SetPSBreakpointCommand'
}
It "Verifies that Wait-Debugger is disabled on locked down system" {
try
{
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
# Create test runspace
[runspace] $runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
# Attach TestRuner.DebuggerTester DebugStop event handler to runspace
$debuggerTester = [TestRunner.DebuggerTester]::new($runspace)
# Run $scriptFilePath script with 'Wait-Debugger' in locked down mode
[powershell] $ps = [powershell]::Create()
$ps.Runspace = $runspace
$null = $ps.AddScript('"Hello"; Wait-Debugger; "Goodbye"').Invoke()
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
if ($runspace -ne $null) { $runspace.Dispose() }
if ($ps -ne $null) { $ps.Dispose() }
}
# Debugger should not have been active in lockdown mode
$debuggerTester.DebuggerStopHitCount | Should Be 0
}
}
}
finally
{
if ($defaultParamValues -ne $null)
if ($null -ne $defaultParamValues)
{
$Global:PSDefaultParameterValues = $defaultParamValues
}

View file

@ -365,116 +365,6 @@ try
}
}
Describe "Script debugging in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
It "Verifies that a debugging breakpoint cannot be set in constrained language and no system lockdown" {
try
{
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
function MyDebuggerFunction {}
Set-PSBreakpoint -Command MyDebuggerFunction
throw "No Exception!"
}
catch
{
$expectedError = $_
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
}
$expectedError.FullyQualifiedErrorId | Should -BeExactly "CannotSetBreakpointInconsistentLanguageMode,Microsoft.PowerShell.Commands.SetPSBreakpointCommand"
}
It "Verifies that a debugging breakpoint can be set in constrained language with system lockdown" {
try
{
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
function MyDebuggerFunction2 {}
$Global:DebuggingOk = $null
$null = Set-PSBreakpoint -Command MyDebuggerFunction2 -Action { $Global:DebuggingOk = "DebuggingOk" }
MyDebuggerFunction2
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
}
$Global:DebuggingOk | Should -BeExactly "DebuggingOk"
}
It "Verifies that debugger commands do not run in full language mode when system is locked down" {
try
{
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
function MyDebuggerFunction3 {}
& {
$null = Set-PSBreakpoint -Command MyDebuggerFunction3 -Action { $Global:dbgResult = [object]::Equals("A", "B") }
$restoreEAPreference = $ErrorActionPreference
$ErrorActionPreference = "Stop"
MyDebuggerFunction3
}
throw "No Exception!"
}
catch
{
$expectedError = $_
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
if ($restoreEAPreference -ne $null) { $ErrorActionPreference = $restoreEAPreference }
}
$expectedError.FullyQualifiedErrorId | Should -BeExactly "CannotSetBreakpointInconsistentLanguageMode,Microsoft.PowerShell.Commands.SetPSBreakpointCommand"
}
It "Verifies that debugger command injection is blocked in system lock down" {
$trustedScriptContent = @'
function Trusted
{
param ($UserInput)
Add-Type -TypeDefinition $UserInput
try { $null = New-Object safe_738057 -ErrorAction Ignore } catch {}
try { $null = New-Object pwnd_738057 -ErrorAction Ignore } catch {}
}
Trusted -UserInput 'public class safe_738057 { public safe_738057() { System.Environment.SetEnvironmentVariable("pwnd_738057", "False"); } }'
"Hello World"
'@
$trustedFile = Join-Path $TestDrive CommandInjectionDebuggingBlocked_System32.ps1
try
{
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
Set-Content $trustedScriptContent -Path $trustedFile
$env:pwnd_738057 = "False"
Set-PSBreakpoint -Script $trustedFile -Line 12 -Action { Trusted -UserInput 'public class pwnd_738057 { public pwnd_738057() { System.Environment.SetEnvironmentVariable("pwnd_738057", "Pwnd"); } }' }
& $trustedFile
}
finally
{
Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
}
$env:pwnd_738057 | Should -Not -Be "Pwnd"
}
}
Describe "Engine events in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
It "Verifies engine event in constrained language mode, its action runs as constrained" {