跳转至

Windows EDR 信号面

Orca 的 Windows 进程树形状,正是行为型 EDR 被设计用来发现的目标。一个企业 Windows 11 / Intune 租户在八天内针对 Orca 1.4.192 创建了 六个 Microsoft Defender for Endpoint 事件。全部六个都作为活动事件触发并保持打开状态;其中三个仅因为有人在门户中手动分类才关闭。Defender 从未自行降级或关闭其中任何一个。

没有任何一个是签名命中。每一个都是行为型进程树评分,其中两个升级为携带 ATT&CK 战术映射(Execution、Collection)的多阶段事件。

本文贯穿始终的框架是,因为两半都很重要:

Defender 并未故障。它在准确描述代码。 Orca 确实会以自己的签名映像复制一份并使用不同名称,确实曾按定时器读取每个进程的内存,确实会运行绕过执行策略的 base64 编码 PowerShell,并且确实会从运行时编译的程序集中截取屏幕截图并合成输入。其中每一项都是带有问题历史的刻意工程选择。问题不在于这些能力不合法——而在于它们的行为签名与攻击技术重叠,而按行为评分的 EDR 无法看出区别。

不要将此读作针对 Defender 的 bug 报告,也不要读作 Orca 是恶意软件的声明。它是一张地图,说明我们的哪些行为会被 EDR 识别为攻击技术形态、每个行为为何存在,以及工程师和管理员可以如何处理。

租户实际看到的内容

来自六个事件的四个独立证据集群:

集群 事件 证据
更新 A, B, C orca-windows-setup.exe → old-uninstaller.exe、Uninstall Orca.exe(electron-builder 生成这些文件;它们不在任何仓库文件中)
派生 全部六个 Orca.exe → orca-terminal-daemon.exe → powershell.exe / pwsh.exe / cmd.exe / reg.exe → claude.exe、gh.exe、codex.cmd
进程表 D “可疑内存活动”——对每个进程重复执行 OpenProcess 以及 PEB 读取
计算机使用 E, F runtime.ps1、computer-sidecar.js、大量 operation.json、约 10 个短生命周期的 powershell.exe 突发

事件 E 是最需要仔细查看的:5 个告警、37 个证据项、ATT&CK Execution + Collection,描述为 “这台设备上意外截取了屏幕截图……在由 powershell.exe 启动的脚本中发现了屏幕捕获代码。” 事件 F 增加了 “可疑 MSIL 代码”,来自每次操作都会重新编译内联 C# P/Invoke 的 Add-Type -TypeDefinition。

在更新集群中,卸载程序确实为 NotSigned,而 Orca.exe 和 orca-terminal-daemon.exe 报告为 Valid CN=SignPath Foundation。

这些行为,以及它们各自存在的原因

守护进程从我们自己镜像的副本运行

src/main/daemon/daemon-host-relocation.ts 将 Electron 运行时复制到 %LOCALAPPDATA%\Orca\daemon-host\<version>\,并从中派生终端守护进程。

它存在的原因是 NSIS 安装程序会删除旧安装目录,并强制结束所有映像位于该目录下的进程。如果没有重定位,自动更新会杀死终端守护进程以及所有正在运行的终端。该副本是以 node 方式运行的 Orca.exe,而不是 node.exe,因此不会出现控制台闪烁,asar 仍可解析;config/nsis/orca-installer-hooks.nsh 会在真正卸载时回收它(由 ${isUpdated} 保护,因此更新的 uninstallOldVersion 永远不会触发它)。

在这些事件发生时,该副本还被重命名为 orca-terminal-daemon.exe,这是本文所有事件报告的映像名称,而 DAEMON_HOST_EXE_NAME 的注释不加修饰地说明了原因:“这样 NSIS 更新程序的 taskkill /IM Orca.exe 就无法匹配到它。” 此后重命名已被 移除;该副本现在保留应用 exe 自身的文件名,因为更新程序的终止扫描在所有具有 PowerShell 的主机上都是按路径限定范围的,而重命名只为没有 PowerShell 的回退方案带来收益。参见 windows-daemon-host-relocation.md。

