Lovedipsingh/sentinel-kql-detection-lab
GitHub: Lovedipsingh/sentinel-kql-detection-lab
这是一个Microsoft Sentinel的检测实验室,提供5个生产级KQL规则来检测凭据攻击并优化误报,映射到MITRE ATT&CK框架。
Stars: 0 | Forks: 0
# 🔵 Microsoft Sentinel SOC 检测实验室
**Sentinel | KQL | Azure | MITRE ATT&CK | 蓝队**
在Azure中部署的Microsoft Sentinel SIEM实验 — 5个KQL检测查询,涵盖凭据泄露关联、暴力破解攻击、外部IP异常、SYSTEM账户滥用以及非工作时间登录。包含一个与MITRE ATT&CK映射关联的实时自动化分析规则,可自动生成事件。
## 📖 如何阅读此仓库
- **30秒快速浏览:** 阅读下面的执行摘要和测试矩阵
- **深入研究:** 每个查询都包含描述、KQL代码、截图、MITRE映射和调优指南
- **仅代码:** 检测逻辑位于 `/queries/` 目录下,以 `.kql` 文件形式存在
- **工程决策:** 参见 `DECISIONS.md` 了解阈值、时间窗口和调优选择背后的原因
## 🎯 目标
在Azure中部署Microsoft Sentinel,编写涵盖常见攻击模式的KQL检测查询,并将检测转化为可自动生成可操作事件的自动化分析规则 — 在实验环境中演示端到端的SOC检测工程工作流程。
## 🔬 环境
| 组件 | 详情 |
|---|---|
| 平台 | Microsoft Sentinel (Azure 云) |
| 工作区 | soc-lab-sentinel |
| 查询语言 | KQL (Kusto 查询语言) |
| 数据源 | Windows 安全事件 (SecurityEvent 表) |
| 分析规则 | 定时查询 — 每 5 分钟运行一次,回溯 15 分钟 |
## 📋 执行摘要
在Azure中部署了一个Microsoft Sentinel工作区,并编写了5个SOC风格的KQL检测规则,涵盖了常见的Tier 1告警场景 — 凭据泄露关联、暴力破解、外部IP登录、SYSTEM账户滥用和非工作时间访问。将优先级最高的检测转化为一个实时的定时分析规则,当检测到暴力破解活动时,会自动生成高严重性事件。
**关键成果:** 通过排除登录类型5(服务账户)的活动,对查询4(SYSTEM账户登录)的调优消除了47个误报中的45个 — **减少了96%**。所有五个查询都经历了类似的误报调优周期,记录在下面的测试与验证矩阵中。
**特色检测:** 查询1(多次失败后的成功登录)使用时序关联来识别高置信度的凭据泄露模式 — 来自同一账户、主机和IP的重复失败登录之后的成功登录 — 映射到MITRE T1110。
所有检测都包含明确的时间窗口、IPv4/IPv6过滤以及经过实验室测试的调优指南。查询均映射到MITRE ATT&CK框架。
## 🔍 KQL 检测查询
### 查询 1 — 多次失败后的成功登录 (T1110) ⭐ 特色
**描述:** 在定义的时间窗口内,将重复的失败登录与来自同一来源的后续成功登录进行关联 — 这是可能存在凭据泄露的高可信度指标。
**关键工程选择:**
- 时序关联:成功必须发生在失败**之后**,而不是之前
- 30分钟关联窗口防止不相关活动导致的误关联
- 在账户 + 计算机名 + IP地址上进行严格连接以降低误报率
- 结果按失败次数和最近性排序,便于分析师优先处理
```
let Lookback = 1h;
let FailureThreshold = 3;
let CorrelationWindow = 30m;
let FailedLogons =
SecurityEvent
| where TimeGenerated >= ago(Lookback)
| where EventID == 4625
| where IpAddress !in ("-", "", "127.0.0.1", "::1")
| summarize FailCount = count(),
FirstFail = min(TimeGenerated),
LastFail = max(TimeGenerated)
by Account, Computer, IpAddress
| where FailCount >= FailureThreshold;
let SuccessfulLogons =
SecurityEvent
| where TimeGenerated >= ago(Lookback)
| where EventID == 4624
| where IpAddress !in ("-", "", "127.0.0.1", "::1")
| project Account, Computer, IpAddress, SuccessTime = TimeGenerated;
SuccessfulLogons
| join kind=inner FailedLogons on Account, Computer, IpAddress
| where SuccessTime > LastFail
| where SuccessTime <= LastFail + CorrelationWindow
| summarize FirstSuccess = min(SuccessTime),
LastSuccess = max(SuccessTime),
SuccessCount = count(),
FailCount = max(FailCount),
FirstFail = min(FirstFail),
LastFail = max(LastFail)
by Account, Computer, IpAddress
| extend Severity = "CRITICAL"
| extend Description = strcat(
"Successful logon from same source after ",
tostring(FailCount),
" failed attempts within ",
tostring(CorrelationWindow),
" - possible successful brute force"
)
| project FirstSuccess, LastSuccess, Account, Computer, IpAddress, SuccessCount, FailCount, FirstFail, LastFail, Severity, Description
| order by FailCount desc, LastSuccess desc
```

