使用Kusto查询语言(KQL)识别Azure AD B2C中特定登录操作序列的恶意活动问题求助
使用Kusto查询语言(KQL)识别Azure AD B2C中特定登录操作序列的恶意活动问题求助
我完全理解你的困扰!你之前的查询确实能筛选出经历过所有四个操作的用户,但它没有验证这些操作是否严格按照你指定的顺序(Validate local account credentials→Update user→Reset user password→Update StsRefreshTokenValidFrom Timestamp)发生——这就是为什么你会得到不符合预期的结果,因为summarize countif()只关心操作是否存在,完全不考虑时间先后顺序。
要解决这个问题,我们需要追踪每个用户操作的时间序列,并检测其中是否包含你要找的连续操作顺序。这里推荐使用KQL的scan运算符,它专门用于识别事件流中的特定序列模式,非常适合你的场景。
下面是修改后的查询代码,我会逐段解释它的作用:
AuditLogs // 第一步:提取需要的字段,给每个操作分配顺序编号,过滤掉无关操作 | extend OperationOrder = case( OperationName == "Validate local account credentials", 1, OperationName == "Update user", 2, OperationName == "Reset user password", 3, OperationName == "Update StsRefreshTokenValidFrom Timestamp", 4, 0 // 标记无关操作,后续过滤掉 ) | where OperationOrder != 0 // 只保留我们关心的四个操作 | extend UserPrincipalName = tostring(parse_json(TargetResources)[0].userPrincipalName) | project UserPrincipalName, OperationOrder, TimeGenerated // 第二步:按用户和时间排序,确保操作按发生顺序排列 | order by UserPrincipalName asc, TimeGenerated asc // 第三步:使用scan检测每个用户的操作序列中是否存在1→2→3→4的连续顺序 | scan declare (is_match:bool=false) with ( step s1: UserPrincipalName != prev(UserPrincipalName) => is_match = false; // 切换用户时重置匹配状态 step s2: OperationOrder == 1 => is_match = false; // 遇到操作1,准备开始匹配序列 step s3: OperationOrder == 2 and prev(OperationOrder) == 1 => is_match = false; // 操作1之后到操作2,继续 step s4: OperationOrder == 3 and prev(OperationOrder) == 2 => is_match = false; // 操作2之后到操作3,继续 step s5: OperationOrder == 4 and prev(OperationOrder) == 3 => is_match = true; // 操作3之后到操作4,标记为匹配 ) // 第四步:筛选出匹配的用户,并去重(避免同一个用户多次触发序列导致重复结果) | where is_match == true | distinct UserPrincipalName
代码解释:
- 初始过滤与字段提取:和你原来的逻辑类似,给目标操作分配编号,同时过滤掉无关操作,提取用户主体名和时间戳。
- 排序:确保每个用户的操作严格按照时间先后顺序排列,这是检测序列的前提。
- scan运算符:这是核心部分,它会逐个检查每个用户的操作流:
- 当切换到新用户时,重置匹配状态;
- 依次检测操作1→2→3→4的连续出现,只有当这四个操作按顺序连续发生时,才会标记
is_match为true。
- 去重输出:最后筛选出匹配的用户,并去重,避免同一个用户多次触发序列导致重复结果。
如果你需要允许操作之间存在其他无关操作(比如四个目标操作按顺序出现,但中间夹杂了其他不相关的操作),可以稍微调整scan的逻辑,比如:
// 允许目标序列中间夹杂其他操作的版本 | scan declare (match_stage:int=0) with ( step reset: UserPrincipalName != prev(UserPrincipalName) => match_stage = 0; step look_for_1: OperationOrder == 1 => match_stage = 1; step look_for_2: match_stage == 1 and OperationOrder == 2 => match_stage = 2; step look_for_3: match_stage == 2 and OperationOrder == 3 => match_stage = 3; step found_match: match_stage == 3 and OperationOrder == 4 => match_stage = 4; ) | where match_stage == 4 | distinct UserPrincipalName
这个版本会忽略目标序列之间的其他操作,只要四个目标操作按1→2→3→4的顺序出现(不管中间有没有其他操作),就会被识别出来。
备注:内容来源于stack exchange,提问作者girish
相关产品推荐
相关产品推荐