EDR 如何解读它:MITRE T1036,伪装(masquerading) — 对于剩余部分, 则是 T1036.005。一个已签名可执行文件从安装目录复制到 %LOCALAPPDATA% 并使用不同名称,随后派生 shell,这与教科书描述足够接近,以至于不能期望任何行为引擎给它低分。移除重命名会消除该字面指标,但不会消除底层形态:从非标准用户可写位置执行本身就会被评分。还需注意,T1036 信号的最强形式在此从未出现——发布二进制的 OriginalFilename 为空,因此没有嵌入名称来与旧磁盘名称相矛盾。

每个进程都会获得一个句柄,按定时器执行

src/main/windows/windows-process-table.ts 在 两种 标志集之一下获取 Toolhelp32 快照:身份(None | CreationTime)用于只读取 pid、ppid 和名称的调用方,详细(+ CommandLine)用于按命令行匹配的调用方。pid、ppid 和名称直接来自快照本身,不会打开任何内容,因此身份扫描完全不会打开任何内容。CommandLine 才是打开句柄的部分:该附加组件对每个进程调用 GetProcessCommandLine,它会打开 PROCESS_QUERY_LIMITED_INFORMATION —— 与任务管理器使用的权限相同 —— 并向内核请求该字符串。上游版本打开 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,并通过三次 ReadProcessMemory 调用遍历 PEB(位于 config/patches/ 修补的内置 @vscode/windows-process-tree 0.8.0 源码中的 src/process_commandline.cc:32,41-47)。

Memory 自本次更改起已弃用,并且这是一次真正的减少:它使 GetProcessMemoryUsage 为每个进程打开一个 第二个 PROCESS_QUERY_INFORMATION | PROCESS_VM_READ 句柄,用于一次没有任何调用方读取其结果的 GetProcessMemoryInfo 调用 (src/process.cc:47-63)。移除它使每个快照打开的句柄数量减半。单靠它并未移除任何内存读取——当时两个句柄都带有 PROCESS_VM_READ——因此它与下面的补丁组合使用,而不是替代它。