**调优指南(实验室测试):**
- 采用严格关联(相同账户+计算机+IP)以实现低误报率
- 为获得更广泛的覆盖范围,可部署一个仅基于账户进行关联的平行规则 — 误报率较高,但能捕获来源跳跃攻击
- 根据环境基线调整关联窗口(15分钟–1小时)
### 查询 2 — 暴力破解检测 (T1110)
**描述:** 标记在15分钟内登录尝试失败5次及以上的账户 — 表明存在密码喷洒或暴力破解活动。
**关键工程选择:**
- 明确的15分钟回溯期与分析规则运行频率保持一致
- 过滤空账户和环回IP地址以去除噪声
- 将检测时间戳与事件时间戳分开投影,以便于分诊
```
let Lookback = 15m;
let FailureThreshold = 5;
SecurityEvent
| where TimeGenerated >= ago(Lookback)
| where EventID == 4625
| where isnotempty(Account) and isnotempty(Computer)
| where IpAddress !in ("-", "", "127.0.0.1", "::1")
| summarize FailedAttempts = count(),
FirstAttempt = min(TimeGenerated),
LastAttempt = max(TimeGenerated)
by Account, Computer, IpAddress
| where FailedAttempts >= FailureThreshold
| extend Severity = "HIGH"
| extend Description = strcat(
"Possible brute force: ",
tostring(FailedAttempts),
" failed logons within ",
tostring(Lookback)
)
| project TimeDetected = now(),
Account,
Computer,
IpAddress,
FailedAttempts,
FirstAttempt,
LastAttempt,
Severity,
Description
```

**调优指南(实验室测试):**
- 按IP地址排除已知的漏洞扫描器
- 验证后排除嘈杂的服务账户
- 根据环境基线调整阈值(3–10)(原因见 `DECISIONS.md`)
### 查询 3 — 外部IP登录异常 (T1078)
**描述:** 标记来自非私有IPv4地址的成功或失败登录,排除RFC1918地址、环回地址、APIPA地址和IPv6链路本地范围。
**关键工程选择:**
- 使用原生的 `ipv4_is_in_range()` 函数而非正则表达式(正确处理172.16.0.0/12 — 一个常见的静默覆盖缺口来源)
- 包含IPv6私有范围过滤
- 将成功和失败计数分开,以便于分诊优先级排序
```
let Lookback = 1h;
SecurityEvent
| where TimeGenerated >= ago(Lookback)
| where EventID in (4624, 4625)
| where isnotempty(IpAddress)
| where not(ipv4_is_in_range(IpAddress, "10.0.0.0/8"))
| where not(ipv4_is_in_range(IpAddress, "192.168.0.0/16"))
| where not(ipv4_is_in_range(IpAddress, "172.16.0.0/12"))
| where not(ipv4_is_in_range(IpAddress, "169.254.0.0/16"))
| where IpAddress !in ("127.0.0.1", "::1", "-", "")
| where not(IpAddress startswith "fe80:")
| where not(IpAddress startswith "fc00:")
| where not(IpAddress startswith "fd00:")
| summarize AttemptCount = count(),
SuccessCount = countif(EventID == 4624),
FailureCount = countif(EventID == 4625),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by Account, Computer, IpAddress
| extend Severity = iff(SuccessCount > 0, "HIGH", "MEDIUM")
| extend Description = iff(
SuccessCount > 0,
"Successful logon from external IP address",
"Failed logon attempts from external IP address"
)
| project Account, Computer, IpAddress, AttemptCount, SuccessCount, FailureCount, FirstSeen, LastSeen, Severity, Description
```

