PowerShell在任意字符串中安全扩展非打印字符



我在XML文件中有数据,最终将用作注册表路径,该路径可能包含非打印字符(例如,将路径从网站复制到XML中时)。如果发现非打印字符,我想验证数据并抛出一个特定的错误。

在Powershell中,如果我在单引号中定义一个非打印字符的变量,然后test-Path,它作为有效路径进行测试,因为非打印字符被作为文字处理。

Test-Path 'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE' -isValid

同样的东西用双引号将"展开"。非打印字符并返回false,这正是我需要的。

Test-Path "HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE" -isValid

我发现[string]::Format(()被用来扩展非打印字符,但是

$invalidPath = 'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE'
[string]::Format("{0}",$invalidPath)

不按预期展开非打印字符。我也看到使用Invoke-Expression的参考,但这是不安全的,也不是一个选择。

最后我发现$ExecutionContext.InvokeCommand.ExpandString(),这似乎工作,

$ExecutionContext.InvokeCommand.ExpandString('HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE')

返回一个多行字符串到控制台,而$ExecutionContext.InvokeCommand.ExpandString('Write-Host "Screwed"')将实际字符串返回到控制台,而不是实际执行Write-Host,只将Screwed返回到控制台。

最后,

$invalidPath = 'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid

按预期返回false。这让我认为这是要追求的正确方法,但考虑到其他地方的所有陷阱,我想100%确定这种方法没有办法被用作安全弱点。我是在正确的轨道上,还是有我的Google-Fu还没有发现的问题?

Invoke-Expression一样,$ExecutionContext.InvokeCommand.ExpandString()也容易被注入不需要的命令,只是在后一种情况下,这些命令只有包含在$(...)(子表达式操作符)中才能被识别,因为这是将命令嵌入可扩展字符串(方法的参数被解释为)的唯一方法。

例如:

$ExecutionContext.InvokeCommand.ExpandString('a $(Write-Host -Fore Red Injected!) b')
防止这种情况的一个简单方法是对所有嵌入的$字符进行分类处理。逐字,通过使用`: 转义
'a $(Write-Host -Fore Red Injected!) b',
'There''s no place like $HOME',
'Too `$(Get-Date) clever by half' |
  ForEach-Object {
    $ExecutionContext.InvokeCommand.ExpandString(($_ -replace '(`*)$', '$1$1`$$'))
  }

注意:在输入字符串中转义逐字$就足够了。$(或(/)) (`u{24}(或`u{28}/`u{29}),在PowerShell (Core) v6+仅支持)的Unicode转义序列表示中,不需要关注,因为PowerShell将生成的字符逐字处理


当然,如果存在命令(或变量值)注入的风险,您可以选择报告错误,这可以简单地像:

$path = 'There''s no place like $HOME'
if ($path -match '$') { Throw 'Unsupported characters in path.' }

然而,这也阻止了在路径中合法使用逐字$


退一步:

您声明路径可能是从网站复制粘贴过来的。这样一个粘贴的字符串可能确实包含(也许是隐藏的)控制字符,但是它们将被逐字包含而不是PowerShell_escape序列

因此,可能足以测试/悄悄地从字符串的文字内容中删除控制字符(在调用Test-Path -IsValid之前):

# Test for control characters.
if ($path -match 'p{C}') { throw 'Path contains control characters.' }
# Quietly remove them.
$sanitizedPath = $path -replace 'p{C}'

我最初运行的是PS 7.1.3版本,其中所有这些方法都具有相同的结果。

当我跑步时:

$invalidPath = 'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid

返回True

一样:

Test-Path ([regex]::Escape($invalidPath)) -IsValid

以及你提到的其他方法。

在5.1的测试中,我看到了和你一样的结果。

在XML中,您会看到`nn实际的非打印字符吗?即
'HKEY_LOCAL_MACHINESOFTWARETest`n@microsoft.com/GENUINE@microsoft.com/GENUINE'

'HKEY_LOCAL_MACHINESOFTWARETest
@microsoft.com/GENUINE@microsoft.com/GENUINE'

如果后者为真,您应该能够将字符串传递给Test-Path "$invalidPath" -IsValid等变量中的test-path以获得您正在寻找的内容。在7.1.3(可能更早)中,PS似乎足够聪明,可以解析这些转义序列之类的——或者没有简单的方法可以做你正在寻找的事情,我可以找到。

相关内容

  • 没有找到相关文章

最新更新