diff --git a/src/System.Management.Automation/engine/serialization.cs b/src/System.Management.Automation/engine/serialization.cs index 716b8eb695..51538bfd66 100644 --- a/src/System.Management.Automation/engine/serialization.cs +++ b/src/System.Management.Automation/engine/serialization.cs @@ -2979,6 +2979,35 @@ namespace System.Management.Automation #endregion constructor + #region Known CIMTypes + + private static Lazy> s_knownCimArrayTypes = new Lazy>( + () => + new HashSet + { + typeof(Boolean), + typeof(byte), + typeof(char), + typeof(DateTime), + typeof(Decimal), + typeof(Double), + typeof(Int16), + typeof(Int32), + typeof(Int64), + typeof(SByte), + typeof(Single), + typeof(String), + typeof(TimeSpan), + typeof(UInt16), + typeof(UInt32), + typeof(UInt64), + typeof(object), + typeof(CimInstance) + } + ); + + #endregion + #region deserialization /// /// Used by Remoting infrastructure. This TypeTable instance @@ -3186,7 +3215,7 @@ namespace System.Management.Automation { return false; } - if (!originalArrayType.IsArray) + if (!originalArrayType.IsArray || !s_knownCimArrayTypes.Value.Contains(originalArrayType.GetElementType())) { return false; } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/corruptedcim.clixml b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/corruptedcim.clixml new file mode 100644 index 0000000000..b20c75e4b3 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/corruptedcim.clixml @@ -0,0 +1,58 @@ + + + + Microsoft.Management.Infrastructure.CimInstance + System.Object + + SomeClassName + + + SomeClassName + + + + + System.Windows.Markup.XamlReader[], PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + + + + <ResourceDictionary + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:System="clr-namespace:System;assembly=mscorlib" + xmlns:Diag="clr-namespace:System.Diagnostics;assembly=system"> + <ObjectDataProvider x:Key="LaunchCalc" + ObjectType="{x:Type Diag:Process}" + MethodName="Start"> + <ObjectDataProvider.MethodParameters> + <System:String>calc</System:String> + </ObjectDataProvider.MethodParameters> + </ObjectDataProvider> + <SolidColorBrush x:Key="ThemeBrushBlue" Color="{Binding Source={StaticResource LaunchCalc}}"/> + </ResourceDictionary> + + + + + + + + + System.Collections.ArrayList + System.Object + + + + + SomeClassName + SomeNamespace + + 460929192 + <CLASS NAME="SomeClassName"><PROPERTY NAME="test1" TYPE="string"></PROPERTY></CLASS> + + + + + + + diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 index 3093780b64..087e20755a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/clixml.tests.ps1 @@ -185,3 +185,52 @@ } } } + +## +## CIM deserialization security vulnerability +## +Describe "Deserializing corrupted Cim classes should not instantiate non-Cim types" -Tags "Feature","Slow" { + + BeforeAll { + + # Only run on Windows platform. + # Ensure calc.exe is avaiable for test. + if ( !$IsWindows -or ((Get-Command calc.exe 2>$null) -eq $null) ) + { + $orginalDefaultParameters = $PSDefaultParameterValues.Clone() + $PSDefaultParameterValues["it:skip"] = $true + } + else + { + (Get-Process -Name 'win32calc','calculator' 2>$null) | Stop-Process -Force -ErrorAction SilentlyContinue + } + } + + AfterAll { + + if ($orginalDefaultParameters -ne $null) + { + $PSDefaultParameterValues = $orginalDefaultParameters + } + else + { + (Get-Process -Name 'win32calc','calculator' 2>$null) | Stop-Process -Force -ErrorAction SilentlyContinue + } + } + + It "Verifies that importing the corrupted Cim class does not launch calc.exe" { + + Import-Clixml -Path (Join-Path $PSScriptRoot "assets\CorruptedCim.clixml") + + # Wait up to 10 seconds for calc.exe to run + $calcProc = $null + $count = 0 + while (!$calcProc -and ($count++ -lt 20)) + { + $calcProc = Get-Process -Name 'win32calc','calculator' 2>$null + Start-Sleep -Milliseconds 500 + } + + $calcProc | Should BeNullOrEmpty + } +}