PowerShell脚本执行策略与受限语言模式深度解析
1. 脚本执行策略
在PowerShell中,脚本执行策略是保障系统安全的重要机制,它可以控制脚本的执行权限,防止恶意脚本的运行。下面将详细介绍几种常见的脚本执行策略设置方法。
1.1 Set-ExecutionPolicy
要更改特定范围的执行策略,可以使用 Set-ExecutionPolicy cmdlet 。其语法如下:
Set-ExecutionPolicy -ExecutionPolicy <ExecutionPolicy> -Scope <Scope>
这个cmdlet只能调整进程、当前用户或本地计算机范围内的执行策略。如果要设置 MachinePolicy 或 UserPolicy ,则必须使用组策略。需要注意的是,组策略对象定义的执行策略会覆盖使用 Set-ExecutionPolicy cmdlet所做的配置更改。
1.2 组策略
通过组策略,我们可以批量设置环境中计算机的执行策略。可以使用PowerShell将所需的注册表值添加到组策略对象(GPO)中。以下是一个示例,展示了如何将PowerShell执行策略添加到GPO中:
$GPOName = '<Name of your Group Policy Object>'
$RegKey = 'HKLM\Software\Policies\Microsoft\Windows\PowerShell'
$SetGPOParams = @{
Name = $GPOName
Key = $RegKey
ValueName = 'EnableScripts'
Value = 1
Type = 'DWORD'
}
Set-GPRegistryValue @SetGPOParams
$SetGPOParams.ValueName = 'ExecutionPolicy'
$SetGPOParams.Value = 'AllSigned'
$SetGPOParams.Type = 'String'
Set-GPRegistryValue @SetGPOParams
上述示例中的注册表值与Windows PowerShell组策略模板中的设置相关联。同样的注册表路径和组策略配置路径也可分别用于 HKEY_CURRENT_USER 和用户配置。
虽然也可以仅通过注册表更改来管理计算机上的执行策略,但这并不推荐。因为如果组策略设置与注册表键冲突,组策略设置将覆盖注册表键。而且,任何具有注册表写入权限的人都可以更改注册表键。注册表键的更改将持续到下一次组策略刷新,默认情况下,计算机每90分钟(随机偏移30分钟)刷新一次组策略。这种方法仅在管理员需要临时放宽执行策略时有用。
对于PowerShell 7.0及更高版本,使用不同的组策略设置和注册表键。可以通过从PowerShell安装目录运行以下脚本安装额外的组策略模板:
InstallPSCorePolicyDefinitions.ps1
这将在组策略编辑器中提供新的配置路径:
- 计算机配置\管理模板\PowerShell Core
- 用户配置\管理模板\PowerShell Core
这些路径包含与Windows PowerShell相同的配置选项,并在以下注册表键中设置值:
- HKLM\SOFTWARE\Policies\Microsoft\PowerShellCore
- HKCU\SOFTWARE\Policies\Microsoft\PowerShellCore
1.3 AppLocker
为了更有效地抵御威胁行为者,可以使用AppLocker来限制用户执行脚本的能力。AppLocker可以根据多种条件阻止脚本运行,包括但不限于:
- 尝试运行脚本的用户身份
- 脚本所在的目录
- 脚本是否由受信任的机构签名
由于并非所有随Windows附带的 .ps1 文件都已签名,因此保留默认规则是个好主意。AppLocker服务 AppIDSvc 默认不运行,需要在要保护的每台计算机上启动该服务,有时需要注销并重新登录,AppLocker规则才会应用到会话中。可以使用组策略首选项或组策略对象中的组策略来将服务启动类型设置为“自动”。
以下是一个基本的AppLocker和执行策略使用示例,假设要阻止所有用户运行未由Microsoft签名的脚本:
1. 创建一个具有以下设置的GPO:
- 计算机策略\Windows设置\安全设置\应用程序控制策略\AppLocker\脚本规则
- 权限:拒绝:所有人
- 条件:文件路径:*
- 例外:发布者:Microsoft
- 计算机策略\管理模板\Windows组件\Windows PowerShell
- 启用脚本执行:启用:仅允许签名的脚本
- 计算机策略\Windows设置\系统服务
- 应用程序身份:定义此策略设置:自动
这种配置将受GPO影响的计算机上的 MachinePolicy 设置为 AllSigned ,从而阻止运行任何未由受信任发布者签名的脚本。
1.4 Windows Defender Application Control(WDAC)
Windows 10引入的Windows Defender Application Control(WDAC)提供了对计算机级应用程序的更高级控制。WDAC策略应用于整个计算机,与AppLocker不同,它没有仅对特定用户应用策略的选项。目前,Microsoft正在积极开发WDAC,而AppLocker仅接收安全修复。如果可能,Microsoft建议使用WDAC策略而不是AppLocker,但这取决于具体的环境。也可以同时部署两者,将AppLocker作为WDAC的补充,例如使用WDAC设置计算机基线,同时部署AppLocker策略以实现更精细的用户级控制。
可以使用 Set-RuleOption cmdlet启用代码完整性规则选项。例如,要限制内核模式和用户模式二进制文件,可以使用 -Option 0 (也称为 Enabled:UMCI ):
Set-RuleOption -FilePath '<Path to policy XML>' -Option 0
要启用PowerShell脚本强制执行,可以使用 -Option 11 和 -Delete 参数(也称为 Disabled: Script Enforcement ):
Set-RuleOption -FilePath '<Path to policy XML>' -Option 11 -Delete
2. 受限语言模式(Constrained Language Mode,CLM)
受限语言模式(CLM)是PowerShell远程会话配置和PowerShell默认(控制台)运行空间使用的一种语言模式。它通过限制未批准脚本的范围,减少了控制台会话中恶意代码执行的风险,为基于控制台的安全提供了一种开箱即用的解决方案。
2.1 深入了解受限语言模式
CLM最早在PowerShell 3.0中引入,最初是Windows Defender Application Control(WDAC,前身为用户模式代码完整性UMCI)在Windows 8.1 RT上管理PowerShell默认运行空间(控制台)的一种机制。在Windows 8.1之后,后续的PowerShell版本将CLM作为提供基于控制台安全的一种方式。
WDAC/AppLocker是Microsoft可信启动过程中Windows Shell的顶级安全模型,Windows使用它们来保护Windows的顶级“Shell”。一旦系统强制执行任何WDAC/AppLocker脚本规则,PowerShell(包括PowerShell Core)控制台会话将以受限语言模式启动。
2.2 语言模式
PowerShell有四种语言模式,它们定义了PowerShell会话的安全状态:
- FullLanguage :默认模式,允许所有语言元素。
- ConstrainedLanguage :允许所有语言元素,但限制允许的类型。
- RestrictiveLanguage :限制语言元素的使用,变量使用也受限。
- NoLanguage :没有可用的语言元素。
要查看当前会话的语言模式,可以使用 $ExecutionContext.SessionState.LanguageMode 。以下是一个示例:
$ExecutionContext.SessionState.LanguageMode
LanguageMode 属性仅在 FullLanguage 语言模式下可设置,可以使用此功能测试脚本可能出现的问题。以下示例展示了将语言模式从 FullLanguage 更改为 ConstrainedLanguage ,再尝试改回的过程:
$ExecutionContext.SessionState.LanguageMode
$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"
$ExecutionContext.SessionState.LanguageMode
$ExecutionContext.SessionState.LanguageMode = "FullLanguage"
需要注意的是,尝试重置属性时,控制台会抛出错误,因此建议仅将会话状态用于调试或测试。
2.3 受限语言模式的特性
CLM具有多种安全特性,这些特性限制了PowerShell控制台会话的范围和影响。
2.3.1 允许的类型
CLM限制会话中类型的使用,允许的类型如下表所示:
| Types A - N | Types O - Z |
| — | — |
| AliasAttribute | OutputTypeAttribute |
| AllowEmptyCollectionAttribute | ParameterAttribute |
| AllowEmptyStringAttribute | PSCredential |
| AllowNullAttribute | PSDefaultValueAttribute |
| Array | PSListModifier |
| Bool | PSObject |
| byte | PSPrimitiveDictionary |
| char | PSReference |
| CmdletBindingAttribute | PSTypeNameAttribute |
| DateTime | Regex |
| decimal | SByte |
| DirectoryEntry | string |
| DirectorySearcher | SupportsWildcardsAttribute |
| double | SwitchParameter |
| float | System.Globalization.CultureInfo |
| Guid | System.Net.IPAddress |
| Hashtable | System.Net.Mail.MailAddress |
| int | System.Numerics.BigInteger |
| Int16 | System.Security.SecureString |
| long | TimeSpan |
| ManagementClass | UInt16 |
| ManagementObject | UInt32 |
| ManagementObjectSearcher | UInt64 |
| NullString | |
此外,CLM还允许以下组件对象模型(COM)对象:
- Scripting.Dictionary
- Scripting.FileSystemObject
- VBScript.RegExp
用户可以获取或设置允许的属性、调用方法,并将对象转换为允许的类型。需要注意的是, [PSCustomObject] 不是CLM中批准的类型,以下示例展示了尝试创建 PSCustomObject 时会出现的错误:
$ExecutionContext.SessionState.LanguageMode
$psobject = [PSCustomObject]@{ key = 'item' }
2.3.2 模块
当导入PowerShell脚本或模块时,cmdlet将继承父语言模式。例如,以下是一个模块脚本 Module.psm1 的示例:
function Do-Something {
[System.Net.WebClient]::new().DownloadFile(
'https://google.com/favicon.ico', 'D:\TEMP\SomeFile.html'
)
}
加载该模块并调用函数:
Import-Module Module
Do-Something
由于 [System.Net.WebClient] 不是允许的类型,执行时会出现错误。不过,如果编译模块使用的是批准的类型,CLM是允许的,以下是一个编译模块的示例:
using System.Management.Automation;
namespace SamplePowerShellModule
{
[Cmdlet(VerbsCommon.Get, "Something")]
public class GetSomething : Cmdlet
{
[Parameter(Mandatory = true)]
public string Name
{
get { return name; }
set { name = value; }
}
private string name;
protected override void ProcessRecord()
{
PSObject pSObject = new PSObject();
pSObject.Members.Add(new PSNoteProperty("Test Object", name));
WriteObject(pSObject);
}
}
}
执行该模块:
Import-Module "SamplePowerShellModule.psd1"
Get-Something -Name 'Test'
2.3.3 Windows PowerShell工作流
PowerShell 7不支持PowerShell工作流。CLM允许Windows PowerShell脚本工作流,但不允许XAML工作流(使用 Invoke-Expression -Language XAML ),允许嵌套工作流,但不允许调用其他工作流。由于其语言限制,不建议实现这种工作流。
2.3.4 脚本
CLM允许脚本执行(使用点源或 Invoke-Command ),但会阻止被WDAC或App Locker策略排除的脚本。
2.3.5 New-Object
CLM允许对象实例化,但仅限于允许的类型。可以在 New-Object 的源代码中找到语言模式功能的嵌入。以下示例展示了尝试创建非批准类型时会出现的错误:
class Fake {}
$ExecutionContext.SessionState.LanguageMode = 'ConstrainedLanguage'
New-Object -TypeName Fake
[Fake]::new()
2.3.6 Add-Type
在CLM中, Add-Type 可以加载签名的C#程序集,但不允许未签名的程序集或Win32 API。以下示例展示了尝试加载未签名程序集和定义新类型的签名DLL时会出现的错误:
$ExecutionContext.SessionState.LanguageMode = 'ConstrainedLanguage'
$PSDir = 'C:\Windows\System32\WindowsPowerShell\v1.0'
Add-Type -LiteralPath "$PSDir\en\powershell_ise.resources.dll"
Add-Type -LiteralPath "C:\Program Files\PowerShell\7\pwsh.dll"
此外,CLM也不允许 Add-Type 加载原生C#代码,以下示例展示了尝试解析C#代码时会出现的错误:
$ExecutionContext.SessionState.LanguageMode = 'ConstrainedLanguage'
$Source = @"
public class Demo
{
public static int Add(int a, int b)
{
return (a + b);
}
}
"@
Add-Type -TypeDefinition $Source
2.3.7 类型转换
CLM仅允许在转换后的类型为允许类型时进行类型和字符串转换。以下示例展示了在CLM中从字符串到 DateTime 的类型转换:
"01/01/2021" -is 'String'
"01/01/2021" -is 'DateTime'
[DateTime]"01/01/2021" -is 'String'
[DateTime]"01/01/2021" -is 'DateTime'
而尝试转换为非批准类型时会出现错误:
[Fake]"String"
2.3.8 PowerShell方法
CLM允许调用批准类型的任何方法。以下示例展示了调用批准类型 [String] 的 GetType() 方法和尝试调用非批准类型 [Microsoft.PowerShell.Commands.WebResponseObject] 的 GetType() 方法的结果:
([string]'Test String').GetType().Name
(Invoke-WebRequest 'https://google.com/favicon.ico').GetType().Name
2.4 受限语言模式的局限性
虽然PowerShell受限语言模式为PowerShell增加了强大的安全功能,但也存在一些局限性:
- 恶意软件可以通过仅使用cmdlet来绕过CLM的限制。例如,可以使用 Invoke-WebRequest 通过HTTP下载恶意软件,并使用 New-ScheduledTask 和 Register-ScheduledTask 初始化代码。因此,还必须部署应用程序控制。
- 受限语言模式仅在PowerShell进程中有效,添加的PowerShell程序集在CLM中不会加载。
- 在管理账户上,理论上可以绕过受限语言模式。因此,应将非必要的管理访问权限限制在仅特权账户上。
综上所述,PowerShell的脚本执行策略和受限语言模式为系统安全提供了重要的保障,但在实际应用中,需要根据具体情况综合使用这些机制,并注意其局限性,以确保系统的安全性。
3. 综合应用建议
为了更好地利用PowerShell的脚本执行策略和受限语言模式来保障系统安全,以下给出一些综合应用的建议。
3.1 策略组合
在实际环境中,可以将不同的脚本执行策略和安全机制组合使用,以达到更高级别的安全防护。例如:
- Set-ExecutionPolicy与AppLocker结合 :先使用 Set-ExecutionPolicy 设置基本的执行策略,如 AllSigned ,确保只有签名的脚本才能执行。然后使用AppLocker进一步细化规则,根据用户身份、脚本目录等条件进行限制,阻止未授权的脚本运行。
- WDAC与CLM结合 :WDAC可以从系统层面控制应用程序的运行,而CLM则在PowerShell会话中限制脚本的执行。将两者结合使用,可以在不同层面上对系统进行保护。例如,使用WDAC设置计算机的基线安全策略,同时启用CLM来限制PowerShell脚本的执行范围。
3.2 操作流程
以下是一个在企业环境中部署脚本执行策略和受限语言模式的操作流程:
1. 需求分析 :了解企业的安全需求和业务需求,确定需要保护的资源和允许执行的脚本类型。
2. 策略制定 :根据需求分析的结果,制定相应的脚本执行策略和CLM规则。例如,确定允许的脚本签名者、限制的脚本目录等。
3. 测试环境部署 :在测试环境中部署制定好的策略和规则,进行充分的测试,确保不会影响正常的业务运行。
4. 生产环境部署 :在测试通过后,将策略和规则部署到生产环境中。可以使用组策略或其他自动化工具来批量部署。
5. 监控与维护 :定期监控系统的安全状态,检查是否有异常的脚本执行行为。同时,根据业务需求和安全形势的变化,及时调整策略和规则。
3.3 注意事项
在使用脚本执行策略和受限语言模式时,需要注意以下几点:
- 兼容性问题 :不同版本的PowerShell和Windows系统可能对策略和规则的支持有所不同,在部署前需要进行充分的测试,确保兼容性。
- 用户培训 :向用户提供相关的培训,让他们了解脚本执行策略和受限语言模式的作用和限制,避免因误操作而导致安全问题。
- 备份与恢复 :在进行策略和规则的修改前,务必备份相关的配置文件,以便在出现问题时能够及时恢复。
4. 总结
PowerShell的脚本执行策略和受限语言模式为系统安全提供了重要的保障。通过合理设置脚本执行策略,可以控制脚本的执行权限,防止恶意脚本的运行。而受限语言模式则通过限制脚本的执行范围,减少了恶意代码在控制台会话中执行的风险。
以下是一个简单的mermaid流程图,展示了脚本执行的安全检查流程:
graph TD;
A[脚本执行请求] --> B{是否符合执行策略};
B -- 是 --> C{是否在CLM范围内};
C -- 是 --> D{是否通过AppLocker/WDAC检查};
D -- 是 --> E[脚本执行];
B -- 否 --> F[拒绝执行];
C -- 否 --> F;
D -- 否 --> F;
在实际应用中,需要根据具体的安全需求和业务场景,综合使用这些安全机制,并注意其局限性。同时,定期进行安全评估和策略调整,以确保系统的安全性始终处于良好的状态。通过合理配置和管理PowerShell的脚本执行策略和受限语言模式,可以有效地保护系统免受恶意脚本的攻击,为企业的信息安全保驾护航。
总之,掌握PowerShell的脚本执行策略和受限语言模式是保障系统安全的重要手段,希望本文的介绍能够帮助读者更好地理解和应用这些安全机制。
超级会员免费看

1300

被折叠的 条评论
为什么被折叠?



