SreejithReji/kql-soc-queries

GitHub: SreejithReji/kql-soc-queries

面向微软安全生态的 KQL 查询参考库,为 SOC 分析师提供从基础语法到高级威胁狩猎与事件响应的全面实战查询模板。

Stars: 0 | Forks: 0

# KQL SOC 查询库 🔍 一份面向 SOC 分析师的全面 KQL (Kusto Query Language) 参考指南 —— 从入门查询到高级威胁狩猎。 适用于 **Microsoft Sentinel**、**Microsoft Defender XDR**、**Log Analytics** 和 **Microsoft 365 Defender**。 由 SOC 分析师构建,为 SOC 分析师服务。 ## 什么是 KQL? KQL 是一种用于整个 Microsoft 安全技术栈的查询语言。如果你的 SOC 团队运行 Sentinel 或 Defender,你每天都要编写 KQL —— 用于警报分类、威胁狩猎、事件调查和构建检测规则。 ## 仓库结构 ``` kql-soc-queries/ │ ├── 01_foundations/ │ ├── 01_basic_syntax.kql │ ├── 02_filtering_where.kql │ ├── 03_selecting_fields.kql │ ├── 04_sorting_limiting.kql │ └── 05_time_ranges.kql │ ├── 02_authentication/ │ ├── 01_failed_logons.kql │ ├── 02_brute_force_detection.kql │ ├── 03_successful_after_failures.kql │ ├── 04_account_lockouts.kql │ └── 05_impossible_travel.kql │ ├── 03_network/ │ ├── 01_suspicious_ports.kql │ ├── 02_c2_beaconing.kql │ ├── 03_dns_tunnelling.kql │ ├── 04_large_data_transfers.kql │ └── 05_port_scanning.kql │ ├── 04_endpoint/ │ ├── 01_suspicious_processes.kql │ ├── 02_powershell_execution.kql │ ├── 03_persistence_mechanisms.kql │ ├── 04_lateral_movement.kql │ └── 05_credential_dumping.kql │ ├── 05_threat_hunting/ │ ├── 01_lolbins_detection.kql │ ├── 02_ransomware_indicators.kql │ ├── 03_data_exfiltration.kql │ ├── 04_cobalt_strike_indicators.kql │ └── 05_mitre_attack_mapping.kql │ ├── 06_incident_response/ │ ├── 01_user_activity_timeline.kql │ ├── 02_ip_investigation.kql │ ├── 03_host_investigation.kql │ ├── 04_alert_summary.kql │ └── 05_ioc_search.kql │ └── 07_dashboards/ ├── 01_soc_daily_overview.kql ├── 02_top_alerts_by_severity.kql └── 03_shift_handover_summary.kql ``` ## 快速参考 — KQL 语法速查表 ### 基本结构 ``` TableName | where Condition | project Field1, Field2, Field3 | sort by Field desc | take 100 ``` ### 常用操作符 | 操作符 | 作用 | 示例 | |---|---|---| | `where` | 过滤行 | `where EventID == 4625` | | `project` | 选择列 | `project TimeGenerated, Account` | | `extend` | 添加新列 | `extend Hour = hourofday(TimeGenerated)` | | `summarize` | 聚合 | `summarize count() by Account` | | `sort by` | 对结果排序 | `sort by TimeGenerated desc` | | `take` / `limit` | 限制行数 | `take 100` | | `distinct` | 唯一值 | `distinct SrcIpAddr` | | `join` | 连接表 | `join kind=inner OtherTable on AccountName` | | `union` | 合并表 | `union Table1, Table2` | | `render` | 可视化 | `render timechart` | ### 时间过滤 ``` // Last 24 hours | where TimeGenerated > ago(24h) // Last 7 days | where TimeGenerated > ago(7d) // Specific range | where TimeGenerated between (datetime(2024-01-15) .. datetime(2024-01-16)) ``` ### 字符串操作符 ``` | where AccountName contains "admin" | where AccountName startswith "svc_" | where AccountName endswith "_test" | where AccountName matches regex @"^[a-z]{3}\d{4}$" | where CommandLine has_any ("mimikatz", "invoke-mimikatz", "sekurlsa") ``` ## 最常用的表 | 表名 | 包含内容 | SIEM | |---|---|---| | `SecurityEvent` | Windows 安全事件日志 | Sentinel | | `SigninLogs` | Azure AD 登录日志 | Sentinel | | `AuditLogs` | Azure AD 审计事件 | Sentinel | | `SecurityAlert` | 所有安全警报 | Sentinel | | `SecurityIncident` | 事件 | Sentinel | | `CommonSecurityLog` | CEF 格式日志(防火墙、IDS) | Sentinel | | `DnsEvents` | DNS 查询 | Sentinel | | `NetworkCommunicationEvents` | 网络连接 | Defender XDR | | `DeviceProcessEvents` | 进程执行 | Defender XDR | | `DeviceLogonEvents` | 设备登录事件 | Defender XDR | | `DeviceNetworkEvents` | 设备上的网络事件 | Defender XDR | | `EmailEvents` | 电子邮件日志 | Defender XDR | | `IdentityLogonEvents` | 身份登录事件 | Defender XDR | ## 查询 ### 01 — 基础 #### 基本语法 ``` // Your first KQL query — get the last 10 security events SecurityEvent | take 10 // Count all events in the last 24 hours SecurityEvent | where TimeGenerated > ago(24h) | count // See all unique Event IDs SecurityEvent | where TimeGenerated > ago(24h) | distinct EventID | sort by EventID asc ``` #### 使用 where 进行过滤 ``` // Filter by a single value SecurityEvent | where EventID == 4625 // Filter by multiple values SecurityEvent | where EventID in (4624, 4625, 4648, 4672, 4740) // Filter by text SecurityEvent | where AccountName contains "admin" // Combine conditions with and / or SecurityEvent | where EventID == 4625 and AccountName contains "admin" and TimeGenerated > ago(24h) ``` #### 使用 project 选择字段 ``` // Only show the columns you care about SecurityEvent | where EventID == 4625 | project TimeGenerated, Account, IpAddress, WorkstationName, LogonTypeName | sort by TimeGenerated desc ``` #### 汇总与聚合 ``` // Count events grouped by EventID SecurityEvent | where TimeGenerated > ago(24h) | summarize EventCount = count() by EventID | sort by EventCount desc // Count failed logons per account SecurityEvent | where EventID == 4625 | where TimeGenerated > ago(24h) | summarize FailedAttempts = count() by Account | sort by FailedAttempts desc ``` ### 02 — 身份验证查询 #### 失败登录检测(Event 4625) ``` // All failed logons in last 24 hours SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4625 | project TimeGenerated, Account, IpAddress, WorkstationName, LogonTypeName, SubStatus | sort by TimeGenerated desc ``` #### 暴力破解检测 — 基于阈值 ``` // Accounts with more than 10 failed logons in 1 hour — brute force indicator SecurityEvent | where TimeGenerated > ago(1h) | where EventID == 4625 | summarize FailedAttempts = count() by Account, IpAddress | where FailedAttempts > 10 | sort by FailedAttempts desc | extend Severity = case( FailedAttempts > 50, "Critical", FailedAttempts > 20, "High", FailedAttempts > 10, "Medium", "Low") ``` #### 多次失败后成功登录 — 可能存在违规 ``` // Find accounts that failed many times then succeeded — classic brute force success let FailedLogons = SecurityEvent | where TimeGenerated > ago(1h) | where EventID == 4625 | summarize FailCount = count() by Account, IpAddress | where FailCount > 5; let SuccessLogons = SecurityEvent | where TimeGenerated > ago(1h) | where EventID == 4624 | project Account, IpAddress, SuccessTime = TimeGenerated; SuccessLogons | join kind=inner FailedLogons on Account | project Account, IpAddress, SuccessTime, FailCount | sort by FailCount desc ``` #### 账户锁定(Event 4740) ``` // All account lockouts — who got locked out and from where SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4740 | project TimeGenerated, TargetAccount, Computer, SubjectUserName | sort by TimeGenerated desc ``` #### 不可能旅行检测 — Azure AD ``` // Same user signing in from two different countries in under 1 hour SigninLogs | where TimeGenerated > ago(24h) | where ResultType == 0 | project TimeGenerated, UserPrincipalName, Location, IPAddress, AppDisplayName | sort by UserPrincipalName, TimeGenerated asc | extend PrevLocation = prev(Location, 1), PrevTime = prev(TimeGenerated, 1), PrevUser = prev(UserPrincipalName, 1) | where UserPrincipalName == PrevUser and Location != PrevLocation and datetime_diff('minute', TimeGenerated, PrevTime) < 60 | project TimeGenerated, UserPrincipalName, Location, PrevLocation, IPAddress, AppDisplayName ``` #### 工作时间外的特权账户登录 ``` // Admin accounts logging in outside 07:00–19:00 SecurityEvent | where TimeGenerated > ago(7d) | where EventID == 4624 | where AccountType == "User" | extend Hour = hourofday(TimeGenerated) | where Hour !between (7 .. 19) | where Account contains_any ("admin", "administrator", "svc_", "root") | project TimeGenerated, Account, IpAddress, WorkstationName, Hour | sort by TimeGenerated desc ``` ### 03 — 网络查询 #### 连接到可疑端口 ``` // Traffic to commonly abused ports let SuspiciousPorts = dynamic([22, 23, 445, 3389, 4444, 8080, 9001, 1337, 31337]); CommonSecurityLog | where TimeGenerated > ago(24h) | where DestinationPort in (SuspiciousPorts) | where DeviceAction == "deny" | project TimeGenerated, SourceIP, DestinationIP, DestinationPort, Protocol, DeviceAction | sort by TimeGenerated desc ``` #### C2 信标检测 — 固定间隔连接 ``` // Find hosts making connections at suspiciously regular intervals — C2 beacon pattern NetworkCommunicationEvents | where TimeGenerated > ago(24h) | summarize ConnectionCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by DeviceName, RemoteIP, RemotePort | extend Duration = datetime_diff('minute', LastSeen, FirstSeen) | extend BeaconRate = ConnectionCount / (Duration + 1) | where ConnectionCount > 10 and BeaconRate > 1 | sort by BeaconRate desc ``` #### DNS 隧道检测 ``` // Long subdomain queries — classic DNS tunnelling indicator DnsEvents | where TimeGenerated > ago(24h) | extend SubdomainLength = strlen(Name) | where SubdomainLength > 50 | summarize QueryCount = count(), UniqueDomains = dcount(Name) by Computer, ClientIP | where QueryCount > 5 | sort by QueryCount desc ``` #### 可疑的出站数据传输 ``` // Large outbound transfers to external IPs — possible exfiltration CommonSecurityLog | where TimeGenerated > ago(24h) | where SentBytes > 10000000 | where not(DestinationIP matches regex @"^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)") | project TimeGenerated, SourceIP, DestinationIP, SentBytes, ReceivedBytes, Protocol | sort by SentBytes desc ``` #### 端口扫描检测 ``` // Single IP connecting to many different ports — port scan indicator NetworkCommunicationEvents | where TimeGenerated > ago(1h) | summarize UniquePortsScanned = dcount(RemotePort), PortList = make_set(RemotePort) by DeviceName, RemoteIP | where UniquePortsScanned > 20 | sort by UniquePortsScanned desc ``` ### 04 — 终端查询 #### 可疑进程执行 ``` // Processes commonly used by attackers — LOLBins and hacking tools let SuspiciousProcesses = dynamic([ "mimikatz.exe", "procdump.exe", "psexec.exe", "wce.exe", "fgdump.exe", "pwdump.exe", "gsecdump.exe", "meterpreter", "cobaltrike", "cobaltstrike", "empire.exe", "covenant" ]); DeviceProcessEvents | where TimeGenerated > ago(24h) | where FileName has_any (SuspiciousProcesses) or ProcessCommandLine has_any (SuspiciousProcesses) | project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName | sort by TimeGenerated desc ``` #### 可疑的 PowerShell 执行 ``` // PowerShell with encoded commands or download cradles — classic attacker technique DeviceProcessEvents | where TimeGenerated > ago(24h) | where FileName =~ "powershell.exe" or FileName =~ "pwsh.exe" | where ProcessCommandLine has_any ( "-enc", "-encodedcommand", "-nop", "-noprofile", "invoke-expression", "iex", "downloadstring", "invoke-webrequest", "wget", "curl", "bypass", "hidden", "windowstyle hidden" ) | project TimeGenerated, DeviceName, AccountName, ProcessCommandLine | sort by TimeGenerated desc ``` #### 持久化机制 ``` // New scheduled tasks created — common attacker persistence technique SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4698 | project TimeGenerated, Computer, Account, TaskName, TaskContent | sort by TimeGenerated desc ``` ``` // New services installed — another common persistence method SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 7045 | project TimeGenerated, Computer, Account, ServiceName, ServiceFileName, ServiceType | sort by TimeGenerated desc ``` #### 横向移动 — 传递哈希和远程执行 ``` // Remote logons using network credentials — lateral movement pattern SecurityEvent | where TimeGenerated > ago(24h) | where EventID == 4624 | where LogonType == 3 | where AccountType == "User" | where not(WorkstationName == Computer) | summarize RemoteHosts = dcount(Computer), HostList = make_set(Computer) by Account, IpAddress | where RemoteHosts > 3 | sort by RemoteHosts desc ``` #### 凭据转储指标 ``` // LSASS memory access — classic credential dumping technique (Mimikatz etc) DeviceProcessEvents | where TimeGenerated > ago(24h) | where InitiatingProcessFileName !in~ ("MsMpEng.exe", "svchost.exe", "lsass.exe") | where ProcessCommandLine has "lsass" or FileName =~ "lsass.exe" | project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName | sort by TimeGenerated desc ``` ### 05 — 威胁狩猎查询 #### 靠山吃山 (LOLBins) 检测 ``` // Built-in Windows tools used maliciously by attackers let LOLBins = dynamic([ "certutil.exe","bitsadmin.exe","regsvr32.exe","mshta.exe", "wscript.exe","cscript.exe","rundll32.exe","msiexec.exe", "installutil.exe","regasm.exe","regsvcs.exe","msconfig.exe", "at.exe","schtasks.exe","wmic.exe","net.exe","netsh.exe" ]); DeviceProcessEvents | where TimeGenerated > ago(24h) | where FileName has_any (LOLBins) | where InitiatingProcessFileName !in~ ("explorer.exe","services.exe","svchost.exe") | project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName | sort by TimeGenerated desc ``` #### 勒索软件指标 ``` // Mass file modification or deletion — ransomware behaviour DeviceFileEvents | where TimeGenerated > ago(1h) | where ActionType in ("FileModified","FileDeleted","FileRenamed") | summarize FileChanges = count(), UniqueExtensions = dcount(FileExtension) by DeviceName, InitiatingProcessFileName, bin(TimeGenerated, 5m) | where FileChanges > 100 | sort by FileChanges desc ``` #### Cobalt Strike 信标指标 ``` // Network connections on common Cobalt Strike ports with beacon-like intervals NetworkCommunicationEvents | where TimeGenerated > ago(24h) | where RemotePort in (80, 443, 8080, 8443) | summarize ConnectionCount = count(), BytesSent = sum(SentBytes), BytesReceived = sum(ReceivedBytes) by DeviceName, RemoteIP, RemotePort | where ConnectionCount > 20 and BytesSent between (1000 .. 50000) | sort by ConnectionCount desc ``` #### 数据泄露狩猎 ``` // Unusual volume of data leaving a specific host DeviceNetworkEvents | where TimeGenerated > ago(24h) | where RemoteIPType == "Public" | summarize TotalBytesSent = sum(SentBytes), UniqueDestinations = dcount(RemoteIP) by DeviceName, bin(TimeGenerated, 1h) | where TotalBytesSent > 100000000 | sort by TotalBytesSent desc | extend TotalMB = round(TotalBytesSent / 1048576, 2) ``` #### MITRE ATT&CK — T1059 命令和脚本解释器 ``` // All scripting interpreter activity mapped to MITRE T1059 let ScriptingInterpreters = dynamic([ "powershell.exe","cmd.exe","wscript.exe","cscript.exe", "mshta.exe","bash.exe","python.exe","python3.exe","perl.exe" ]); DeviceProcessEvents | where TimeGenerated > ago(24h) | where FileName has_any (ScriptingInterpreters) | extend MITRE_Technique = "T1059 - Command and Scripting Interpreter" | extend MITRE_Tactic = "Execution" | project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, MITRE_Technique, MITRE_Tactic | sort by TimeGenerated desc ``` ### 06 — 事件响应查询 #### 完整的用户活动时间线 ``` // Complete timeline of everything a user did — essential for IR let TargetUser = "administrator"; // change this let StartTime = ago(24h); let EndTime = now(); union (SecurityEvent | where TimeGenerated between (StartTime .. EndTime) | where Account contains TargetUser | project TimeGenerated, Category="Auth Event", Details=strcat("EventID:", tostring(EventID), " | ", Activity), Computer, IpAddress), (SigninLogs | where TimeGenerated between (StartTime .. EndTime) | where UserPrincipalName contains TargetUser | project TimeGenerated, Category="Azure AD Signin", Details=strcat("App:", AppDisplayName, " | Status:", ResultDescription), Computer=DeviceDetail, IpAddress=IPAddress), (DeviceProcessEvents | where TimeGenerated between (StartTime .. EndTime) | where AccountName contains TargetUser | project TimeGenerated, Category="Process", Details=ProcessCommandLine, Computer=DeviceName, IpAddress="") | sort by TimeGenerated asc ``` #### IP 地址调查 ``` // Everything associated with a specific IP — for alert triage let TargetIP = "185.220.101.45"; // change this union (SecurityEvent | where IpAddress == TargetIP | where TimeGenerated > ago(24h) | project TimeGenerated, Source="SecurityEvent", Details=strcat("EventID:", tostring(EventID), " Account:", Account)), (CommonSecurityLog | where SourceIP == TargetIP | where TimeGenerated > ago(24h) | project TimeGenerated, Source="Firewall", Details=strcat("Action:", DeviceAction, " Port:", tostring(DestinationPort))), (DnsEvents | where ClientIP == TargetIP | where TimeGenerated > ago(24h) | project TimeGenerated, Source="DNS", Details=strcat("Query:", Name)) | sort by TimeGenerated desc ``` #### 主机调查 ``` // Full picture of a specific host — for incident scoping let TargetHost = "DESKTOP-HR-042"; // change this union (DeviceProcessEvents | where DeviceName == TargetHost | where TimeGenerated > ago(24h) | project TimeGenerated, Category="Process", Details=ProcessCommandLine), (DeviceNetworkEvents | where DeviceName == TargetHost | where TimeGenerated > ago(24h) | project TimeGenerated, Category="Network", Details=strcat(RemoteIP, ":", tostring(RemotePort))), (DeviceLogonEvents | where DeviceName == TargetHost | where TimeGenerated > ago(24h) | project TimeGenerated, Category="Logon", Details=strcat(AccountName, " - ", ActionType)) | sort by TimeGenerated desc ``` #### 跨所有表的 IOC 搜索 ``` // Search for a hash, IP, or domain across all relevant tables at once let IOC = "d41d8cd98f00b204e9800998ecf8427e"; // replace with your IOC union (DeviceFileEvents | where SHA256 == IOC or MD5 == IOC | project TimeGenerated, Source="FileEvent", DeviceName, Details=FileName), (DeviceProcessEvents | where SHA256 == IOC or MD5 == IOC | project TimeGenerated, Source="ProcessEvent", DeviceName, Details=ProcessCommandLine), (CommonSecurityLog | where SourceIP == IOC or DestinationIP == IOC | project TimeGenerated, Source="Firewall", DeviceName=DeviceName, Details=strcat(SourceIP,"->",DestinationIP)) | sort by TimeGenerated desc ``` ### 07 — 仪表板查询 #### SOC 每日概览 ``` // High level summary for start of shift SecurityEvent | where TimeGenerated > ago(24h) | where EventID in (4624, 4625, 4740, 4720, 4728, 7045, 4698) | summarize Count = count() by EventID | extend EventDescription = case( EventID == 4624, "Successful Logons", EventID == 4625, "Failed Logons", EventID == 4740, "Account Lockouts", EventID == 4720, "Accounts Created", EventID == 4728, "Added to Admin Group", EventID == 7045, "Services Installed", EventID == 4698, "Scheduled Tasks Created", "Other") | project EventDescription, EventID, Count | sort by Count desc ``` #### 按严重程度排列的最高警报 — 轮班概览 ``` // Alert count by severity for current shift SecurityAlert | where TimeGenerated > ago(8h) | summarize AlertCount = count() by AlertSeverity, AlertName | sort by case( AlertSeverity == "High", 1, AlertSeverity == "Medium", 2, AlertSeverity == "Low", 3, 4) asc, AlertCount desc ``` #### 轮班交接摘要 ``` // Everything that happened in the last 8 hours — for handover report let ShiftStart = ago(8h); let FailedLogons = toscalar(SecurityEvent | where TimeGenerated > ShiftStart | where EventID == 4625 | count); let Lockouts = toscalar(SecurityEvent | where TimeGenerated > ShiftStart | where EventID == 4740 | count); let NewAccounts = toscalar(SecurityEvent | where TimeGenerated > ShiftStart | where EventID == 4720 | count); let HighAlerts = toscalar(SecurityAlert | where TimeGenerated > ShiftStart | where AlertSeverity == "High" | count); print ShiftPeriod = strcat(format_datetime(ShiftStart, 'HH:mm'), " - ", format_datetime(now(), 'HH:mm')), FailedLogons = FailedLogons, AccountLockouts = Lockouts, NewAccountsCreated = NewAccounts, HighSeverityAlerts = HighAlerts ``` ## 关键事件 ID 参考 | EventID | 描述 | 重要性说明 | |---|---|---| | 4624 | 成功登录 | 基准 — 查找异常时间或来源 | | 4625 | 登录失败 | 暴力破解指标 | | 4634 | 注销 | 会话持续时间分析 | | 4648 | 使用显式凭据登录 | 横向移动指标 | | 4672 | 分配特殊权限 | 权限提升 | | 4688 | 创建进程 | 恶意软件执行 | | 4698 | 创建计划任务 | 持久化机制 | | 4720 | 创建用户账户 | 攻击者后门 | | 4728 | 添加到安全组 | 权限提升 | | 4740 | 账户被锁定 | 超出暴力破解阈值 | | 7045 | 安装服务 | 恶意软件持久化 | | 4776 | 凭据验证 | 传递哈希指标 | | 4771 | Kerberos 预身份验证失败 | Kerberoasting 指标 | ## 学习资源 - 📖 [Microsoft KQL 官方文档](https://docs.microsoft.com/en-us/azure/data-explorer/kusto/query/) - 🎓 [Microsoft Learn — 适用于 Sentinel 的 KQL](https://learn.microsoft.com/en-us/training/paths/sc-200-utilize-kql-for-azure-sentinel/) - 🧪 [KQL 练习场](https://dataexplorer.azure.com/clusters/help/databases/Samples) - 🎯 [TryHackMe — Microsoft Sentinel 房间](https://tryhackme.com) - 📚 [MITRE ATT&CK 框架](https://attack.mitre.org) ## 关于 作为 SOC 分析师学习作品集的一部分构建。 **作者:** Sreejith Reji | 网络安全理学硕士 | CEH | Security+ 属于 [cybersecurity-portfolio](https://github.com/SreejithReji/cybersecurity-portfolio) 合集的一部分。
标签:DNS 反向解析, IP 地址批量处理, KQL查询, Microsoft Defender, 安全运营, 库, 应急响应, 扫描框架, 红队行动