cybernovaacademy/KQL-THREAT-HUNTING

GitHub: cybernovaacademy/KQL-THREAT-HUNTING

CyberNova Academy 推出的一套从零到实战的 KQL 威胁狩猎课程,帮助初学者掌握 Microsoft 安全栈下的日志分析与威胁检测技能。

Stars: 0 | Forks: 0

# CyberNova Academy — KQL 与威胁狩猎精通课程

## 课程标识 | 字段 | 详细信息 | |---|---| | 课程名称 | KQL 与威胁狩猎精通课程 | | 副标题 | 从零到 SOC 分析师 | | 提供者 | CyberNova Academy | | 主要平台 | Microsoft Sentinel, Microsoft Defender XDR, Log Analytics Workspace | | 主表 | DeviceLogonEvents | | 技能路径 | 日志分析 → KQL 基础 → 威胁狩猎 → 检测工程 | | 目标学习者 | 初级 SOC 分析师、IT 管理员、威胁猎人、网络安全理学硕士学生 | | 预计时长 | 15–18 小时 | ## 课程介绍 ### 我们在学什么? 本课程教授学习者如何使用 **Kusto Query Language (KQL)**,利用 Microsoft 安全遥测技术调查身份验证活动、检测可疑行为,并培养实用的威胁狩猎技能。 学习者将在以下方面建立信心: - Kusto Query Language 基础知识 - 读取、过滤和分析安全日志 - Microsoft Defender 和 Sentinel 风格的调查工作流 - DeviceLogonEvents 身份验证分析 - 暴力破解检测 - 密码喷洒检测 - 外部访问调查 - 权限提升狩猎 - 横向移动分析 - 可迁移的 SIEM 查询逻辑 ### 我们为什么要学这个? | 原因 | 网络安全价值 | |---|---| | 就业市场需求 | 在使用 Microsoft 安全技术栈的众多 SOC 职位中都有 KQL 的要求 | | 速度 | 手动审查日志耗时数小时;KQL 可将调查时间缩短至几秒 | | 主动防御 | 威胁狩猎能在警报触发前发现攻击者的行为 | | 职业发展 | KQL 技能能将初级分析师与更优秀的二级/三级分析师区分开来 | | 现实相关性 | SOC 分析师在入职的第一周就需要查询日志 | ## 平台转换思维 | 概念 | Microsoft KQL | Splunk SPL | Elastic / OpenSearch | AWS CloudWatch | |---|---|---|---|---| | 过滤行 | `where` | `search` / `where` | Query filter | `filter` | | 选择字段 | `project` | `fields` / `table` | `_source` filtering | `fields` | | 分组结果 | `summarize` | `stats` | Aggregations | `stats` | | 排序 | `order by` | `sort` | Sort clause | `sort` | | 时间范围 | `ago()` / `datetime()` | `earliest=` | time picker / range | `ago()` 样式过滤器 | 逻辑是通用的。语法只是词汇。 # 模块 1 — 基础:理解日志
## 第 1.1 课 — 什么是日志? 日志是系统活动的数字凭证。它们记录了诸如登录、进程启动、网络连接、文件创建、服务更改和安全事件等操作。 ### 日志回答的三个问题 | 问题 | 含义 | |---|---| | 发生了什么? | 记录的活动或事件 | | 什么时候发生的? | 事件的时间戳 | | 是谁或什么引起的? | 涉及的用户、进程、设备或来源 | ### 现实世界背景 没有日志,事件响应就变成了凭空猜测。有了日志,分析师可以重建攻击者的行为,证明时间线,识别受影响的资产,并建议遏制措施。 ## 第 1.2 课 — Log Analytics Workspace **Log Analytics Workspace** 是 Microsoft 基于云的日志存储和分析环境。 ### Excel 类比 | Excel 概念 | Log Analytics 对应项 | |---|---| | 工作簿 | Log Analytics Workspace | | 工作表 / 标签页 | 表 | | 行 | 单个日志事件 | | 列 | 字段 / 属性 | ### 常见安全表 | 表格 | 用途 | |---|---| | DeviceLogonEvents | 身份验证和登录活动 | | DeviceProcessEvents | 进程执行和命令行 | | DeviceNetworkEvents | 网络连接 | | DeviceFileEvents | 文件创建、删除和修改 | | SecurityAlert | 触发的警报 | | SigninLogs | Azure AD / Entra ID 身份验证 | ## 第 1.3 课 — 什么是 KQL? KQL 是一种用于查询大型安全数据集的语言。 ``` DeviceLogonEvents | where ActionType == "LogonFailed" | project Timestamp, DeviceName, AccountName, RemoteIP ``` KQL 允许分析师: - 快速过滤数百万行数据 - 仅选择有用的列 - 将事件分组为模式 - 构建检测 - 创建仪表板 - 跨表透视 # 模块 2 — KQL 基础
## 第 2.1 课 — 你的第一个查询 ### 从表格开始 ``` DeviceLogonEvents ``` ### 提取样本 ``` DeviceLogonEvents | take 10 ``` ### 使用 `where` 过滤行 ``` DeviceLogonEvents | where ActionType == "LogonSuccess" ``` ### 使用 `project` 选择列 ``` DeviceLogonEvents | project Timestamp, DeviceName, AccountName, ActionType ``` ## 第 2.2 课 — 专业过滤 | 运算符 | 含义 | 示例 | |---|---|---| | `==` | 精确匹配 | `ActionType == "LogonFailed"` | | `!=` | 不等于 | `AccountName != "guest"` | | `contains` | 部分文本匹配 | `DeviceName contains "server"` | | `has` | 词界匹配 | `ProcessCommandLine has "powershell"` | | `startswith` | 以某值开头 | `AccountName startswith "adm"` | | `endswith` | 以某值结尾 | `FileName endswith ".exe"` | | `in` | 多个值 | `ActionType in ("LogonSuccess", "LogonFailed")` | ### 实际示例 ``` DeviceLogonEvents | where ActionType == "LogonFailed" ``` ``` DeviceLogonEvents | where AccountName == "administrator" ``` ``` DeviceLogonEvents | where LogonType == "Network" ``` ``` DeviceLogonEvents | where RemoteIPType == "Public" ``` ``` DeviceLogonEvents | where ActionType == "LogonFailed" and RemoteIPType == "Public" ``` ## 第 2.3 课 — 基于时间的过滤 ### 相对时间 ``` DeviceLogonEvents | where Timestamp > ago(24h) ``` ``` DeviceLogonEvents | where Timestamp > ago(7d) ``` ``` DeviceLogonEvents | where Timestamp > ago(1h) ``` ### 特定时间范围 ``` DeviceLogonEvents | where Timestamp between (datetime(2026-01-13 06:00:00) .. datetime(2026-01-13 08:00:00)) ``` ### 专业提示 始终尽早按时间过滤以提高性能。 ## 第 2.4 课 — 排序与限制 ``` DeviceLogonEvents | order by Timestamp desc ``` ``` DeviceLogonEvents | top 10 by Timestamp desc ``` ``` DeviceLogonEvents | where Timestamp > ago(24h) | where ActionType == "LogonFailed" | order by Timestamp desc | take 100 ``` ## 第 2.5 课 — 计数与聚合 ### 计算行数 ``` DeviceLogonEvents | where Timestamp > ago(24h) | count ``` ### 按操作类型汇总 ``` DeviceLogonEvents | where Timestamp > ago(24h) | summarize count() by ActionType ``` ### 按 IP 统计失败登录 ``` DeviceLogonEvents | where Timestamp > ago(24h) | where ActionType == "LogonFailed" | summarize FailedCount = count() by RemoteIP | order by FailedCount desc ``` ### 每台设备的唯一用户 ``` DeviceLogonEvents | where Timestamp > ago(24h) | summarize UniqueUsers = dcount(AccountName) by DeviceName | order by UniqueUsers desc ``` ## 第 2.6 课 — 使结果更具可读性 ### 重命名列 ``` DeviceLogonEvents | project Time = Timestamp, User = AccountName, Device = DeviceName, Result = ActionType ``` ### 添加计算列 ``` DeviceLogonEvents | extend HourOfDay = hourofday(Timestamp) | extend DayOfWeek = dayofweek(Timestamp) ``` ### 使用条件逻辑 ``` DeviceLogonEvents | extend Status = case( ActionType == "LogonSuccess", "SUCCESS", ActionType == "LogonFailed", "FAILED", "UNKNOWN" ) ``` # 模块 3 — 深入探讨:DeviceLogonEvents
## 核心字段 | 字段类别 | 字段 | 含义 | |---|---|---| | 身份 | AccountName | 登录的用户 | | 身份 | AccountDomain | 域或机器上下文 | | 身份 | AccountSid | 唯一安全标识符 | | 操作 | ActionType | LogonSuccess 或 LogonFailed | | 操作 | FailureReason | 身份验证失败的原因 | | 操作 | LogonType | 身份验证是如何发生的 | | 设备 | DeviceName | 目标机器 | | 设备 | DeviceId | 唯一设备 ID | | 网络 | RemoteIP | 源 IP | | 网络 | RemoteIPType | Public 或 Private | | 网络 | RemotePort | 源端口 | | 网络 | Protocol | NTLM、Kerberos 等 | | 进程 | InitiatingProcessFileName | 触发登录的进程 | | 进程 | InitiatingProcessCommandLine | 完整命令行 | ## 重要的登录类型 | 登录类型 | 含义 | 威胁狩猎价值 | |---|---|---| | Interactive | 物理控制台登录 | 本地访问基线 | | Network | SMB / 网络资源访问 | 横向移动检测 | | RemoteInteractive | RDP 会话 | 远程访问和勒索软件操作者活动 | | Service | 服务账户活动 | 服务滥用或配置错误 | ## 失败原因 | 失败原因 | 解释 | |---|---| | InvalidUserNameOrPassword | 暴力破解或密码喷洒指标 | | AccountLocked | 攻击可能导致账户锁定 | | PasswordExpired | 薄弱的运维规范或账户问题 | | AccountDisabled | 对已禁用账户的探测 | | LogonTypeRestricted | 策略阻止了此登录类型 | ## 解析 AdditionalFields ``` DeviceLogonEvents | extend ParsedFields = parse_json(AdditionalFields) | extend Terminal = tostring(ParsedFields.Terminal) | extend PosixUserId = toint(ParsedFields.PosixUserId) | project Timestamp, DeviceName, AccountName, Terminal, PosixUserId ``` ### Linux 狩猎信号 | 字段 | 可疑含义 | |---|---| | Terminal = ssh | 外部 SSH 活动 | | PosixUserId = 0 | Root 级别活动 | | InitiatingAccountName != AccountName | 可能是 sudo 或权限提升 | # 模块 4 — 威胁狩猎模式
## 第 4.1 课 — 暴力破解检测 ### 基本失败登录搜寻 ``` DeviceLogonEvents | where Timestamp > ago(1h) | where ActionType == "LogonFailed" ``` ### 按源 IP 统计失败尝试 ``` DeviceLogonEvents | where Timestamp > ago(1h) | where ActionType == "LogonFailed" | summarize FailedAttempts = count() by RemoteIP | where FailedAttempts > 10 | order by FailedAttempts desc ``` ### 完整暴力破解上下文 ``` DeviceLogonEvents | where Timestamp > ago(1h) | where ActionType == "LogonFailed" | summarize FailedAttempts = count(), TargetAccounts = make_set(AccountName), TargetDevices = make_set(DeviceName), FirstAttempt = min(Timestamp), LastAttempt = max(Timestamp) by RemoteIP | where FailedAttempts > 10 | order by FailedAttempts desc ``` ## 第 4.2 课 — 密码喷洒检测 ``` DeviceLogonEvents | where Timestamp > ago(1h) | where ActionType == "LogonFailed" | summarize TargetedAccounts = dcount(AccountName), TotalAttempts = count(), AccountList = make_set(AccountName, 10) by RemoteIP | extend AttemptsPerAccount = todouble(TotalAttempts) / todouble(TargetedAccounts) | where TargetedAccounts > 5 and AttemptsPerAccount < 3 | order by TargetedAccounts desc ``` ### 分析师解释 | 攻击类型 | 模式 | |---|---| | 暴力破解 | 针对一个账户尝试多个密码 | | 密码喷洒 | 使用一个或几个密码尝试多个账户 | ## 第 4.3 课 — 成功的外部访问 ``` DeviceLogonEvents | where Timestamp > ago(24h) | where ActionType == "LogonSuccess" | where RemoteIPType == "Public" ``` ### 添加上下文 ``` DeviceLogonEvents | where Timestamp > ago(24h) | where ActionType == "LogonSuccess" | where RemoteIPType == "Public" | summarize LoginCount = count(), Devices = make_set(DeviceName), FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by RemoteIP, AccountName | order by LoginCount desc ``` ## 第 4.4 课 — 权限提升狩猎 ``` DeviceLogonEvents | where AccountName in~ ("root", "Administrator") or tostring(parse_json(AdditionalFields).PosixUserId) == "0" | where InitiatingProcessAccountName != AccountName | project Timestamp, DeviceName, AccountName, InitiatingProcessAccountName, InitiatingProcessFileName, AdditionalFields | order by Timestamp desc ``` ## 第 4.5 课 — 横向移动检测 ``` DeviceLogonEvents | where Timestamp > ago(24h) | where LogonType == "Network" | where RemoteIPType == "Private" | summarize DeviceCount = dcount(DeviceName), Devices = make_set(DeviceName) by AccountName, RemoteIP | where DeviceCount > 3 | order by DeviceCount desc ``` ## 第 4.6 课 — 威胁狩猎工作流 | 步骤 | 操作 | |---|---| | 1 | 形成可测试的假设 | | 2 | 确定相关的表和字段 | | 3 | 构建广泛查询 | | 4 | 根据时间、用户、设备和 IP 缩小范围 | | 5 | 透视到相关的表 | | 6 | 记录发现和建议 | # 模块 5 — 高级技术
## 联结表以获取上下文 ``` DeviceLogonEvents | where Timestamp > ago(24h) | where ActionType == "LogonSuccess" and RemoteIPType == "Public" | project LogonTime = Timestamp, DeviceName, AccountName, RemoteIP | join kind=inner ( DeviceProcessEvents | where Timestamp > ago(24h) | project ProcessTime = Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine ) on DeviceName, AccountName | where ProcessTime between (LogonTime .. LogonTime + 1h) | order by LogonTime asc ``` ## 使用 `let` 定义变量 ``` let timeRange = 24h; let failureThreshold = 10; let suspiciousIP = "163.223.99.217"; DeviceLogonEvents | where Timestamp > ago(timeRange) | where RemoteIP == suspiciousIP | where ActionType == "LogonFailed" | summarize FailedAttempts = count() | where FailedAttempts > failureThreshold ``` ## 时间序列分析 ``` DeviceLogonEvents | where Timestamp > ago(24h) | where ActionType == "LogonFailed" | summarize FailedLogins = count() by bin(Timestamp, 15m) | render timechart ``` # 模块 6 — 动手实验:威胁狩猎练习
## 场景 学生使用 KQL 查询对身份验证日志进行调查,重点关注潜在的系统入侵,主要针对 DeviceLogonEvents 表。 ### 学生正在搜寻的内容 - 暴力破解尝试 - 成功的未授权访问 - 权限提升活动 - 横向移动指标 ## 实验练习 1 — 初始侦察 ### 目标 了解环境和可用数据。 ### 任务 ``` DeviceLogonEvents | summarize Devices = make_set(DeviceName) ``` ``` DeviceLogonEvents | summarize Accounts = make_set(AccountName) ``` ``` DeviceLogonEvents | summarize FirstEvent = min(Timestamp), LastEvent = max(Timestamp) ``` ``` DeviceLogonEvents | summarize Count = count() by ActionType | order by Count desc ``` ## 实验练习 2 — 搜寻暴力破解 ``` DeviceLogonEvents | where Timestamp > ago(24h) | where ActionType == "LogonFailed" | summarize FailedAttempts = count(), TargetAccounts = make_set(AccountName), TargetDevices = make_set(DeviceName) by RemoteIP | where FailedAttempts > 20 | order by FailedAttempts desc ``` ### 关键问题 - 哪些 IP 地址正在发起攻击? - 哪些账户被作为目标? - 是否有尝试成功的? - 使用了哪种身份验证协议? ## 实验练习 3 — 搜寻未授权外部访问 ``` DeviceLogonEvents | where Timestamp > ago(24h) | where ActionType == "LogonSuccess" | where RemoteIPType == "Public" | project Timestamp, DeviceName, AccountName, RemoteIP, LogonType, Protocol | order by Timestamp desc ``` ## 实验练习 4 — 搜寻权限提升 ``` DeviceLogonEvents | where AccountName in~ ("root", "Administrator") or tostring(parse_json(AdditionalFields).PosixUserId) == "0" | project Timestamp, DeviceName, AccountName, InitiatingProcessAccountName, InitiatingProcessFileName, AdditionalFields | order by Timestamp desc ``` ## 实验练习 5 — 完整调查综合 ### 交付物 | 交付物 | 描述 | |---|---| | 事件摘要 | 发生了什么以及为什么重要 | | 时间线 | 从第一个事件到最后一个已知活动 | | IoCs | IP、账户、设备、协议 | | 影响评估 |影响的系统和用户 | | 补救措施 | 封禁、重置密码、MFA、监控 | # 模块 7 — 将技能迁移到其他平台
## KQL 到 Splunk SPL | KQL | Splunk SPL | |---|---| | `where` | `search` / `where` | | `project` | `fields` / `table` | | `summarize count() by X` | `stats count by X` | | `order by X desc` | `sort -X` | | `take 10` | `head 10` | | `ago(24h)` | `earliest=-24h` | ## KQL 到 Elastic / OpenSearch | KQL 概念 | Elastic / OpenSearch 对应项 | |---|---| | 过滤 | Lucene filter 或 DSL 查询 | | 汇总 | Aggregations | | 时间图表 | Date histogram | | 投影 | Source 字段选择 | # 快速参考附录 ## 基本 KQL 运算符 ``` | where // Filter rows | project // Select columns | extend = value // Add columns | summarize by // Aggregate | order by desc // Sort | take N // Limit rows | top N by // Sorted limit | join (table) on // Combine tables | count // Count rows ``` ## DeviceLogonEvents 关键字段 | 字段 | 含义 | |---|---| | Timestamp | 事件发生的时间 | | AccountName | 登录的用户 | | DeviceName | 目标设备 | | ActionType | 成功或失败 | | LogonType | 身份验证是如何发生的 | | RemoteIP | 源 IP | | RemoteIPType | Public 或 Private | | FailureReason | 身份验证失败的原因 | | Protocol | NTLM、Kerberos 等 | | InitiatingProcessFileName | 触发身份验证的进程 | # 常见威胁狩猎查询 ## 按外部 IP 统计失败登录 ``` DeviceLogonEvents | where ActionType == "LogonFailed" | summarize FailedCount = count() by RemoteIP | order by FailedCount desc ``` ## 成功的外部访问 ``` DeviceLogonEvents | where ActionType == "LogonSuccess" | where RemoteIPType == "Public" ``` ## Root / Administrator 活动 ``` DeviceLogonEvents | where AccountName in~ ("root", "Administrator") ``` ## 暴力破解检测 ``` DeviceLogonEvents | where ActionType == "LogonFailed" | summarize Attempts = count() by RemoteIP | where Attempts > 20 | order by Attempts desc ``` # 讲师说明 | 模块 | 建议时长 | |---|---:| | 模块 1–2:基础 | 2–3 小时 | | 模块 3:DeviceLogonEvents 深入探讨 | 2 小时 | | 模块 4:威胁狩猎模式 | 3–4 小时 | | 模块 5:高级技术 | 1–2 小时 | | 模块 6:动手实验 | 3–4 小时 | | 模块 7:迁移到其他 SIEM | 1 小时 | | 总计 | 15–18 小时 | ## 前提条件 - 对日志的基本了解 - 熟悉电子表格概念 - 对网络安全运营感兴趣 - 拥有示例日志数据或 Microsoft 安全实验室的访问权限 # 学生作品集证据 学生应提交: - 查询和结果的屏幕截图 - 暴力破解检测查询 - 密码喷洒检测查询 - 成功的外部访问查询 - 权限提升查询 - 书面事件摘要 - 事件时间线 - 失陷指标 - 建议的补救步骤 # CyberNova Academy 最终总结 KQL 不仅仅是一种查询语言。它是 SOC 分析师的超能力。 它帮助分析师从: ``` Alert responder → Investigator → Threat hunter → Detection engineer ``` 最优秀的 SOC 分析师不仅会对警报做出反应。他们还会向数据提出更好的问题。
# 保留的原始提供内容
点击展开原始提供的文本



