Skip to content

行为监控暴露面收敛与持久化检测防御 ​

防御目标与威胁面 ​

在 08-procmon-patterns.md 中,观察者借助 Procmon 过滤 WriteFile、RegSetValue、ProcessCreate/LoadImage/CreateRemoteThread 与 TCP Connect 事件,可以快速绘制目标软件的磁盘落盘路径、注册表持久化键位、DLL 依赖及后端通信端点。

从蓝队视角来看,该场景包含两层防御任务:

  1. 收敛自身软件的可观察敏感面:避免在 AppData/Temp/注册表写入明文配置、凭证或未签名授权状态,防止被直接读取或篡改;对敏感文件实施 DPAPI 加密与严格目录 ACL;对通信链路强制 TLS 1.3 + 证书固定(Pinning)。
  2. 复用行为模式构建端点检测基线:将异常落盘(用户目录可执行写入)、敏感注册表修改(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 完善行为覆盖

Apache-2.0 · 仅供授权环境下的学习与防御性研究使用 · 免责声明