Sooua
登录
返回文章列表
Windows 安全··8 分钟阅读

PowerShell 4104 事件能证明什么,不能证明什么

基于 Windows 测试机实测,拆解 PowerShell Script Block Logging 的证据价值、缺口和进入 SIEM 前的治理基线。

PowerShell 4104 事件能证明什么,不能证明什么

验证环境:Windows 测试节点 DESKTOP-HT6EO5E,Windows 10 Pro for Workstations 19045,Windows PowerShell 5.1.19041.6456。采集命令以 -ExecutionPolicy Bypass 启动单次只读 PowerShell 进程,因此输出中的 Process=Bypass 只代表本次进程级覆盖,不代表机器或域策略。本文只讨论防御、审计和检测工程,不提供攻击执行步骤。

核心观点

PowerShell 事件 4104 的价值不是“看到一条脚本日志就等于完成检测”,而是把脚本内容、执行上下文和主机策略状态放进同一条证据链。它能证明某段脚本块被 PowerShell 引擎记录过;它不能单独证明脚本一定完成执行、一定被 Defender 扫描、一定覆盖所有 PowerShell 版本和所有执行入口。

对安全运营来说,正确姿势是把 4104 当作证据链中的“脚本文本层”,再用执行策略、AMSI/Defender 状态、进程创建、模块日志、转录日志和终端侧策略去补足时间线。否则 SIEM 里会出现两个常见误判:一是把 4104 当成万能审计;二是因为日志噪声太大而完全不用它。

背景与问题定义

PowerShell 的 Windows 日志体系包含 engine/provider/cmdlet 等事件。Script Block Logging 会在 Microsoft-Windows-PowerShell/Operational 中记录脚本块创建事件,其中 4104 是检测工程最常用的事件之一。Microsoft 同时在 PowerShell 安全文档中说明,Windows PowerShell 5.1 起会把脚本块交给 AMSI,PowerShell 7.3 以后扩展了送检内容范围。这些能力给了蓝队很好的可见性,但它们不是同一个控制点。

问题在于,企业落地时经常把三个层次混在一起:

层次常见对象能回答的问题不能回答的问题
脚本文本可见性4104 Script Block Logging记录到了什么脚本块文本脚本是否完整执行、是否绕过其他入口
安全扫描与阻断AMSI、Defender、EDR是否把动态脚本内容交给反恶意软件能力日志策略是否开启、事件是否集中采集
企业治理GPO/MDM、SIEM、SOAR、WDAC/App Control是否能形成强制基线和审计闭环单台机器临时状态是否代表全域状态

实测基线:一台 Windows 节点暴露出来的边界

下面是本次在授权 Windows 测试环境上采集的只读输出。命令读取系统、PowerShell、日志通道和最近 4104 事件,没有修改策略。

=== System ===
WindowsProductName : Windows 10 Pro for Workstations
WindowsVersion     : 2009
OsBuildNumber      : 19045
OsArchitecture     : 64-bit
 
=== PowerShell ===
PSVersion          : 5.1.19041.6456
PSEdition          : Desktop
 
=== ExecutionPolicy ===
        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process          Bypass
  CurrentUser    RemoteSigned
 LocalMachine       Undefined
 
=== ScriptBlockLoggingPolicy ===
(no explicit HKLM policy value returned)
 
=== ModuleLoggingPolicy ===
(no explicit HKLM policy value returned)
 
=== TranscriptionPolicy ===
(no explicit HKLM policy value returned)
 
=== PowerShell Operational Log ===
LogName            : Microsoft-Windows-PowerShell/Operational
IsEnabled          : True
RecordCount        : 976
MaximumSizeInBytes : 15728640
 
=== Recent 4104 ===
TimeCreated  : 6/9/2026 2:01:48 AM
Id           : 4104
ProviderName : Microsoft-Windows-PowerShell
Message      : Creating Scriptblock text (1 of 1):
               $ErrorActionPreference='SilentlyContinue'
               Write-Host '=== System ==='
               Get-ComputerInfo | Select-Object WindowsProductName,...
               ScriptBlock ID: 5e52b512-4f9e-42be-ba19-b0b60d66858b

这组结果能支撑三个具体判断。

  1. Microsoft-Windows-PowerShell/Operational 日志通道已启用,并且有 4104 记录;这说明至少当前 PowerShell 入口产生了脚本块文本可见性。
  2. HKLM 下未读到 ScriptBlockLogging、ModuleLogging、Transcription 的显式企业策略值;Process=Bypass 来自本次只读采集进程的启动参数,不是机器持久策略,所以不能把这台机器的行为外推成“域内强制基线已开启”。
  3. 事件内容记录了本次采集命令本身,证明 4104 可以把多行脚本块、管道和部分参数纳入证据;但这并不证明所有脚本入口、所有 PowerShell 版本、所有主机进程都被同等覆盖。

环境边界也要写清楚:这是一台授权测试节点,不代表企业域控 GPO、Intune/MDM、EDR 代理或生产 SIEM 的真实状态。本文使用它验证事件字段与证据链写法,不能把“本机看到了 4104”扩展成“生产环境已经合规”。

