PowerShell 安全扩展任意字符串中的非打印字符
PowerShell safe expansion of non printing characters in arbitrary strings
我在 XML 文件中有数据,最终将用作注册表路径,其中可能包含非打印字符(例如,将路径从网站复制到 XML).我想验证数据并在发现非打印字符时抛出特定错误。
在 Powershell 中,如果我在单引号中定义了一个带有非打印字符的变量,然后 test-Path
它测试为有效路径,因为非打印字符被作为文字处理。
Test-Path 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE' -isValid
双引号同样会“扩展”非打印字符和return false,这正是我需要的。
Test-Path "HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE" -isValid
我找到了对 [string]::Format(()
用于扩展非打印字符的引用,但是
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE'
[string]::Format("{0}",$invalidPath)
没有按预期扩展非打印字符。
我也看到了使用 Invoke-Expression
的参考,但这不安全,也不是一个选择。
最后我找到了$ExecutionContext.InvokeCommand.ExpandString()
,这似乎有效,
$ExecutionContext.InvokeCommand.ExpandString('HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE')
returns 一个多行字符串到控制台,而
$ExecutionContext.InvokeCommand.ExpandString('Write-Host "Screwed"')
return 是控制台的实际字符串,而不是实际执行 Write-Host
并且仅 returning Screwed
到控制台。
最后,
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid
return如预期的那样为假。这让我认为这是追求的正确方法,但考虑到其他地方的所有陷阱,我想 100% 确定没有办法将这种方法用作安全弱点。我是在正确的轨道上,还是我的 Google-Fu 还没有出现?
我最初是运行PS版本7.1.3,所有这些方法都得到相同的结果。
当我运行:
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid
True
返回
同于:
Test-Path ([regex]::Escape($invalidPath)) -IsValid
还有你提到的其他方法。
在 5.1 的测试中,我看到了与您相同的结果。
在您的 XML 中,您会看到类似 `n
或 \n
或 actual 的非打印字符吗? IE
'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE'
或
'HKEY_LOCAL_MACHINE\SOFTWARE\Test\
@microsoft.com/GENUINE\@microsoft.com/GENUINE'
如果后者为真,您应该能够将字符串传递给像 Test-Path "$invalidPath" -IsValid
这样的变量中的测试路径,以获得您要查找的内容。在 7.1.3(可能更早)中,PS 似乎足够聪明来解析那些转义序列等等——或者没有简单的方法来做你正在寻找的我能找到的东西。
类似于 Invoke-Expression
, $ExecutionContext.InvokeCommand.ExpandString()
is vulnerable to injection of unwanted commands, except that in the latter case such commands are only recognized if enclosed in $(...)
, the subexpression operator, as that is the only way to embed commands in expandable strings(方法的参数被解释为)。
例如:
$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 '(`*)$', '`$$'))
}
注意:在输入字符串中逐字转义$
即可。 $
(或(
/)
)(`u{24}
(或`u{28}
/`u{29}
)的 Unicode 转义序列表示,在 PowerShell (Core) v6+ only),不是问题,因为 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}'
我在 XML 文件中有数据,最终将用作注册表路径,其中可能包含非打印字符(例如,将路径从网站复制到 XML).我想验证数据并在发现非打印字符时抛出特定错误。
在 Powershell 中,如果我在单引号中定义了一个带有非打印字符的变量,然后 test-Path
它测试为有效路径,因为非打印字符被作为文字处理。
Test-Path 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE' -isValid
双引号同样会“扩展”非打印字符和return false,这正是我需要的。
Test-Path "HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE" -isValid
我找到了对 [string]::Format(()
用于扩展非打印字符的引用,但是
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE'
[string]::Format("{0}",$invalidPath)
没有按预期扩展非打印字符。
我也看到了使用 Invoke-Expression
的参考,但这不安全,也不是一个选择。
最后我找到了$ExecutionContext.InvokeCommand.ExpandString()
,这似乎有效,
$ExecutionContext.InvokeCommand.ExpandString('HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE')
returns 一个多行字符串到控制台,而
$ExecutionContext.InvokeCommand.ExpandString('Write-Host "Screwed"')
return 是控制台的实际字符串,而不是实际执行 Write-Host
并且仅 returning Screwed
到控制台。
最后,
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid
return如预期的那样为假。这让我认为这是追求的正确方法,但考虑到其他地方的所有陷阱,我想 100% 确定没有办法将这种方法用作安全弱点。我是在正确的轨道上,还是我的 Google-Fu 还没有出现?
我最初是运行PS版本7.1.3,所有这些方法都得到相同的结果。
当我运行:
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid
True
返回
同于:
Test-Path ([regex]::Escape($invalidPath)) -IsValid
还有你提到的其他方法。
在 5.1 的测试中,我看到了与您相同的结果。
在您的 XML 中,您会看到类似 `n
或 \n
或 actual 的非打印字符吗? IE
'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n@microsoft.com/GENUINE\@microsoft.com/GENUINE'
或
'HKEY_LOCAL_MACHINE\SOFTWARE\Test\
@microsoft.com/GENUINE\@microsoft.com/GENUINE'
如果后者为真,您应该能够将字符串传递给像 Test-Path "$invalidPath" -IsValid
这样的变量中的测试路径,以获得您要查找的内容。在 7.1.3(可能更早)中,PS 似乎足够聪明来解析那些转义序列等等——或者没有简单的方法来做你正在寻找的我能找到的东西。
类似于 Invoke-Expression
, $ExecutionContext.InvokeCommand.ExpandString()
is vulnerable to injection of unwanted commands, except that in the latter case such commands are only recognized if enclosed in $(...)
, the subexpression operator, as that is the only way to embed commands in expandable strings(方法的参数被解释为)。
例如:
$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 '(`*)$', '`$$'))
}
注意:在输入字符串中逐字转义$
即可。 $
(或(
/)
)(`u{24}
(或`u{28}
/`u{29}
)的 Unicode 转义序列表示,在 PowerShell (Core) v6+ only),不是问题,因为 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}'