news 2026/9/12 14:44:35

在 Graph 日志中检测 Entra 攻击工具:基于 Sentinel 的 ROADtools / AADInternals / AzureHound 猎捕实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 Graph 日志中检测 Entra 攻击工具:基于 Sentinel 的 ROADtools / AADInternals / AzureHound 猎捕实战

在 Graph 日志中检测 Entra 攻击工具:基于 Sentinel 的 ROADtools / AADInternals / AzureHound 猎捕实战

【免费下载链接】Anthropic-Cybersecurity-Skills817 structured cybersecurity skills for AI agents · Mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF & MITRE F3 (Fight Fraud) · agentskills.io standard · Works with Claude Code, GitHub Copilot, Codex CLI, Cursor, Gemini CLI & 20+ platforms · 29 security domains · Apache 2.0项目地址: https://gitcode.com/GitHub_Trending/an/Anthropic-Cybersecurity-Skills

这篇技术指南聚焦于本项目 detecting-entra-offensive-tools-in-graph-logs 技能所覆盖的核心议题:利用 Microsoft Sentinel / Log Analytics 中的AADGraphActivityLogsMicrosoftGraphActivityLogs两张目录 API 活动表,通过 KQL 对 ROADtools(roadrecon)、AADInternals、AzureHound 等进攻性 Entra ID 枚举工具进行指纹识别与行为猎捕。读完本文,你将掌握三类检测手段——User-Agent 字符串指纹、可抵御 UA 伪造的端点扫描(endpoint-sweep)行为指纹、以及高量枚举离群点分析,并能够把可疑 Graph 调用关联回原始登录会话,最终将高保真查询固化为 Sentinel 计划性分析规则。

背景:AAD Graph 的十年盲区与两张新表

过去近十年,传统Azure AD Graph APIgraph.windows.net)一直是防御方的盲区:对它的请求不会产生一级活动日志。ROADtools(roadrecon)与 AADInternals 这类重度依赖 AAD Graph 的工具,可以在几乎不留痕的情况下枚举整个租户。这一局面随着微软正式发布AADGraphActivityLogs(本项目文档注明其 2026 年达到正式可用 GA 状态)而改变——它是对已可用的MicrosoftGraphActivityLogsgraph.microsoft.com)的补充。

两张表共同为 SOC 提供目录 API 流量的请求级可见性,包括:调用者身份、应用、源 IP、HTTP 方法、请求 URI,以及关键的User-Agent。这些检测既能暴露正在进行的入侵,也能反过来验证配套红队技能中的进攻技术在遥测上是可观测的——本项目仓库中同时收录了 attacking-entra-id-with-roadtools、auditing-entra-id-with-aadinternals 与 exploiting-active-directory-with-bloodhound 等进攻/审计技能,本技能正是它们的防御性对照面。

工具为什么会留下指纹

  • ROADtools构建于 Python 的aiohttp之上,未伪装时 User-Agent 形如Python/3.12 aiohttp/3.10.4
  • AADInternals常在 User-Agent 中遗留AADInternals或库字符串;
  • AzureHound使用 Go HTTP 客户端,agent 特征明显。

即使攻击者伪造了 User-Agent,工具仍会通过特征性的端点扫描模式暴露自己:roadrecon gather会在极短时间窗内拉取usersgroupsapplicationsserviceprincipalsdevicesdirectoryrolesroledefinitionsoauth2permissiongrants等大量目录资源——这种特征在头字段伪装下依然存活。

何时使用本技能

  • 构建或调优覆盖 Entra ID 的 Microsoft Sentinel / Log Analytics 检测;
  • 在疑似凭证失窃、设备代码钓鱼(device-code phishing)或 OAuth 同意滥用后进行威胁猎捕;
  • 紫队演练中验证 ROADtools / AADInternals / AzureHound 的活动是否可被检测;
  • 调查告警时需要把 Graph API 调用关联回某个登录/会话;
  • 启用 AADGraphActivityLogs 后,收口传统 Azure AD Graph 的可见性缺口。