KQL & THREAT HUNTING

MASTERY COURSE

From Zero to SOC Analyst

CyberNova Academy

Curriculum Guide

 
课程介绍

我们在学什么?

•	Kusto Query Language (KQL) - Microsoft 安全工具中使用的查询语言

•	如何阅读、理解和分析安全日志

•	使用真实企业数据进行威胁狩猎的方法论

•	重点:DeviceLogonEvents 表 - 身份验证和登录活动

我们为什么要学这个?

•	就业市场现实:在使用 Microsoft 技术栈的 SOC 分析师职位描述中,80%+ 都要求掌握 KQL

•	调查速度:手动日志审查 = 数小时;KQL 查询 = 数秒

•	主动防御:威胁狩猎能在警报触发之前发现攻击者

•	职业晋升:KQL 技能将 L1 分析师与 L2/L3 角色区分开来

•	现实需求:在你入职的第一周,你一定需要查询日志

这将如何帮助你?

•	更快、更准确地调查安全事件

•	从零开始构建检测规则和警报

•	通过包含 KQL 练习的技术面试

•	从警报响应者转型为主动威胁猎人

•	凭借实际的查询经验在简历中脱颖而出

这如何应用于其他平台?

•	Splunk:SPL (Search Processing Language) - 类似的过滤概念,不同的语法