证据链架构

这张图的关键不是“多收日志”,而是避免把 4104 放在孤岛里。4104 适合回答脚本文本层的问题;进程创建适合回答谁启动了 PowerShell;AMSI/Defender 适合回答扫描与处置;策略注册表和 GPO 适合回答基线是否被强制。

工程化设计:从事件到可运营检测

1. 先定义采集基线,而不是先写规则

最低限度的主机侧基线应包含:

控制项验证命令/对象合格信号失败模式
Operational 日志通道Get-WinEvent -ListLog Microsoft-Windows-PowerShell/OperationalIsEnabled=True,容量足够通道关闭、容量太小导致覆盖
Script Block Logging 策略HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLoggingGPO/MDM 明确配置只依赖默认行为,无法证明强制基线
Module Logging...\ModuleLogging\ModuleNames关键模块被纳入只有脚本文本,没有模块调用上下文
Transcription...\Transcription输出目录、权限和保留策略明确转录文件泄露敏感输出或无法集中采集
AMSI/Defender/EDRDefender/EDR 健康状态实时保护与脚本扫描链路可观测日志有了,但扫描/处置缺位
SIEM 归一化字段映射host,user,process,script_block_id,message_hash 可查询只存原文,无法关联或去重

2. 再写检测逻辑,并保留“证据等级”

示例规则不应该直接等价于“出现某字符串就是入侵”。更稳妥的写法是把证据分级:

证据等级条件处置建议
单条 4104 命中可疑关键字,但无进程/用户异常进入低优先队列,做哈希去重和上下文补全
4104 命中 + 非交互父进程/计划任务/异常路径创建告警,拉取父子进程、登录会话和文件落点
4104 命中 + AMSI/EDR 告警 + 横向移动或凭据访问信号进入事件响应流程,隔离主机前保全日志
审计缺口高风险资产没有 4104 或日志容量不足不是安全告警,而是基线缺陷工单

这能避免规则把安全运营拖进两个极端:要么噪声淹没,要么因为误报而关闭采集。

最小可复现实验

下面实验只验证可见性,不包含攻击步骤。它适合在测试机或实验 OU 中执行,生产环境应通过变更流程启用策略。

# 1. 查看当前日志通道
Get-WinEvent -ListLog 'Microsoft-Windows-PowerShell/Operational' |
  Select-Object LogName, IsEnabled, RecordCount, MaximumSizeInBytes
 
# 2. 执行一段无害脚本块,制造可追溯事件
$marker = 'ps4104-lab-' + [guid]::NewGuid().ToString()
Write-Output $marker | Out-Null
 
# 3. 回查最近 4104,并确认 marker 是否出现
Get-WinEvent -FilterHashtable @{
  LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104
} -MaxEvents 20 |
  Where-Object { $_.Message -like "*$marker*" } |
  Select-Object TimeCreated, Id, ProviderName, Message

预期结果:如果日志通道和脚本块记录生效,最近的 4104 中应能看到 marker 或包含 marker 的脚本文本。若没有看到,排查顺序不是“规则写错了”,而是:日志通道是否开启、策略是否强制、是否使用了不同 PowerShell 版本或宿主、事件是否被覆盖、采集代理是否过滤。

失败模式与排错路径

现象首查对象常见原因修复方向
本机能看到 4104,SIEM 看不到采集代理、WEF 订阅、索引映射只采 Security/System,未采 Operational增加 PowerShell Operational 订阅和字段解析
4104 太多,规则不可用去重字段、脚本哈希、资产分组构建/运维脚本噪声未建白名单按资产角色和脚本签名做基线
只有脚本文本,没有父进程4688/EDR telemetryWindows 审计策略或 EDR 字段缺失补齐进程创建、命令行和用户登录事件
合规检查无法证明策略开启GPO/MDM 状态、注册表策略值依赖默认行为,没有集中策略建立配置基线与漂移检测
敏感信息进入日志Transcription/4104 脱敏策略脚本输出或参数包含密钥日志访问分级、密钥扫描、最小化记录范围

风险与安全边界

4104 的边界要明确写进检测规范:

  • 它不是强制执行控制,不能替代 WDAC/App Control、最小权限、脚本签名和 JEA。
  • 它不是完整取证系统,日志容量、覆盖周期和采集延迟会影响证据完整性。
  • 它不应被当作单点阻断信号,必须和 AMSI/Defender/EDR、进程事件和身份上下文关联。
  • 它可能记录敏感脚本文本,日志平台本身要纳入数据安全和访问控制。
  • 它在不同 PowerShell 版本、宿主和企业策略下表现可能不同,生产规则必须先做资产分层验证。

结论

真正有用的 PowerShell 检测,不是把 4104 塞进 SIEM 就结束,而是让它成为一条可解释、可复核、可回归测试的证据链。资产范围要明确,策略来源要可追溯,事件关联要能串联用户、主机、父进程和 AMSI 告警,噪声治理要有基线。对蓝队来说,这比追逐单条规则的命中率更重要。

分享

评论

登录 后参与讨论。

加载中…

相关文章