行为监控暴露面收敛与持久化检测防御
防御目标与威胁面
在 08-procmon-patterns.md 中,观察者借助 Procmon 过滤 WriteFile、RegSetValue、ProcessCreate/LoadImage/CreateRemoteThread 与 TCP Connect 事件,可以快速绘制目标软件的磁盘落盘路径、注册表持久化键位、DLL 依赖及后端通信端点。
从蓝队视角来看,该场景包含两层防御任务:
- 收敛自身软件的可观察敏感面:避免在
AppData/Temp/注册表写入明文配置、凭证或未签名授权状态,防止被直接读取或篡改;对敏感文件实施 DPAPI 加密与严格目录 ACL;对通信链路强制 TLS 1.3 + 证书固定(Pinning)。 - 复用行为模式构建端点检测基线:将异常落盘(用户目录可执行写入)、敏感注册表修改(
Run/Winlogon/IFEO)、跨进程线程创建与未知外连转化为自动化的 Sysmon/Sigma 告警规则。
核心防御架构
| 行为监控通道 | 自身软件加固措施 | 端点异常检测规则 |
|---|---|---|
文件写入(WriteFile / CreateFile) | 禁止明文写凭证或本地状态;使用 CryptProtectData(DPAPI)+ 专属 ACL 保护状态文件 | 告警非安装器向 %APPDATA%/%TEMP% 写入 PE/DLL/脚本文件 |
注册表写入(RegSetValue) | 不在注册表存放明文授权或敏感配置;仅存必要系统集成项 | 监控 Run、RunOnce、Winlogon、Services 与 Image File Execution Options 写入 |
进程与模块活动(ProcessCreate / LoadImage) | 子进程启动使用 CreateProcessW 完整绝对路径与命令行引号保护,校验依赖签名 | 关联 CreateRemoteThread 与非系统路径 LoadImage 告警注入行为 |
网络连接(TCP Connect / UDP) | 全程 TLS + SPKI Pinning + 服务端签发短生命周期令牌,观测 IP/域名亦无法重放 | 统计异常外连目的 IP/端口与非标准进程外连(如办公文档进程发起连接) |
加固实现与检测代码
以下 Python 脚本提供蓝队双用途校验:一方面使用 Windows 行为 CSV 日志模式识别高危持久化(Run/Winlogon/IFEO)、用户目录可疑落盘及远程线程注入指标;另一方面校验本地持久化配置文件是否误含明文敏感字段:
python
"""procmon_blue_analyzer.py: 分析 Procmon 导出事件中的高危行为基线并校验配置文件明文暴露"""
from __future__ import annotations
import csv
import io
import json
from typing import Dict, List
PERSISTENCE_REG_KEYS = ("\\Run", "\\RunOnce", "\\Winlogon", "\\Image File Execution Options", "\\Services\\")
SUSPICIOUS_DROP_EXTS = (".exe", ".dll", ".sys", ".ps1", ".vbs", ".bat")
def evaluate_procmon_csv(csv_text: str) -> List[Dict[str, str]]:
alerts: List[Dict[str, str]] = []
reader = csv.DictReader(io.StringIO(csv_text))
for row in reader:
op = row.get("Operation", "")
path = row.get("Path", "")
proc = row.get("Process Name", "")
if op == "RegSetValue" and any(k.lower() in path.lower() for k in PERSISTENCE_REG_KEYS):
alerts.append({"rule": "registry_persistence", "process": proc, "path": path})
elif op == "WriteFile" and path.lower().endswith(SUSPICIOUS_DROP_EXTS):
if "\\appdata\\" in path.lower() or "\\temp\\" in path.lower():
alerts.append({"rule": "user_dir_executable_drop", "process": proc, "path": path})
elif op == "CreateRemoteThread":
alerts.append({"rule": "remote_thread_injection", "process": proc, "path": path})
return alerts
def check_config_plaintext_leak(config_json: str) -> List[str]:
data = json.loads(config_json)
forbidden_keys = {"license_key", "private_key", "secret", "password", "raw_token"}
exposed: List[str] = []
def walk(node: object, prefix: str = "") -> None:
if isinstance(node, dict):
for k, v in node.items():
full = f"{prefix}.{k}" if prefix else k
if k.lower() in forbidden_keys and isinstance(v, str) and not v.startswith("dpapi:"):
exposed.append(full)
walk(v, full)
elif isinstance(node, list):
for idx, item in enumerate(node):
walk(item, f"{prefix}[{idx}]")
walk(data)
return exposed
if __name__ == "__main__":
sample_csv = (
"Time,Process Name,Operation,Path,Detail\n"
"12:00:01,unknown.exe,RegSetValue,HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\Updater,SUCCESS\n"
"12:00:02,unknown.exe,WriteFile,C:\\ProgramData\\AppData\\Temp\\helper.dll,Offset:0\n"
"12:00:03,notepad.exe,ReadFile,C:\\Windows\\System32\\ntdll.dll,SUCCESS\n"
)
hits = evaluate_procmon_csv(sample_csv)
assert len(hits) == 2
leaks = check_config_plaintext_leak('{"auth": {"license_key": "ABCD-1234", "sealed": "dpapi:AQAA"}}')
assert leaks == ["auth.license_key"]
print("Procmon defense analyzer self-check passed.")以下 C++ 片段演示使用 Windows DPAPI(CryptProtectData)对必须本地落盘的配置或状态载荷进行机器/用户绑定加密,防止通过 WriteFile 监控路径后直接阅读或篡改明文内容:
cpp
// dpapi_state_seal.cpp: 使用 DPAPI + 附加熵保护本地持久化状态
#include <windows.h>
#include <wincrypt.h>
#include <vector>
#include <cstdint>
#pragma comment(lib, "crypt32.lib")
bool SealLocalState(const std::vector<uint8_t>& plaintext,
const std::vector<uint8_t>& appEntropy,
std::vector<uint8_t>& outBlob) {
DATA_BLOB inBlob = { static_cast<DWORD>(plaintext.size()),
const_cast<BYTE*>(plaintext.data()) };
DATA_BLOB entropyBlob = { static_cast<DWORD>(appEntropy.size()),
const_cast<BYTE*>(appEntropy.data()) };
DATA_BLOB protectedBlob = {};
if (!CryptProtectData(&inBlob, L"AppSealedState", &entropyBlob,
nullptr, nullptr, CRYPTPROTECT_UI_FORBIDDEN, &protectedBlob)) {
return false;
}
outBlob.assign(protectedBlob.pbData, protectedBlob.pbData + protectedBlob.cbData);
LocalFree(protectedBlob.pbData);
return true;
}防御工作流
text
1. 敏感落盘收敛:排查所有 WriteFile/RegSetValue 调用点,消除明文密钥/授权状态写入,改用 DPAPI + 服务端签名载荷
2. 权限边界控制:为应用数据目录设置最小权限 ACL,拒绝非同用户或非提权实体枚举读写
3. 网络暴露面收敛:所有激活与遥测连接启用 TLS 1.3 与证书固定,使捕获目的 IP/域名无法直接伪造响应
4. 行为检测规则上线:使用 make_procmon_filters 与 make_sigma_stub 将持久化写入与跨进程注入行为转化为持续监控基线验证与判定标准
- 明文零落盘验证:对受保护软件开启全流程 Procmon 捕获后,使用
check_config_plaintext_leak与字符串检索检查全部新建文件与注册表键值,不得发现未加密的授权密钥或明文凭证。 - 持久化与落盘告警:向
evaluate_procmon_csv输入模拟的Run键写入或%TEMP%目录.dll落盘日志时,必须在零漏报下准确命中对应规则。 - 跨环境抗重放:复制 DPAPI 保护的本地状态文件到另一账户或另一主机尝试加载时,
CryptUnprotectData必须解密失败。
MCP 工具映射
| 防御步骤 | MCP 工具 | 说明 |
|---|---|---|
| 生成蓝队行为监控过滤集 | make_procmon_filters | 基于样本导入表生成文件/注册表/网络异常监视配置 |
| 生成持久化与异常落盘规则 | make_sigma_stub | 输出覆盖 Run/IFEO/Winlogon 与远程线程的 Sigma 规则 |
| 梳理样本文件与注册表导入调用 | triage_pe、ghidra_summary_imports | 排查明文写盘与未受保护的注册表 API 调用点 |
| 检索红蓝成对文档 | kb_router | 对照 08-procmon-patterns.md 完善行为覆盖 |