•	Elastic/ELK:Lucene 查询和 KQL(不同的 KQL!)- 同样的逻辑适用

•	Chronicle/Google SecOps:YARA-L 和 UDM 搜索 - 同样的心智模型

•	AWS CloudWatch:Insights 查询 - 过滤概念是相通的

•	任何 SIEM:逻辑是通用的;语法只是词汇

核心真相:一旦你深入理解了一种查询语言,其他的就会变得更容易

 
模块 1:基础 - 理解日志

第 1.1 课:什么是日志?(全局概览)

要涵盖的核心概念:

•	日志 = 系统上发生的所有事情的数字凭证

•	每次点击、登录、文件访问、网络连接都会生成日志

•	类比:你 IT 环境的监控摄像头,不过是文本形式的

•	没有日志,你对发生的事情一无所知

日志回答的三个问题:

1.	发生了什么?

2.	什么时候发生的?

3.	是谁/什么导致它发生的?

现实世界背景:

•	“发生了数据泄露” - 没有日志,调查是不可能的

•	没有日志的事件响应 = 凭空猜测

•	合规要求(HIPAA、PCI、SOC2)强制要求保留日志

第 1.2 课:日志是如何存储的 - Log Analytics Workspace

要涵盖的核心概念:

•	Log Analytics Workspace = Microsoft 基于云的日志存储