**调优指南(实验室测试):**
- 将VPN出口IP加入白名单
- 将云身份提供商基础设施(Okta, Microsoft Entra ID)加入白名单
- 将已知的远程管理网关加入白名单
### 查询 4 — SYSTEM 账户网络登录 (T1078.003)
**描述:** 标记使用网络(类型3)或远程交互(类型10)登录类型的 `NT AUTHORITY\SYSTEM` 登录 — 与横向移动或C2活动一致。
**关键工程选择:**
- 精确匹配 `NT AUTHORITY\SYSTEM`(不使用部分匹配)
- 排除登录类型5(服务)以移除整个良性基线类别 — 这是减少96%误报的关键
- 针对每种登录类型提供特定于上下文的描述,便于分析师分诊
```
let Lookback = 1h;
SecurityEvent
| where TimeGenerated >= ago(Lookback)
| where EventID == 4624
| where Account =~ @"NT AUTHORITY\SYSTEM"
| where LogonType in (3, 10)
| where IpAddress !in ("-", "", "127.0.0.1", "::1")
| extend Severity = "HIGH"
| extend Description = case(
LogonType == 3, "SYSTEM network logon detected - review for lateral movement or remote service activity",
LogonType == 10, "SYSTEM remote interactive logon detected - review for RDP abuse or session hijacking",
"SYSTEM logon detected"
)
| project TimeGenerated, Account, Computer, IpAddress, LogonType, Severity, Description
```

**调优指南(实验室测试):**
- 按源IP地址排除已批准的管理工具
- 验证后备份代理和远程管理平台
- 登录类型10对于SYSTEM来说很少见 — 需立即调查
### 查询 5 — 非工作时间登录 (T1078)
**描述:** 标记在UTC时间早上7点之前或晚上7点之后的成功登录 — 支持内部威胁和凭据泄露检测。
**关键工程选择:**
- 明确文档说明时间评估是在UTC时间下进行
- 排除Windows系统账户(DWM、UMFD、以 `$` 结尾的机器账户)
- 在告警描述中包含时区上下文,便于分析师理解
```
let Lookback = 3d;
let BusinessStartHour = 7; // 7 AM UTC
let BusinessEndHour = 19; // 7 PM UTC
SecurityEvent
| where TimeGenerated >= ago(Lookback)
| where EventID == 4624
| where Account !contains "SYSTEM"
| where Account !startswith "DWM-"
| where Account !startswith "UMFD-"
| where Account !endswith "$"
| extend HourOfDay = datetime_part("hour", TimeGenerated)
| where HourOfDay < BusinessStartHour or HourOfDay >= BusinessEndHour
| extend Severity = "MEDIUM"
| extend Description = strcat(
"Logon outside business hours at ",
format_datetime(TimeGenerated, "yyyy-MM-dd HH:mm:ss"),
" UTC (Hour: ", tostring(HourOfDay), ")"
)
| project TimeGenerated, Account, Computer, IpAddress, HourOfDay, Severity, Description
```

**调优指南(实验室测试):**
- 根据组织所在的时区调整工作时间(应用UTC偏移量)
- 将已批准的非工作时间用户(值班人员、轮班工人)加入白名单
- 排除已知的批处理作业和计划任务
## 🚨 分析规则 — 实时检测
查询2(暴力破解检测)已被转化为一个在Microsoft Sentinel中每5分钟运行一次的定时分析规则。触发时,它会自动生成一个映射到MITRE T1110的高严重性事件。
| 设置 | 值 |
|---|---|
| 规则名称 | Brute Force Detection - Multiple Failed Logons |
| 严重性 | 高 |
| 状态 | 已启用 |
| 运行频率 | 每 5 分钟 |
| 回溯期 | 15 分钟 |
| 告警阈值 | 结果数大于 0 |
| 事件创建 | 已启用 |
| 实体映射 | 账户、主机、IP |
| 告警分组 | 按匹配的实体分组 |
| 抑制时间 | 1 小时 |
| MITRE 战术 | 凭据访问 |
| MITRE 技术 | T1110 - 暴力破解 |