前置条件

  • 一个正在摄入以下数据的 Microsoft Sentinel 工作区(或 Log Analytics):
    • MicrosoftGraphActivityLogs(Microsoft Entra ID →graph.microsoft.com的诊断设置);
    • AADGraphActivityLogs(Microsoft Entra ID → 传统 Azure AD Graph 的诊断设置);
  • 用于关联的SigninLogsAADNonInteractiveUserSignInLogs
  • 运行 KQL 所需的 Microsoft Sentinel Reader/Responder(或 Log Analytics Reader)RBAC 权限;
  • 熟悉 Kusto Query Language(KQL)。

启用诊断设置

通过 Azure 门户(Azure Portal → Microsoft Entra ID → Diagnostic settings → 将MicrosoftGraphActivityLogsAADGraphActivityLogs发送到工作区),或通过 CLI 启用:

az monitor diagnostic-settings create \ --name "entra-graph-logs" \ --resource "/providers/microsoft.aadiam/diagnosticSettings" \ --logs '[{"category":"MicrosoftGraphActivityLogs","enabled":true},{"category":"AADGraphActivityLogs","enabled":true}]' \ --workspace "<log-analytics-workspace-id>"

两张活动表的 Schema 与关联键

api-reference.md 对两张表的字段做了完整梳理,是编写查询时的速查手册:

覆盖范围关键字段
MicrosoftGraphActivityLogsgraph.microsoft.com请求RequestUriRequestMethodUserAgentUserIdAppIdIPAddress/CallerIpAddressResponseStatusCodeSignInActivityIdTimeGenerated
AADGraphActivityLogs传统graph.windows.net请求RequestUriRequestMethodUserAgentUserIdAppIdCallerIpAddressSignInActivityIdTimeGenerated

跨源关联键

字段关联目标注意事项
SignInActivityIdSigninLogs.UniqueTokenIdentifierAADGraphActivityLogs 中的值可能带==填充,关联前需要修剪
SessionIdSigninLogs / MicrosoftGraphActivityLogs / Unified Audit Log跨源会话关联
UserIdSigninLogs.UserId账户实体
AppIdSigninLogs.AppId调用应用

这里最容易踩的坑是SignInActivityId==填充——下文 Step 6 的 KQL 会演示如何用trim_end("=", ...)处理后再 JOIN。

标准与框架映射

本技能按 standards.md 映射到两套框架:

NIST CSF 2.0

ID名称在本技能中的体现
DE.CM-09对计算硬件、软件、运行时环境及其数据进行监控以发现潜在不利事件持续猎捕两张 Graph 活动表,监控目录 API 使用以发现攻击工具活动

MITRE ATT&CK

ID名称在本技能中的体现
T1078.004Valid Accounts: Cloud Accounts核心技术:攻击者使用有效云凭证/令牌查询 Graph API,本技能的猎捕即检测这类使用
T1087.004Account Discovery: Cloud Account被检测到的枚举扫描会枚举云账户
T1069.003Permission Groups Discovery: Cloud Groups扫描会枚举云组与角色
T1526Cloud Service Discovery广泛的目录枚举即云服务发现

其中核心检测目标对应T1078.004:攻击者使用合法(常为钓鱼所得或令牌被盗)云凭证,经由 Graph API 对租户进行枚举与操作。

猎捕工作流:7 个步骤

Step 1:确认两张表均已摄入

正式猎捕前,先确认数据存在,并检查你将作为枢纽使用的 schema 字段:

union withsource=Tbl MicrosoftGraphActivityLogs, AADGraphActivityLogs | where TimeGenerated > ago(1d) | summarize Records=count(), LastSeen=max(TimeGenerated) by Tbl

预期看到两张表都有记录。若AADGraphActivityLogs为空,说明诊断设置未生效或 AAD Graph 流量本就稀疏,需要回到前置条件检查配置。

Step 2:猎捕 User-Agent 指纹(ROADtools / aiohttp)