它的存在是因为七个独立的读取器过去会 fork powershell.exe 以执行 Get-CimInstance Win32_Process 扫描。该成本已实测:一项 PowerShell Transcription 策略记录了 约 289 GB、跨 140 万个文件,因为扫描每约 2 秒运行一次(#15209);组策略或防病毒软件拦截会将查询变为“不可用”,调用方将其解读为“无证据”,这正是 PTY 树在自身拆除过程中存活下来的原因(#9045、#10475);并且扫描每个窗格耗时约 700 ms,因此窗格数量会将其放大(#15036)。原生快照以 15.9 ms 回答同一问题,而 CIM 为 706 ms——p50,在 Windows 11 上以 1050 个进程测得。参见 windows-process-enumeration.md。

请求更少的字段更便宜,现在每个调用方都请求能回答其问题的最小字段集。恰好有 两个 带 TTL 缓存的快照,每个标志集一个,绝不为每个调用方一个:缓存旨在消除的扇出是每个 调用方 一次扫描,而每个读取器仍然服务于所有需要其标志集的调用方,因此宽度为 32 的拆除仍会收敛为每种各一次扫描。拆除身份和所有者探测选择身份集,因此不打开任何句柄;每个窗格的前台跟踪器确实需要命令行,并且仍会为此付出一次代价。第三个缓存需要第三个标志集,而不是第三个调用方。在 492 个进程下测得,p50:身份 6.3 ms,详细 12.3 ms——参见 windows-process-enumeration.md。

EDR 如何解读它: 一个跨进程句柄加上对机器上每个进程的远程内存读取,并按固定节奏重复,正是凭据转储和进程注入所产生的遥测的读取部分。MDE 将其显示为“可疑内存活动”。

内存读取已消失。 config/patches/@vscode__windows-process-tree@0.8.0.patch 中的第四个块让 GetProcessCommandLine 调用 NtQueryInformationProcess,使用 ProcessCommandLineInformation(class 60,Windows 8.1+;Electron 的最低要求是 Windows 10),它返回一个由内核构建的 UNICODE_STRING,并且只需要 PROCESS_QUERY_LIMITED_INFORMATION。在约 540 个进程上测得,每次详细扫描:ReadProcessMemory 1128 → 0,所需访问权限 0x0410 → 0x1000,并且两个读取器恢复的每个进程的命令行都逐字节相同。没有 PEB 回退机制会重新启用它——一个被挂钩的 ntdll 若对某个目标返回 STATUS_INVALID_INFO_CLASS,就会在正是为此而存在的机器上,把一个进程范围、单向的开关翻回 PROCESS_VM_READ。

因为该属性是 缺失 一个导入,所以可以在产物而非源代码上检查:inspectWindowsProcessTreeAddon() 返回 clean / unpatched / missing,而重建、ensure-native-runtime.mjs、relay 构建和 loadWindowsProcessTree() 都以它为依据。该检查至关重要,因为发布的 tarball 附带一个由未打补丁的源代码构建的 可加载 预构建版本,因此“它干净地 require 了”不是证据。

现在需要向管理员声明的是:在详细快照中,每个进程一个 PROCESS_QUERY_LIMITED_INFORMATION 句柄,并且完全没有任何远程内存访问;身份快照不打开任何东西。这并未缩小 询问哪些 进程——详细扫描仍然查询每个 pid,包括 lsass.exe。将命令行遍历限制到 Orca 自身的子树需要以 job-object 成员关系作为事实来源(基于 ppid 的允许列表会遗漏 #9045 和 #10475 中已分离、被重新父化的后代),并且仍是无人认领的工作。

编码的、绕过策略的 PowerShell

事件分析中点名了三个位置:

  • src/relay/windows-port-scan.ts 曾在一个 Get-NetTCPConnection -State Listen 脚本上运行 -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand,以查找开发服务器端口。 枚举监听端口是 MITRE T1049,即网络服务发现,而通过编码的、绕过策略的 shell 执行它是加重因素,而不是发现本身。普通扫描现在完全不启动 PowerShell——使用 netstat.exe -ano,并从共享原生表中投影出拥有进程名称——该 payload 仅作为最后手段的回退保留,且以 -Command 形式出现,没有策略覆盖。
  • src/main/daemon/shell-ready.ts 使用 -EncodedCommand 进行 OSC 133 引导。
  • src/main/agent-hooks/windows-powershell-hook-launcher.ts 封装托管钩子。

没有任何位置再明确写出该参数对。 src/main/ssh/ssh-remote-powershell.ts、 src/shared/setup-agent-sequencing.ts、 src/shared/windows-cmd-runner-delayed-launch.ts 和 src/shared/windows-interactive-login-spawn.ts 各自移除了 -ExecutionPolicy Bypass,因为实测它是无效操作:策略只控制脚本 文件,从不控制 -EncodedCommand。在绕过起关键作用的地方,它已移入 payload 内,作为进程范围的 Set-ExecutionPolicy(setup-agent-sequencing.ts),这是应复制的模式,而不是恢复该开关——该开关无论如何都会输给 GPO 范围,因此它从未覆盖锁定场景。

剩下的是没有 bypass 的 -EncodedCommand:PTY 引导(src/main/daemon/shell-ready.ts、src/main/providers/local-pty-shell-ready.ts、 src/main/providers/windows-shell-args.ts),hook 封装器 (src/main/agent-hooks/windows-powershell-hook-launcher.ts 及其调用方 src/main/agent-hooks/runtime-home-hook-command.ts、 src/main/agent-hooks/installer-utils.ts 和 src/main/claude/hook-settings.ts ——自 #18875 起,最后一个仅作为 回退,见下文), src/main/runtime/windows-default-route-interfaces.ts、 src/main/runtime/orchestration/setup-completion-signal.ts、 src/shared/hermes-startup-query.ts,以及上述四个曾使用 bypass 的位置。 src/main/runtime/windows-mobile-firewall.ts 编码一个脚本并通过 Start-Process -Verb RunAs 提升权限 启动它,这比上述任何形式都更强;只有该跳被编码,因为 -ArgumentList 会按空白重新拆分未加引号的参数字符串。

有一处仍然拼写为 -ExecutionPolicy Bypass 且没有编码,这是较弱的信号:src/main/cli/wsl-cli-scripts.ts(使用 -File,而且它是一个真正的脚本文件,所以该开关在那里并非空操作)。src/main/system-fonts.ts 将其改为普通的 -Command;src/shared/secure-path-windows-acl.ts 完全不再运行 PowerShell,而是改用 icacls.exe;computer use 功能现在在 src/main/computer/windows-powershell-execution-policy.ts 中要求 -ExecutionPolicy RemoteSigned,仅在策略阻止启动后才回退到 Bypass。

请使用 rg -- '-EncodedCommand|-ExecutionPolicy' src/ 重新生成,而不是相信上述清单;并注意原始 grep 会漏报:这些钩子位置通过 wrapWindowsPowerShellEncodedCommand 触及 -EncodedCommand,它们自己从不拼写该标志。

编码并非毫无必要:它可以保护路径和开关免受 cmd.exe 和 MSYS 的重写(#6078、#14815),这是一类真实的损坏问题。但 -EncodedCommand 是 Defender 的一级警报标题("Suspicious PowerShell command line"),而且 base64 会提高分数而非降低分数,因为它使分析器无法看到原本会予以放行的载荷。

钩子启动器是值得借鉴的既有实践。#16003 在一个上报的 Kaspersky 主机上测得,-WindowStyle Hidden 配合 -EncodedCommand 在 CreateProcess 处被拒绝,退出码为 126,与载荷无关——即使是 exit 0 也被拒绝。修复方法是停止_拼写_这些标志:WINDOWS_POWERSHELL_HOOK_SWITCHES 现在仅为 -NoProfile,另外在 #16576 中,执行策略绕过被移入载荷内部,作为进程作用域的 Set-ExecutionPolicy——这是真实的命令行信号削减,不过 #16003 测得的拒绝是针对 -WindowStyle Hidden + -EncodedCommand 的组合,而非绕过本身。同样诚实的是,底层行为并未改变。

复制这个模式,但也要复制它的告诫。windows-powershell-hook-launcher.ts 记录道,去掉 -WindowStyle Hidden 是一个真实的权衡,其抑制效果"从未被测量过",而且"在真实机器上仍未得到验证"。减少拼写出来的标志是正确的直觉;在有人实际测量之前,任何关于被移除标志具体作用的说法都应视为未经证实。

携带脱字符转义自由文本的 cmd.exe /c

src/shared/child-process/windows-command-line.ts 中的 buildWindowsCmdShimCommandLine 为 Windows 只能通过 cmd.exe 启动的 .cmd 和 .bat 目标构建 /d /v:off /s /c "…"(其中 codex.cmd 才是关键的那个)。由于 cmd 即使在带引号的 token 内也会展开 %VAR%,每个 % 都用 "^%" 进行转义。

这种转义并非装饰性的。在 Windows 11 上针对真实的 .cmd shim 测得,["a b", 'c"d', "e%F%g", "h&i", "j^k"] 返回为 ["a b", 'c"d', "e^%F^%g", "h"]——& 截断了参数,_并且_将剩余部分作为命令执行。

EDR 如何看待它: 脱字符转义是 cmd.exe 命令行中典型的混淆标记,而这里被转义的自由文本是 agent 提示词,因此该命令行冗长、高熵、且具有攻击者形态。这正是混淆命令行检测器专门针对的输入。

派生进程树本身

Orca.exe → 重定位后的守护进程宿主(在这些事件涉及的构建中为 orca-terminal-daemon.exe,之后为 Orca.exe)→ 一个 shell → 一个 agent CLI,这就是编码 agent 的终端多路复用器_本身_。reg.exe 来自 src/main/win32-utils.ts、src/main/agent-hooks/managed-hook-owner-identity.ts 和 src/relay/pty-shell-utils.ts(读取 OpenSSH 的 DefaultShell)。

这里没有任何东西在原则上是可避免的。可控的是深度和广度:Orca 与用户所要求的目标之间的每一次解释器跳转都会增加一条被评分的边;这正是为何 #15520 和 #15595 的既定方针是_缩短解释器链_而不是隐藏窗口。

18875 是该方针的一个实际案例。Claude Code 的生命周期钩子原先注册为 powershell.exe -NoProfile -EncodedCommand <...>,其解码后的完整载荷只是一个 Test-Path 和一次对 ~/.orca/agent-hooks/claude-hook.cmd 的调用。现在它直接注册脚本路径本身(<path> || echo {}),因此 bash -> powershell -> cmd -> curl 变成了 bash -> cmd -> curl,并且每个钩子事件一个的 powershell.exe -EncodedCommand——一级 Defender 警报标题——不再出现在该树中。上报的主机在五天内触发了约 6 900 次该警报,其中 70% 来自完全不在 Orca 下运行的 Claude 会话;这些会话的钩子在第一个 ORCA_PANE_KEY 守卫处就退出了。

被测量到的只有延迟和跳转次数,没有别的:空闲时每事件中位数 471 ms -> 213 ms,10 路并发下 656 ms -> 296 ms(p95 696 ms -> 337 ms),调用方式与 Claude Code 的调用方式一致。两棵树的 EDR 判定都没有被测量,因此要声称的是移除的 -EncodedCommand 拼写和更短的链,而不是某个分数。cmd.exe 仍留在树中,但由 MSYS 自己的 .cmd 生成逻辑拼写,而非由我们——即文档中"对 .cmd/.bat 不可避免"的那一种情况,携带绝对路径和两个字面 token,没有脱字符转义、没有编码、也没有自由文本。编码启动器仍然是以下场景所需要的形态:shell 无法原样携带的配置文件路径(含空格、%、^、&、非 ASCII、UNC 配置文件),以及 Git Bash 无法解析的主机,因为 PowerShell 5.1 会拒绝 ||(实测:解析错误,退出码 1)。

最后这一句是本变更的长期假设,值得直说,因为它没有被测量过。|| 在 Git Bash、cmd.exe 和 pwsh 中都能解析,但在 Windows PowerShell 5.1 中不能,因此直接形态对前三种主机中的任何一种都是正确的。Claude Code 本身在原生 Windows 上就是一个 Git Bash 主机。这里没有人验证过的是 _compat 消费方_使用哪种主机:cursor-agent 和 Devin 导入 ~/.claude/settings.json,并通过它们自己的启动器运行 command(受管的 .cmd 专门为此包含了 DEVIN_PROJECT_DIR 跳过逻辑)。如果其中某一个通过 Windows PowerShell 5.1 生成钩子字符串,它导入的 Claude 事件就会变成解析错误且 stdout 为空,这正是 #14818 所要防止的 fail-closed 情形。编码启动器没有这种假设——它是一个 powershell.exe 调用,因此在任何地方都能解析。在将直接形态推广到另一个 agent 之前,请先测量该消费方的主机。

计算机使用:屏幕捕获、合成输入、运行时编译的 MSIL

native/computer-use-windows/runtime.ps1 是一个大型 PowerShell 脚本。 src/main/computer/desktop-script-provider-bridge.ts 以如下方式启动它: powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -File runtime.ps1 <operation.json>,仅当启动因策略被阻止时,才以 Bypass 重试一次 — 每个操作一次,并且 desktop-script-provider-client.ts 每次都会将一份新的 operation.json 写入新的 临时目录。每次启动时,脚本都会对一段内联 C# 执行 Add-Type -TypeDefinition,该 C# 通过 P/Invoke 调用 SendInput 和窗口 API, 然后通过 Graphics.CopyFromScreen 捕获屏幕。

这是在同一个进程中堆叠的四种独立高信号行为:

行为 评分方式
Graphics.CopyFromScreen MITRE T1113,屏幕捕获 — Collection 战术
SendInput 合成键盘/鼠标 针对其他应用程序的输入合成
每次操作都执行 Add-Type -TypeDefinition 运行时编译 MSIL;事件 F 中的“可疑 MSIL 代码”
每个操作一个 powershell.exe 同一父进程下短生命周期解释器爆发

表格底部两行正是事件文本直接点名的两项,也是持久运行时宿主会消除的两项:一个长生命周期辅助进程只编译一次其 P/Invoke 桩,并通过通道响应操作,因此既不会重复 MSIL 重编译,也不会重复解释器爆发。在撰写本文时,一项实现该做法的变更正在推进中且尚未合并;关于已发布构建实际行为,请查看代码而不是本段。屏幕捕获和 SendInput 是该功能的固有组成部分,任何重构都无法移除它们。

签名不是门槛

整个事件集合中最有用的校准来自报告者自己的机器:Antigravity IDE 的主可执行文件为 NotSigned,且未被标记,而 Orca 的主可执行文件已签名,却被标记了六次。 他们的结论: “这里的门槛不是签名——而是行为。”

其机制在于 Defender 信誉是签名者加上普及度,而普及度以文件哈希为键。一个广泛安装的未签名二进制文件仅凭安装量即可通过。Orca 的签名来自 SignPath Foundation 的免费 OV 证书(config/electron-builder.config.cjs 设置 win.signtoolOptions.publisherName;config/scripts/verify-windows-inner-signature.mjs 固定为 CN=SignPath Foundation, O=SignPath Foundation, L=Lewes, S=Delaware, C=US), 被许多 OSS 项目共享,本身没有独立的 SmartScreen 或 MAPS 信誉。每次发布都会带来新的哈希,因此某个构建积累的任何普及度都会在下次更新时重置。开发渠道按设计以未签名方式发布,因为 SignPath 的审批等待无法适应开发节奏 (config/scripts/verify-dev-channel-packaging.mjs)。

为卸载程序签名是值得做的——一个未签名的 old-uninstaller.exe 在已签名安装程序下运行,是对更新集群的无谓贡献——但不要指望它会改变行为判定。三个非更新集群中根本没有任何未签名二进制文件。

我们不知道什么

事件分析记录了两个局限,这里保留它们而不是将其抹平:

  • 没有关于 Hermes 的数据。 本文档中的任何内容都没有描述 Hermes 在相同租户策略下的行为——尽管 src/shared/hermes-startup-query.ts 确实写明了 -EncodedCommand,因此缺口在于遥测,而不是表面。
  • Antigravity 未被标记只是证据缺失,而非证明。 它是一位报告者在一台机器上的回忆,不是一项测量。它足以证伪“问题是我们签名得不够好”;但它不足以支持关于 Defender 如何给该产品打分的肯定性主张。

再加上:这是一个租户、一种策略配置。同一构建在别处是否得到相同评分尚未测量。

给工程师的建议

上述若干形态的修复正在多个独立变更中推进;本节中的任何内容都不应被解读为某个站点已经变更的声明。在依赖之前,请先查看代码。

检查清单。在 Windows 上,不要使用:

不要 替代方案
命令行上的 -ExecutionPolicy Bypass 在进程范围内于载荷内设置策略,如 windows-powershell-hook-launcher.ts 所做的那样,或者根本不要运行 .ps1
-EncodedCommand 带参数的临时 .ps1,或不经过 PowerShell 跳转:优先使用原生 API 或现有 Node 路径
携带转义自由文本的 cmd.exe /c 直接生成真实目标。cmd.exe 仅在 .cmd/.bat 时不可避免;尽可能将自由文本排除在命令行之外
派生 powershell.exe 来读取系统状态 使用原生读取器——windows-process-enumeration.md 是进程表的常设规则
循环中每个操作一个进程 一个带请求通道的长生命周期辅助进程。同一父进程下短生命周期解释器爆发本身就是信号
运行时使用 Add-Type -TypeDefinition 预编译、已签名的程序集,或原生辅助程序
以不同名称复制我们自己的映像 原样复制——windows-daemon-host-relocation.md(已为守护进程宿主完成)
不要 改为
从 UI 偏好设置派生脚本运行器 windows-setup-shell.md — 脚本自行声明其解释器

两条比表格更持久的框架规则:

  • 缩短解释器链。 Orca 与用户实际目标之间的每一跳都是一条被评分的边,也是 AV 拒绝 CreateProcess 的位置。这是 #15520 和 #15595 的已发布准则。
  • 不要显式指定可以避免指定的标志。 #16003 测量到一次拒绝,它与载荷无关,完全取决于命令行上的开关组合。命令行上的内容本身就是检测面。

部署 Orca 的管理员指南

仅路径排除无法消除这些告警

这是最重要的单点运维要点,也是最常被搞错的一点。这六起事件是 MDE EDR 行为告警。Defender 杀毒软件路径排除会抑制 扫描 检测;它们不会以相同方式抑制 EDR 行为告警。将 %LOCALAPPDATA%\Programs\orca\ 添加到 AV 排除列表并期望事件停止,是行不通的。

真正阻止事件创建的方法

一条作用域限定到进程树的 MDE 告警抑制规则。在 Microsoft 365 Defender 中创建它(设置 → 端点 → 告警抑制),条件为:

  • 告警标题 — A suspicious file was observed 和 Suspicious PowerShell command line,以及你的租户实际产生的任何其他标题。请从你自己的事件中提取标题,而不是从本列表中提取。
  • 文件路径 — 位于 %LOCALAPPDATA%\Programs\orca\ 和 %LOCALAPPDATA%\Orca\daemon-host\ 下的 Orca.exe 与 orca-terminal-daemon.exe。

将范围限定到租户可容忍的最窄程度,并在 Orca 更新时审查它:daemon-host 路径包含一个 <version> 段,因此固定到某个版本的规则会静默停止匹配。该路径尤其有两个陷阱。物化会先暂存到一个 <version>.staging-<hex> 同级目录,然后再重命名到目标位置,因此精确版本规则会在更新过程中错过该树——而这正是更新集群事件触发的时刻。并且当 LOCALAPPDATA 未设置时,根目录会回退到 Electron userData 路径,因此 %LOCALAPPDATA%\Orca\daemon-host\ 是常规位置,而非保证位置。优先使用对 …\Orca\daemon-host\ 的前缀匹配,而不是固定到某个完整路径的规则。

也请为这两个目录添加 AV 路径排除——它们可以降低每次更新都会重写的树的扫描成本——但要理解分工。排除项减少扫描;抑制规则才是阻止事件创建的东西。

检查 ASR 规则

检查租户是否启用了攻击面缩减规则 “除非满足流行度、年龄或可信列表标准,否则阻止可执行文件运行”。如果已启用,仅此一点就能解释为什么每次更新后新签名的 Orca 构建都会立即被命中:每个版本都会发布新的哈希值,因此无论如何签名,每个构建都从零流行度和零年龄开始。要么为该规则将 Orca 安装路径加入允许列表,要么预期每次更新都会命中。

预期每次更新后告警会再次出现

流行度以文件哈希为键。更新会替换哈希值,信誉重新开始,而抑制规则是唯一能跨更新保留的东西。

计算机使用:部署前做出决定

在受监控端点上启用计算机使用之前,而不是之后,阅读本节。

在受监控端点上,一条显示 “Screenshots were taken unexpectedly on this device” 的告警,不是 SOC 会一眼忽略的那类发现。

事件 E 是预期形态:5 条告警、37 个证据项、一个映射到 ATT&CK 执行 + 收集 的多阶段事件,以及描述中点名在由 powershell.exe 启动的脚本中发现屏幕捕获。事件 F 在同一进程树中添加了运行时编译的 MSIL。

其中每一部分都是该功能实际行为的准确描述。Orca 的计算机使用会截取屏幕截图,向其他应用程序合成键盘和鼠标输入,并在运行时编译其所需的 P/Invoke 存根。监控收集战术活动的组织——任何以默认事件创建方式运行 MDE 的组织都会这样做——会看到它,并且会将其视为收集。

因此,请提前审慎决定:

  • 将其加入允许列表,并创建一条抑制规则,覆盖计算机使用进程树(powershell.exe 带 -File …\runtime.ps1)以及基础 Orca 路径,并在第一次事件发生之前而不是事件期间告知 SOC 它是什么。
  • 或者在受监控端点上保持禁用。

不可行的做法是未经分诊就部署,然后被动地处理事件。等到一个收集战术事件被打开时,分析师已经在阅读“在用户不知情的情况下截取屏幕截图”的描述,而举证责任已经转移到了你身上。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 orca48/orca