gpt4 book ai didi

powershell - 如何防止 PowerShell 中的变量注入(inject)?

转载 作者:行者123 更新时间:2023-12-03 09:33:22 24 4
gpt4 key购买 nike

我再次被@Ansgar Wiechers 对最近 PowerShell 问题的评论触发: DO NOT use Invoke-Expression 关于一个安全问题,我一直在脑海中某个地方需要问。

强声明(引用 Invoke-Expression considered harmful 文章)表明调用可以覆盖变量的脚本被认为是有害的。

PSScriptAnalyzer 还建议不要使用 Invoke-Expression ,请参阅 AvoidUsingInvokeExpression rule

但是我曾经自己使用过一种技术来更新递归脚本中的公共(public)变量,它实际上可以覆盖其任何父范围中的值,这很简单:

([Ref]$ParentVariable).Value = $NewValue

据我所知,潜在的恶意脚本也可以使用这种技术在任何情况下注入(inject)变量,无论它是如何被调用的......

考虑以下“恶意” Inject.ps1 脚本:
([Ref]$MyValue).Value = 456
([Ref]$MyString).Value = 'Injected string'
([Ref]$MyObject).Value = [PSCustomObject]@{Name = 'Injected'; Value = 'Object'}

我的 Test.ps1 脚本:
$MyValue = 123
$MyString = "MyString"
$MyObject = [PSCustomObject]@{Name = 'My'; Value = 'Object'}
.\Inject.ps1
Write-Host $MyValue
Write-Host $MyString
Write-Host $MyObject

结果:
456
Injected string
@{Name=Injected; Value=Object}

如您所见, Test.ps1 范围内的所有三个变量都被 Inject.ps1 脚本覆盖。这也可以使用 Invoke-Command cmdlet 来完成,我是否将变量的范围设置为 Private 也没有关系:
New-Variable -Name MyValue -Value 123 -Scope Private
$MyString = "MyString"
$MyObject = [PSCustomObject]@{Name = 'My'; Value = 'Object'}
Invoke-Command {
([Ref]$MyValue).Value = 456
([Ref]$MyString).Value = 'Injected string'
([Ref]$MyObject).Value = [PSCustomObject]@{Name = 'Injected'; Value = 'Object'}
}
Write-Host $MyValue
Write-Host $MyString
Write-Host $MyObject

有没有办法将调用的脚本/命令与覆盖当前范围内的变量完全隔离开来?
如果不是,这是否可以被视为以任何方式调用脚本的安全风险?

最佳答案

反对使用 Invoke-Expression 的建议使用主要是为了防止意外执行代码(代码注入(inject))。
如果您调用一段 PowerShell 代码 - 无论是直接还是通过 Invoke-Expression - 它确实可以(可能是恶意地)操纵父作用域,包括全局作用域。
请注意,这种潜在的操作不限于变量:例如,函数和别名也可以修改。
警告 : 运行未知代码有问题在两个方面:

  • 主要针对潜力直接执行不需要的/破坏性的操作 .[1]
  • 其次,对于 的潜力恶意修改调用者状态 (变量,...),即 以下解决方案的唯一方面是防止 .

  • 提供 所需的隔离 ,您有两个基本选择:
  • 运行 中的代码子进程 :
  • 通过启动另一个 PowerShell 实例;例如(在 Windows PowerShell 中使用 powershell 而不是 pwsh):
  • pwsh -c { ./someUntrustedScript.ps1 }

  • 通过启动后台作业;例如。:
  • Start-Job { ./someUntrustedScript.ps1 } | Receive-Job -Wait -AutoRemove


  • 运行 中的代码单独的线程 在同一过程中:
  • 作为线程作业,通过 Start-ThreadJob cmdlet(随 PowerShell [Core] 6+ 提供;在 Windows PowerShell 中,可以安装 from the PowerShell GalleryInstall-Module -Scope CurrentUser ThreadJob 之类的东西);例如。:
  • Start-ThreadJob { ./someUntrustedScript.ps1 } | Receive-Job -Wait -AutoRemove

  • 通过 PowerShell SDK 创建新的运行空间;例如。:
  • [powershell]::Create().AddScript('./someUntrustedScript.ps1').Invoke()
  • 请注意,您必须做额外的工作才能获得成功以外的输出流,尤其是错误流的输出;还有,.Dispose()应在命令完成时在 PowerShell 实例上调用。



  • 基于子进程的解决方案会很慢并且在您可以返回的数据类型方面受到限制(由于涉及到序列化/反序列化),但它提供了对调用代码崩溃进程的隔离。
    基于线程的作业要快得多,可以返回任何数据类型,但可能会使整个过程崩溃。
    在所有情况下,您都必须从调用者传递被调用代码需要访问的任何值作为参数,或者使用后台作业和线程作业,或者通过 $using:范围说明符。

    js2010提到其他不太理想的选择:
  • Start-Process (基于子进程,带有纯文本参数和输出)
  • PowerShell Workflows ,它们已经过时(它们没有被移植到 PowerShell Core,也不会被移植)。
  • 使用 Invoke-Command使用“环回远程处理”( -ComputerName localhost )假设也是一种选择,但是您会产生子进程和基于 HTTP 的通信的双重开销;此外,您的计算机必须设置为远程处理,并且您必须以提升(以管理员身份)运行。

  • [1] 缓解该问题的一种方法是限制在评估字符串时允许调用哪些命令、语句、类型……,这可以通过 PowerShell SDK 来实现。结合 language modes和/或通过显式构造 initial session state .见 this answer有关 SDK 与语言模式一起使用的示例。

    关于powershell - 如何防止 PowerShell 中的变量注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56985269/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com