I was playing around with hash tables in PowerShell, and I noticed some odd behavior related to accessing items. As we know, PowerShell allows at least three different ways of assigning values to hash table entries:
$hashtable["foo"] = "bar" #1
$hashtable.Item("foo") = "bar" #2
$hashtable.foo = "bar" #3
Meanwhile, we use the #3 syntax to access the properties of the Hashtable object itself, such as Count
, Keys
, Values
, etc. And if we add an item with the key that conflicts with the name of an internal property, PowerShell allows us to do so, and we effectively are no longer able to read the value of the property (except using Reflection).
I guess that in a situation where the keys come from an untrustworthy source (e.g. from external file or network), this might have an undesired impact on flow control, and could probably be exploited by a malicious user.
This snippet demonstrates the issue:
function Get-HashtableProperties($hashTable, $header)
{
"{0} {1} {0}" -f ("-" * 10), $header
"Count : {0}" -f $hashtable.Count
"Keys.Count : {0}" -f $hashtable.Keys.Count
"Values.Count : {0}" -f $hashtable.Values.Count
"Actual Count (Reflection) : {0}" -f $hashtable.GetType().GetProperty("Count").GetValue($hashtable)
"`nItems (Keys iteration):"
$hashtable.Keys | ForEach-Object { " [ {0} = {1} ]" -f $_, $hashtable.Item($_) }
"`nItems (Enumerator iteration):"
$enumerator = $hashTable.GetEnumerator()
while ($enumerator.MoveNext())
{
" [ {0} = {1} ]" -f $enumerator.Current.Key, $enumerator.Current.Value
}
}
$fileContent = @"
Foo = a
Bar = b
"@
$maliciousFileContent = @"
Foo = a
Bar = b
Count = 0
Keys =
Values =
"@
$hashtable = ConvertFrom-StringData $fileContent
$damagedHashtable = ConvertFrom-StringData $maliciousFileContent
Get-HashtableProperties $hashtable "Normal Hash Table"
Get-HashtableProperties $damagedHashtable "Damaged Hash Table"
Output:
---------- Normal Hash Table ----------
Count : 2
Keys.Count : 2
Values.Count : 2
Actual Count (Reflection) : 2
Items (Keys iteration):
[ Bar = b ]
[ Foo = a ]
Items (Enumerator iteration):
[ Bar = b ]
[ Foo = a ]
---------- Damaged Hash Table ----------
Count : 0
Keys.Count : 1
Values.Count : 1
Actual Count (Reflection) : 5
Items (Keys iteration):
[ = ]
Items (Enumerator iteration):
[ Count = 0 ]
[ Bar = b ]
[ Foo = a ]
[ Values = ]
[ Keys = ]
Question: is there a way to protect against this issue, except manually checking every key before assignment and/or using Reflection everywhere in the code when we need to access the value of some Hashtable
property?
In this sort of a scenario you can access the Hashtable's count property like so:
C:\PS> $ht = @{Count = 99}
$ht.psbase.Count
1
The extended type system in PowerShell offers several different views on an object via these PS* properties. See the PowerShell team blog post for details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With