ROADtools 使用aiohttp;未伪装的运行会在 User-Agent 中同时出现pythonaiohttp

AADGraphActivityLogs | where TimeGenerated > ago(7d) | where RequestMethod == "GET" | where UserAgent contains "python" and UserAgent contains "aiohttp" | summarize RequestCount = count() by CallerIpAddress, AppId, UserAgent, UserId | sort by RequestCount desc

按调用方 IP、AppId、UserAgent、UserId 聚合请求数并降序排列,可快速定位哪个身份以该 UA 发起了多少请求。

Step 3:猎捕 AADInternals 与 AzureHound 的 Agent

AADInternals 会遗留工具/库字符串;AzureHound 的 Go HTTP 客户端与 BloodHound 工具链 agent 特征明显:

union MicrosoftGraphActivityLogs, AADGraphActivityLogs | where TimeGenerated > ago(7d) | where UserAgent has_any ("AADInternals", "aad-internals", "azurehound", "BloodHound", "python-requests", "Go-http-client") | project TimeGenerated, UserAgent, CallerIpAddress, AppId, UserId, RequestUri | sort by TimeGenerated desc

注意这里用了has_any(子串匹配,性能优于contains组合),并覆盖了两张表,避免漏掉走 AAD Graph 的 AADInternals 与走 MS Graph 的 AzureHound。

Step 4:行为猎捕——roadrecon 端点扫描(抗 UA 伪造)

即使伪造了 User-Agent,roadrecon gather也会在短时间内触达一组可识别的目录资源。按用户与 5 分钟时间窗分桶,当同一身份命中完整扫描集合时告警:

AADGraphActivityLogs | where TimeGenerated > ago(1d) | where RequestMethod == "GET" | extend TopLevelResource = tolower(tostring(split(split(RequestUri, "?")[0], "/")[3])) | summarize TopLevelResources = make_set(TopLevelResource), AppIds = make_set(AppId), CallerIPs = make_set(CallerIpAddress), UserAgents = make_set(UserAgent), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserId, bin(TimeGenerated, 5m) | where TopLevelResources has_all ("users", "tenantdetails", "groups", "applications", "serviceprincipals", "devices", "directoryroles", "roledefinitions", "contacts", "oauth2permissiongrants", "authorizationpolicy") | project StartTime, EndTime, UserId, AppIds, CallerIPs, UserAgents

这条查询的技术要点在于TopLevelResource的提取:split(RequestUri, "?")[0]去掉查询参数,再按/切分取索引[3]得到顶层资源名,从而把形形色色的目录 URI 归一到可比较的集合。has_all要求 5 分钟窗口内同一UserId完整命中 11 类目录资源的 GET 请求——这是roadrecon gather的标志性行为,正常人工操作几乎不可能在如此短窗口内覆盖全部资源。

Step 5:高量枚举离群点

捕获那些只是短时间内发起了远超人类正常频率目录读取的工具:

MicrosoftGraphActivityLogs | where TimeGenerated > ago(1d) | where RequestMethod == "GET" | where RequestUri has_any ("/users", "/groups", "/servicePrincipals", "/applications", "/directoryRoles", "/roleManagement") | summarize Reads=count(), Resources=dcount(RequestUri) by UserId, AppId, CallerIpAddress, bin(TimeGenerated, 10m) | where Reads > 200 | sort by Reads desc

10 分钟窗口内同一身份对目录资源的 GET 读取超过 200 次即视为可疑。阈值200可根据租户基线调优(下文 agent.py 也把该值设计为可配置参数)。

Step 6:将 Graph 活动关联回源登录

把可疑的 Graph 调用者透视回登录记录,恢复设备、位置、MFA 与条件访问结果。注意AADGraphActivityLogs中的SignInActivityId可能携带==填充,与SigninLogs.UniqueTokenIdentifier不同:

AADGraphActivityLogs | where TimeGenerated > ago(1d) | where UserAgent contains "aiohttp" | extend TokenId = trim_end("=", tostring(SignInActivityId)) | join kind=leftouter ( SigninLogs | extend TokenId = tostring(UniqueTokenIdentifier) | project TokenId, UserPrincipalName, IPAddress, AppDisplayName, ConditionalAccessStatus, DeviceDetail ) on TokenId | project TimeGenerated, UserId, UserPrincipalName, CallerIpAddress, IPAddress, AppDisplayName, ConditionalAccessStatus, UserAgent

trim_end("=", ...)正是 api-reference.md 中强调的关联键预处理,缺失这一步会导致 JOIN 大面积失败。关联成功后,可同时看到 Graph 调用侧的CallerIpAddress与登录侧的IPAddress、条件访问状态与设备详情,足以支撑告警定级。

Step 7:固化为计划性分析规则

将保真度最高的查询(Step 2–4)提升为 Sentinel 计划性分析规则:

  • 设置查询周期/频率(例如每 1h 运行一次、回看 1d);
  • 将规则映射到 T1078.004;
  • 配置实体映射(Entity =UserId,IP =CallerIpAddress,Host/App =AppId),使事件自动富化;
  • 上线前通过 watchlist 排除已知的自动化/服务主体 AppId 与已批准的扫描器 IP,控制误报。

api-reference.md 还给出了通过 REST API 创建/更新计划的 Sentinal 分析规则的端点大纲:

方法端点用途
PUT/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.OperationalInsights/workspaces/{ws}/providers/Microsoft.SecurityInsights/alertRules/{ruleId}?api-version=2023-02-01创建/更新计划性分析规则(请求体承载 KQLqueryqueryFrequencyqueryPeriodtacticstechniques: ["T1078.004"]entityMappings

可复用的 KQL 积木块

api-reference.md 将本技能中的常用表达式提炼为可直接复用的积木块,适合在构建新规则时拼接:

// 确认摄入 union withsource=Tbl MicrosoftGraphActivityLogs, AADGraphActivityLogs | where TimeGenerated > ago(1d) | summarize count() by Tbl // aiohttp / python UA(ROADtools) AADGraphActivityLogs | where UserAgent contains "python" and UserAgent contains "aiohttp" // 工具 UA 字符串 union MicrosoftGraphActivityLogs, AADGraphActivityLogs | where UserAgent has_any ("AADInternals","azurehound","BloodHound","Go-http-client") // 从 RequestUri 提取顶层 Graph 资源 | extend TopLevelResource = tolower(tostring(split(split(RequestUri,"?")[0],"/")[3])) // 为关联修剪 SignInActivityId 填充 | extend TokenId = trim_end("=", tostring(SignInActivityId))

用 agent.py 脚本化猎捕

仓库中 scripts/agent.py 把上述五条核心 KQL 猎捕查询封装成了可重复运行的蓝队工具。它通过 Azure Monitor Query REST API(https://api.loganalytics.io/v1/workspaces/{ws}/query)执行查询,用 AAD bearer token 认证。获取 token 的方式:

az account get-access-token --resource https://api.loganalytics.io \ --query accessToken -o tsv

脚本内置的HUNTS字典对应 SKILL.md 的五个核心猎捕步骤:

  • ingestion—— Step 1 的摄入确认;
  • roadtools-ua—— Step 2 的 python/aiohttp UA 指纹;
  • tool-agents—— Step 3 的 AADInternals/AzureHound agent 字符串;
  • endpoint-sweep—— Step 4 的抗伪造端点扫描(完整保留has_all的 11 类资源集合);
  • volume-outlier—— Step 5 的高量读取离群点。

运行方式:

python3 agent.py --workspace "<workspace-guid>" \ --token "$(az account get-access-token --resource https://api.loganalytics.io --query accessToken -o tsv)" \ --hunt all --days 7 --threshold 200

从源码结构看,脚本的参数设计体现了工程化考量的几个要点:

  • --hunt支持单条或all批量执行,便于先跑全量再聚焦;
  • --days--threshold均为可配置项,其中--threshold默认 200,与 SKILL.md Step 5 的Reads > 200保持一致,允许按租户基线调优;
  • 错误处理对HTTPErrorURLError分别输出前 300 字符的响应体或网络错误,便于在 Sentinel/LA 权限不足或网络隔离环境下快速定位问题;
  • 结果表格最多打印 50 行并提示剩余行数,避免超大结果集刷屏。

该脚本是「查询即代码」的体现:把本文档中所有关键 KQL 从文档落到可执行文件,适合纳入日常狩猎的定时任务或 SOAR 编排。

检测指纹速查

工具主要指纹数据表
ROADtools(roadrecon)python+aiohttpUA;5 分钟内完整目录端点扫描AADGraphActivityLogs
AADInternalsUA 中的AADInternals/ 工具库字符串;AAD Graph 读取AADGraphActivityLogs
AzureHoundGo HTTP 客户端 UA;广泛的 MS Graph 枚举MicrosoftGraphActivityLogs
通用侦察短窗口内对 users/groups/apps/SPs 的高量 GET两张表

验证标准

按以下清单确认本技能已落地生效:

  • MicrosoftGraphActivityLogs 与 AADGraphActivityLogs 均已确认摄入
  • 已执行 ROADtools/aiohttp 的 User-Agent 指纹猎捕
  • 已执行 AADInternals/AzureHound agent 猎捕
  • 已执行行为端点扫描猎捕,并针对误报完成调优
  • 已执行高量枚举离群点查询
  • 至少一个发现已关联回登录/会话与源身份
  • 高保真查询已提升为计划性分析规则,映射 T1078.004 并配置实体映射
  • 已通过 watchlist 排除已知良好的服务主体/IP,控制误报

小结

AADGraphActivityLogs 的上线终结了传统 Azure AD Graph 的可见性盲区,而本技能给出了把两张 Graph 活动表变成检测力的完整路径:从确认摄入、字符串指纹猎捕,到抗 UA 伪造的行为端点扫描、高量离群点分析,再到登录关联与规则固化。它与仓库中的进攻性技能(attacking-entra-id-with-roadtools、auditing-entra-id-with-aadinternals、exploiting-active-directory-with-bloodhound)互为镜像,构成攻防闭环;配合 scripts/agent.py 可将整套猎捕流程脚本化、可重复化,最终让 T1078.004 云账户滥用在这一数据源上真正可检测、可响应。

【免费下载链接】Anthropic-Cybersecurity-Skills817 structured cybersecurity skills for AI agents · Mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF & MITRE F3 (Fight Fraud) · agentskills.io standard · Works with Claude Code, GitHub Copilot, Codex CLI, Cursor, Gemini CLI & 20+ platforms · 29 security domains · Apache 2.0项目地址: https://gitcode.com/GitHub_Trending/an/Anthropic-Cybersecurity-Skills

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 14:43:35

LangGraph生产级错误处理:RateLimitError与AuthError的四层防御体系

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 14:41:26

前端工程化配置文件解析与最佳实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 14:40:34

空调线控器弱电接线与蓝牙调试标准化实践

1. 为什么空调线控器的弱电接线和蓝牙调试必须“标准化”——从三起现场返工说起 去年夏天在杭州一个精装交付的别墅项目里&#xff0c;我跟着施工队跑了整整两周。不是调试失败&#xff0c;而是反复返工&#xff1a;第一套客厅空调线控器装完&#xff0c;业主一按“制冷”&…

作者头像 李华
网站建设 2026/9/12 14:39:38

Java校园卡系统实战:Eclipse+Tomcat+JDBC完整开发指南

简介&#xff1a;这是一份基于Java开发的轻量级校园卡管理系统源码包&#xff0c;面向Java初学者与课程设计学生&#xff0c;聚焦校园场景下的饭卡充值、消费记录与账户管理等核心功能&#xff0c;适合作为Java SE综合实践项目或毕业设计参考。资源共30个文件&#xff0c;含7个…

作者头像 李华