•	把它想象成云端的一个巨大的 Excel 文件

•	数据流入来源:Defender for Endpoint、Sentinel、Azure 资源、自定义来源

•	组织成表(就像 Excel 的标签页/工作表)

Excel 电子表格类比:

•	工作簿 = Log Analytics Workspace

•	工作表/标签页 = 表(DeviceLogonEvents、DeviceProcessEvents 等)

•	行 = 单个日志条目(事件)

•	列 = 字段/属性(Timestamp、DeviceName、AccountName 等)

需要了解的常见表:

•	DeviceLogonEvents - 登录/身份验证活动

•	DeviceProcessEvents - 进程执行

•	DeviceNetworkEvents - 网络连接

•	DeviceFileEvents - 文件操作

•	SecurityAlert - 触发的警报

•	SigninLogs - Azure AD 身份验证

要点:

•	表有 SCHEMAS(定义的列)

•	并非每一行都有所有列的数据(稀疏数据)

•	数据有保留期(30、90、180、365 天)

•	在生产环境中存在查询成本

第 1.3 课:什么是 KQL?(最简单的解释)

核心信息:

•	KQL = 一种过滤巨大电子表格的方法

•	你不是在编程;你是在向数据提问

•	从数百万行开始,准确过滤出你需要的

心智模型:

数百万条日志 → KQL 查询 → 少量相关结果

为什么不直接用 Excel?

•	规模:Excel 在大约 100 万行时会崩溃;Log Analytics 可以处理数十亿行

•	速度:查询在庞大的数据集中几秒钟即可运行完成

•	功能:内置安全函数、时间智能

•	协作:共享查询、构建仪表板、自动化警报

KQL 理念:

•	基于管道:数据通过运算符从左向右流动

•	可读性:查询读起来几乎像英语句子

•	迭代性:逐步构建查询,边构建边优化

 

在你继续之前

下一部分需要查询实际的日志。你有两个选择:

自己搭建 – 我会给你提供设置带有 Defender for Endpoint 的 Azure 环境的说明。完全可行,你只需处理来自你自己机器的小型数据集。

加入 CyberNova Academy– 1,000+ 名用户、数百台虚拟机、Tenable、实时威胁狩猎、完整课程库、就业证明,以及一个真正在乎的社区。我从没遇到过谁加入后说不值得的。

两种方式都行。选一个,我们继续。

 
模块 2:KQL 基础

第 2.1 课:你的第一个查询 - 基础知识

要教授的核心运算符:

从一个表开始:

DeviceLogonEvents

•	仅此一项就会返回所有行(不要在生产环境中这样做!)

•	总是从这里开始,然后进行过滤

take - 获取样本:

DeviceLogonEvents| take 10

•	返回前 N 行

•	使用它来探索数据结构

•	有助于了解存在哪些列

where - 过滤器:

DeviceLogonEvents| where ActionType == "LogonSuccess"

•	最重要的运算符

•	根据条件过滤行

•	想象:Excel 的筛选下拉菜单,但更强大

project - 选择列:

DeviceLogonEvents| project Timestamp, DeviceName, AccountName, ActionType

•	选择要显示的列

•	减少干扰,集中调查

•	就像在 Excel 中隐藏列一样

核心教学要点:

•	管道符 | 将数据从一个操作传递到下一个操作

•	顺序很重要:尽早过滤以提高性能

•	区分大小写:值中 "LogonSuccess" ≠ "logonsuccess"

•	双等号 == 用于精确匹配

第 2.2 课:专业级过滤

比较运算符:

•	== 精确匹配

•	!= 不等于

•	> < >= <= 用于数字和日期

•	contains 部分文本匹配(不区分大小写)

•	has 词界匹配(比 contains 更快)

•	startswith / endswith 用于模式匹配

•	in 用于多个值

使用 DeviceLogonEvents 的实际示例:

查找失败登录:

| where ActionType == "LogonFailed"

查找特定用户:

| where AccountName == "administrator"

查找网络登录:

| where LogonType == "Network"

查找外部 IP:

| where RemoteIPType == "Public"

组合条件 (AND):

| where ActionType == "LogonFailed" and RemoteIPType == "Public"

多值 (OR):

| where ActionType in ("LogonSuccess", "LogonFailed")

教学要点:

•	AND 缩小结果范围(更具限制性)

•	OR 扩大结果范围(限制较少)

•	圆括号用于分组逻辑:(A and B) or C

•	首先对索引列进行过滤以提高性能

第 2.3 课:基于时间的过滤

为什么时间很重要:

•	安全调查几乎总是受时间限制的

•	“昨天下午 2 点到 4 点之间发生了什么?”

•	减少数据量以加快查询速度

时间运算符:

相对时间(最常见):

DeviceLogonEvents

| where Timestamp > ago(24h)

| where Timestamp > ago(7d)

| where Timestamp > ago(1h)

时间范围:

| where Timestamp between (datetime(2026-01-13 06:00:00) .. datetime(2026-01-13 08:00:00))

特定日期:

| where Timestamp > datetime(2026-01-13)

时间单位:

•	m = 分钟

•	h = 小时

•	d = 天

专业提示:

•	始终在查询的早期按时间过滤(提高性能)

•	注意 UTC 与本地时间的区别(日志通常为 UTC)

•	使用 ago() 表示相对时间,datetime() 表示特定时间

第 2.4 课:排序和限制结果

使用 order by 排序:

| order by Timestamp desc

•	desc = 最新优先(在安全领域最常见)

•	asc = 最旧优先

多列排序:

| order by AccountName asc, Timestamp desc

使用 take 和 top 限制:

| take 100| top 10 by Timestamp desc

•	take = 任意样本

•	top = 排序限制(结合了 order by + take)

实用模式:

DeviceLogonEvents| where Timestamp > ago(24h)| where ActionType == "LogonFailed"| order by Timestamp desc| take 100

第 2.5 课:计数和聚合

为什么要聚合?

•	原始日志显示单个事件

•	聚合揭示了模式

•	“给我看计数,而不是细节”

count - 总行数:

DeviceLogonEvents| where Timestamp > ago(24h)| count

summarize -组和聚合:

DeviceLogonEvents| where Timestamp > ago(24h)| summarize count() by ActionType

常见聚合函数:

•	count() - 行数

•	dcount() - 去重计数

•	sum() - 数字字段的总和

•	avg() - 平均值

•	min() / max() - 极值

强大的模式:

按 IP 统计失败登录:

| summarize FailedCount = count() by RemoteIP| order by FailedCount desc