**为何采用此配置:**
- 5分钟的运行频率配合15分钟的回溯期,确保告警延迟最小且无遗漏
- 实体映射支持为调查剧本自动提取实体
- 按实体分组告警,减少来自同一攻击活动的重复事件
- 1小时的抑制期防止因重复失败导致的告警疲劳
## 🗺️ MITRE ATT&CK 映射
| 查询 | 技术 | ID |
|---|---|---|
| Q1 — 失败后的成功登录 | 暴力破解 | T1110 |
| Q2 — 暴力破解检测 | 暴力破解 | T1110 |
| Q3 — 外部IP登录 | 有效账户 | T1078 |
| Q4 — SYSTEM 账户登录 | 有效账户: 本地账户 | T1078.003 |
| Q5 — 非工作时间登录 | 有效账户 | T1078 |
## 🧪 测试与验证
每个查询都在 `soc-lab-sentinel` 工作区中使用模拟的Windows安全事件日志进行了测试。
| 查询 | 测试方法 | 初始结果 | 误报 | 应用的调优 |
|---|---|---|---|---|
| Q1 — 失败后的成功登录 | 关联事件 | 2 个告警 | 0 | 时序关联工作正常 |
| Q2 — 暴力破解 | 模拟失败登录 | 12 个告警 | 3 (扫描器流量) | 排除了环回IP地址 |
| Q3 — 外部IP | VPN 和互联网登录 | 8 个告警 | 2 (云身份提供商) | 记录了白名单需求 |
| Q4 — SYSTEM 账户 | 服务登录 | 47 个告警 | 45 (登录类型 5) | 从查询中移除了登录类型 5 |
| Q5 — 非工作时间 | 周末登录 | 23 个告警 | 5 (机器账户) | 排除了以 `$` 结尾的账户 |
**关键发现:**
- Q4 最初包含登录类型5,产生了45个误报。将其移除后,噪声减少了**96%**。
- Q3 的 RFC1918 过滤最初使用正则表达式不完整(捕获了所有172.x地址)。切换到 `ipv4_is_in_range()` 修复了静默覆盖缺口。
- Q1 的时序关联防止了成功登录发生在失败窗口*之前*时的误匹配。
## 🔵 演示的SOC分析师工作流程
1. **检测工程** — 识别可疑的认证模式(失败登录、外部IP、SYSTEM滥用、非工作时间访问)
2. **查询开发** — 编写具有适当时间范围、实体过滤和连接逻辑的KQL查询
3. **阈值调优** — 根据环境基线和误报/真阳性权衡分析设置阈值
4. **误报减少** — 排除已知的噪声源(扫描器、VPN、服务账户、机器账户)
5. **时序关联** — 使用时间窗口和严格的连接键关联相关事件(失败 -> 成功)
6. **自动化** — 将验证过的查询转化为定时分析规则
7. **事件创建** — 为Tier 1分诊启用自动生成高/严重严重性事件
8. **实体映射** — 提取账户、主机、IP,用于调查剧本
## 📁 仓库结构
```
sentinel-soc-detection-lab/
├── README.md
├── DECISIONS.md
├── queries/
│ ├── 01-successful-after-failures.kql
│ ├── 02-brute-force-detection.kql
│ ├── 03-external-ip-logon.kql
│ ├── 04-system-account-logon.kql
│ └── 05-after-hours-logon.kql
└── screenshots/
├── kql-01-brute-force-detection.png
├── kql-02-external-ip-logon.png
├── kql-03-system-account-logon.png
├── kql-04-after-hours-logon.png
├── kql-05-successful-brute-force.png
└── kql-06-analytics-rule.png
```
## 🏅 展示的技能
- **Microsoft Sentinel:** 在Azure中部署和配置工作区
- **KQL 查询语言:** 高级过滤、聚合、关联和时间序列分析
- **检测工程:** 将威胁情报转化为可操作的检测规则
- **时序逻辑:** 使用 `let` 语句和 `join` 操作进行多查询关联
- **误报减少:** IP范围过滤、账户排除、登录类型限定
- **分析规则创建:** 具有实体映射和告警分组的定时查询
- **MITRE ATT&CK:** 用于威胁覆盖映射的战术和技术分类
- **工程文档:** 决策依据、调优指南和测试验证
## 🔗 联系
由 **Lovedip Singh** 构建
[领英](https://linkedin.com/in/lovedipsingh) | [GitHub](https://github.com/Lovedipsingh)
本项目展示了适用于SOC分析师和 Tier
标签:AMSI绕过, Azure, Cloudflare, KQL, Microsoft Sentinel, MITRE ATT&CK, PoC, RFC1918过滤, SYSTEM账户滥用, 凭证攻击, 威胁检测, 安全事件, 安全运营中心, 异常登录, 时间相关性, 暴力破解, 检测规则, 网络安全, 网络映射, 网络资产发现, 自动化响应, 误报调优, 隐私保护, 非工作时间访问