每台设备的唯一用户:

| summarize UniqueUsers = dcount(AccountName) by DeviceName

第 2.6 课:使结果具有可读性

重命名列:

| project TimeStamp = Timestamp, User = AccountName, Device = DeviceName

extend - 添加计算列:

| extend HourOfDay = hourofday(Timestamp)| extend DayOfWeek = dayofweek(Timestamp)

使用 case 的条件逻辑:

| extend Status = case(    ActionType == "LogonSuccess", "SUCCESS",    ActionType == "LogonFailed", "FAILED",    "UNKNOWN")

 
模块 3:深入探讨 - DeviceLogonEvents 表

第 3.1 课:理解 Schema

需要了解的核心字段:

身份字段:

•	AccountName - 登录的用户名

•	AccountDomain - 账户的域/机器

•	AccountSid - 安全标识符(唯一 ID)

操作字段:

•	ActionType - LogonSuccess 或 LogonFailed

•	FailureReason - 失败原因(InvalidUserNameOrPassword 等)

•	LogonType - 登录方式(Interactive、Network、RemoteInteractive 等)

设备字段:

•	DeviceName - 目标机器

•	DeviceId - 唯一设备标识符

网络字段:

•	RemoteIP - 源 IP 地址

•	RemoteIPType - Public 或 Private

•	RemotePort - 源端口

•	Protocol - 身份验证协议(NTLM、Kerberos 等)

进程字段:

•	InitiatingProcessFileName - 触发登录的进程

•	InitiatingProcessCommandLine - 完整命令行

•	InitiatingProcessAccountName - 运行进程的用户

重要区别:

•	AccountName = 谁正在登录

•	InitiatingProcessAccountName = 谁启动了登录过程

它们可能不同(权限提升、runas 等)

第 3.2 课:LogonType - 关键字段

什么是 LogonType?

•	身份验证是如何发生的

•	对于理解攻击媒介至关重要

•	不同的类型 = 不同的威胁含义

需要了解的 LogonTypes:

Interactive (类型 2):

•	物理键盘登录

•	坐在机器前的人

Network (类型 3):

•	通过网络访问

•	SMB 文件共享、Web 应用等

•	常用于横向移动

RemoteInteractive (类型 10):

•	远程桌面 (RDP)

•	攻击者的高价值目标

Service (类型 5):

•	服务账户启动

•	通常是自动化的/预期的

威胁狩猎相关性:

•	意外的 Network 登录 = 潜在的横向移动

•	来自异常 IP 的 RemoteInteractive = 可能的 RDP 攻击

•	多次失败的 Network 登录 = 暴力破解尝试

第 3.3 课:失败原因 - 哪里出了问题

常见 FailureReason 值:

•	InvalidUserNameOrPassword - 错误的凭据(暴力破解指标)

•	AccountLocked - 失败尝试过多

•	PasswordExpired - 凭据需要更新

•	AccountDisabled - 尝试访问已禁用的账户

•	LogonTypeRestricted - 策略阻止登录类型

威胁狩猎价值:

•	InvalidUserNameOrPassword 集群 = 密码喷洒/暴力破解

•	AccountDisabled 尝试 = 有人在探测已禁用的账户

•	AccountLocked = 攻击造成的账户成功锁定

第 3.4 课:协议 - 身份验证是如何发生的

关键协议:

NTLM:

•	传统身份验证

•	容易受到哈希传递攻击

•	在现代环境中应该较少见到

•	如果在期望 Kerberos 的地方看到了 NTLM,则是危险信号

Kerberos:

•	现代、更安全的身份验证

•	使用票据而不是密码

•	域身份验证的预期协议

第 3.5 课:AdditionalFields 列

这里包含了什么:

•	带有扩展信息的 JSON 数据块

•	特定于平台的详细信息

•	Linux:POSIX 用户 ID、组信息、终端信息

•	Windows:扩展的身份验证详细信息

如何解析:

| extend Terminal = tostring(parse_json(AdditionalFields).Terminal)| extend PosixUserId = toint(parse_json(AdditionalFields).PosixUserId)

特定于 Linux 的字段:

•	Terminal(ssh、cron、pts/0 等)

•	PosixUserId(0 = root!)

•	InitiatingAccountName(谁运行了 sudo 等)

威胁狩猎价值:

•	来自公共 IP 的 Terminal = "ssh" = 外部 SSH 访问

•	PosixUserId = 0 = root 活动(权限提升?)

•	InitiatingAccountName 不同于 AccountName = sudo/权限提升

 
模块 4:威胁狩猎模式

第 4.1 课:检测暴力破解攻击

模式:

•	多次失败的登录

•	相同的目标账户或设备

•	短时间窗口

•	通常来自相同的源 IP

检测查询逻辑:

步骤 1 - 查找失败登录:

| where ActionType == "LogonFailed"| where Timestamp > ago(1h)

步骤 2 - 按来源分组:

| summarize FailedAttempts = count() by RemoteIP| where FailedAttempts > 10

步骤 3 - 添加上下文:

| summarize     FailedAttempts = count(),    TargetAccounts = make_set(AccountName),    TargetDevices = make_set(DeviceName),    FirstAttempt = min(Timestamp),    LastAttempt = max(Timestamp)  by RemoteIP| where FailedAttempts > 10

来自实验室数据的真实示例:

•	IP 163.223.99.217 攻击 Windows 目标

•	针对 administrator 账户

•	在一段时间内进行多次尝试

•	NTLM 协议 - 经典的暴力破解特征

教学要点:

•	阈值调优(10?50?100?)

•	时间窗口考量

•	误报来源(用户忘记密码)

•	make_set() 用于查看被针对的账户

第 4.2 课:检测密码喷洒攻击

模式:

•	跨多个账户的失败登录

•	到处尝试相同的密码

•	通常来自单个 IP 或小范围 IP

•	每个账户的尝试次数少(逃避锁定)

与暴力破解的区别:

•	暴力破解:多个密码 → 一个账户

•	密码喷洒:一个密码 → 多个账户

检测查询逻辑:

| where ActionType == "LogonFailed"| where Timestamp > ago(1h)| summarize     TargetedAccounts = dcount(AccountName),    AttemptsPerAccount = count() / dcount(AccountName),    AccountList = make_set(AccountName, 10)  by RemoteIP| where TargetedAccounts > 5 and AttemptsPerAccount < 3

第 4.3 课:检测成功的外部访问

关注点:

•	来自公共 IP 的成功登录

•	可能是合法的远程工作,或者是初始访问

检测查询逻辑:

| where ActionType == "LogonSuccess"| where RemoteIPType == "Public"| where Timestamp > ago(24h)

添加上下文:

| summarize     LoginCount = count(),    Devices = make_set(DeviceName),    FirstSeen = min(Timestamp),    LastSeen = max(Timestamp)  by RemoteIP, AccountName| order by LoginCount desc

要注意什么:

•	以前未见过的新 IP

•	异常的地理位置

•	非工作时间访问

•	对敏感系统的访问

第 4.4 课:检测权限提升

Linux 重点 - sudo 检测:

模式:

•	以普通用户登录

•	由低权限用户启动的进程

•	账户变为 root(AccountName = root,PosixUserId = 0)

查询方法:

| where AccountName == "root"     or tostring(parse_json(AdditionalFields).PosixUserId) == "0"| where InitiatingProcessAccountName != "root"| where InitiatingProcessFileName == "sudo"

来自实验室数据的真实示例:

•	labuser → sudo → root on linux-scan-agent-test-josh

•	命令:sudo -i(交互式 root shell)

•	labuser 是否被授权执行此操作?上下文很重要!

第 4.5 课:检测横向移动

概念:

•	攻击者从受感染机器移动到其他机器

•	使用被盗的凭据

•	网络登录类型

•	内部 IP 到内部 IP

指标:

•	工作站之间的网络登录(异常)

•	管理员账户登录多台机器

•	内部的 NTLM 身份验证

•	不同机器上登录之间的时间很短

查询方法:

| where LogonType == "Network"| where RemoteIPType == "Private"| where Timestamp > ago(24h)| summarize     DeviceCount = dcount(DeviceName),    Devices = make_set(DeviceName)  by AccountName, RemoteIP| where DeviceCount > 3

教学要点:

•	正常:服务账户跨多台机器

•	异常:用户账户快速在多台服务器上登录

•	需要环境“正常”的基线

第 4.6 课:构建威胁狩猎工作流

过程:

1. 形成假设:

•	“我认为可能存在针对 RDP 的暴力破解攻击”

•	从一个具体的、可测试的想法开始

2. 确定相关数据:

•	哪些表?哪些字段?什么时间范围?

3. 构建初始查询:

•	从宽泛开始,迭代缩小

•	先测试较小的时间范围

4. 分析结果:

•	寻找模式、异常值

•	什么是正常与异常?

5. 透视和扩展:

•	发现了可疑 IP?在其他地方搜索它

•	使用发现来指导下一次查询

6. 记录发现:

•	发现了什么?有什么影响?需要采取什么行动?

 
模块 5:高级技术

第 5.1 课:联结表以获取上下文

为什么要联结?

•	DeviceLogonEvents 显示了谁登录了

•	DeviceProcessEvents 显示了他们之后运行了什么

•	相关性揭示了完整的攻击故事

基本联结:

DeviceLogonEvents| where ActionType == "LogonSuccess" and RemoteIPType == "Public"| project LogonTime = Timestamp, DeviceName, AccountName, RemoteIP| join kind=inner (    DeviceProcessEvents    | where Timestamp > ago(24h)    | project ProcessTime = Timestamp, DeviceName, AccountName, FileName) on DeviceName, AccountName| where ProcessTime between (LogonTime .. LogonTime + 1h)

教学要点:

•	联结键必须完全匹配

•	Kind 参数:inner、left、right、full

•	时间限制对性能至关重要

•	这正是调查变得强大的地方

第 5.2 课:使用 let 定义变量

为什么要使用变量?

•	可重用的值

•	更简洁的查询

•	易于调整阈值

语法:

let timeRange = 24h;let failureThreshold = 10;let suspiciousIP = "163.223.99.217";DeviceLogonEvents| where Timestamp > ago(timeRange)| where RemoteIP == suspiciousIP| where ActionType == "LogonFailed"| summarize count()

实际用途:

•	在顶部定义调查范围

•	更改一次,到处适用

•	共享带有可调参数的查询

第 5.3 课:时间序列分析

bin() - 时间分桶:

| summarize count() by bin(Timestamp, 1h)

可视化攻击模式:

DeviceLogonEvents| where ActionType == "LogonFailed"| where Timestamp > ago(24h)| summarize FailedLogins = count() by bin(Timestamp, 15m)| render timechart

这揭示了什么:

•	失败登录的激增

•	攻击定时模式

•	正常与异常量

•	工作时间与非工作时间

 
模块 6:动手实验 - 威胁狩猎练习

实验室概述

场景:

学生可以访问带有真实日志数据的 CyberNova Academy 环境。他们必须仅使用针对 DeviceLogonEvents 的 KQL 查询来调查潜在的入侵。

他们正在搜寻什么:

•	暴力破解尝试的证据

•	成功的未授权访问

•	权限提升活动

•	横向移动指标

实验练习 1:初始侦察

目标:

了解环境和可用数据

任务:

4.	查询以查看日志中的所有唯一设备

5.	查询以查看所有唯一账户

6.	查询以查看可用数据的时间范围

7.	查询以查看 ActionType 的分类

预期输出:

	范围内的设备列表

•	需要关注的账户列表

•	对数据量的了解

实验练习 2:搜寻暴力破解

目标:

识别活跃的暴力破解攻击

任务:

8.	查找过去 24 小时内的所有失败登录

9.	按源 IP 对失败进行分组

10.	识别具有超过 20 次失败的 IP

11.	记录被针对的账户和设备

12.	确定是否有任何在失败后成功的尝试

要回答的关键问题:

•	哪个(些)IP 正在攻击?

•	哪些账户被作为目标?

•	是否有攻击成功?

•	正在使用什么协议?

交付物:

•	攻击来源摘要

•	攻击活动时间线

•	成功/失败的评估

实验练习 3:搜寻未授权访问

目标:

找到可能表明系统被入侵的成功登录

任务:

13.	查找来自公共 IP 的所有成功登录

14.	识别哪些账户从外部登录

15.	确定此访问是否是预期的

16.	查找失败尝试后的成功登录(突破)

要回答的关键问题:

•	在此环境中,外部登录是否是预期的?

•	源 IP 在地理位置上是否合理?

•	是否有来自已知恶意 IP 的成功登录?

实验练习 4:搜寻权限提升

目标:

找到用户获得提升权限的证据

任务:

17.	查找所有导致 root/administrator 访问的登录

18.	识别启动用户(谁运行了 sudo)

19.	确定权限提升是否经过授权

20.	寻找不寻常的权限提升模式

关键问题:

•	谁正在提升到 root?

•	这是预期的管理员活动吗?

•	是否有来自受损账户的提升?

实验练习 5:完整调查综合

目标:

将所有发现结合成事件叙述

任务:

21.	建立从第一个攻击迹象到现在的时间线

22.	映射攻击者的进展(如果成功)

23.	识别所有受影响的系统和账户

24.	记录 IoC(IP、账户等)

25.	建议响应行动

交付物:

•	书面事件摘要

•	事件时间线

•	失陷指标

•	建议的补救措施

 
模块 7:将技能迁移到其他平台

第 7.1 课:KQL 概念 → Splunk SPL

概念映射:

KQL	Splunk SPL

| where	| search 或 | where

| project	| fields 或 | table

| summarize count() by X	| stats count by X

| order by X desc	| sort -X

| take 10	| head 10

ago(24h)	earliest=-24h

主要区别:

•	Splunk 使用 index= 来指定数据源(而在 KQL 中是表名)

•	Splunk 时间语法:earliest=-24h@h latest=now

•	Splunk 中的字段提取更偏手动

核心逻辑是一致的:

•	过滤数据 → 选择列 → 分组计数 → 排序结果

第 7.2 课:KQL 概念 → Elastic/OpenSearch

相似理念:

•	Lucene 查询语法用于过滤

•	聚合用于分组

•	Kibana 用于可视化

概念映射:

•	KQL where → Lucene filters 或 DSL 查询

•	KQL summarize → Aggregations (terms, date_histogram)

•	KQL project → _source 过滤

示例转换:

KQL: DeviceLogonEvents | where ActionType == "LogonFailed"

Elastic: 搜索栏中的 action_type: "LogonFailed"

第 7.3 课:通用的威胁狩猎技能

随处可迁移的技能:

26.	过滤思维 - 将庞大数据缩小到相关子集

27.	基于时间的分析 - 事情何时发生?

28.	聚合思维 - 通过分组显现模式

29.	关联技能 - 联结数据源以获取上下文

30.	基线意识 - 了解正常以发现异常

这些是与 SIEM 无关的:

•	理解身份验证日志

•	识别暴力破解模式

•	发现横向移动

•	检测权限提升

平台只是工具:

•	锤子与螺丝刀 - 都能建造东西

•	KQL 与 SPL - 都能狩猎威胁

•	掌握概念,适应语法

 
课程总结

核心要点

技术技能:

•	从基础到高级的 KQL 查询构建

•	DeviceLogonEvents 表精通

•	基于时间的过滤和聚合

•	联结表进行关联

•	构建可重用查询

威胁狩猎技能:

•	暴力破解检测

•	密码喷洒识别

•	权限提升狩猎

•	横向移动检测

•	调查工作流方法论

职业价值:

•	具备面试能力的 KQL 技能

•	使用真实数据的动手经验

•	适用于任何 SIEM 的可迁移概念

•	检测工程的基础

 
附录:快速参考

基本 KQL 运算符备忘单

| where <condition>           // 过滤行| project <columns>           // 选择列| extend <new_column> = value // 添加列| summarize <agg> by <group>  // 聚合| order by <column> desc/asc  // 排序| take N                      // 限制行| top N by <column>           // 排序限制| join (table) on <key>       // 联结表| count                       // 计算所有行

DeviceLogonEvents 关键字段

Timestamp          // 何时AccountName        // 谁登录了DeviceName         // 在哪里(目标)ActionType         // 成功或失败LogonType          // 如何(Network、Interactive 等)RemoteIP           // 源 IPRemoteIPType       // Public 或 PrivateFailureReason      // 为什么失败Protocol           // NTLM、Kerberos 等InitiatingProcess* // 什么进程触发了登录

常见威胁狩猎查询

按外部 IP 统计失败登录:

| where ActionType == "LogonFailed"| summarize count() by RemoteIP| order by count_ desc

成功的外部访问:

| where ActionType == "LogonSuccess"| where RemoteIPType == "Public"

Root/admin 活动:

| where AccountName in ("root", "Administrator")

暴力破解检测:

| where ActionType == "LogonFailed"| summarize Attempts = count() by RemoteIP| where Attempts > 20

 
讲师说明

进度建议

•	模块 1-2:2-3 小时(基础)

•	模块 3:2 小时(表格深入探讨)

•	模块 4:3-4 小时(威胁模式)

•	模块 5:1-2 小时(高级)

•	模块 6:3-4 小时(动手实验)

•	模块 7:1 小时(迁移)

总课程时长:约 15-18 小时

前提条件

•	对什么是日志有基本了解

•	熟悉电子表格概念(Excel)

•	对网络安全感兴趣

所需材料

•	访问 CyberNova Academy Log Analytics 环境

•	示例 DeviceLogonEvents 数据(已提供)

•	KQL 查询界面



标签:BurpSuite集成, KQL, Kusto查询语言, Log Analytics, Microsoft Defender XDR, Microsoft Sentinel, SOAR, SOC分析师, Threat Hunting, 培训课程, 安全教育, 安全运营, 扫描框架, 端点遥测, 红队行动, 网络安全, 防御矩阵, 隐私保护, 零基础入门