审计守卫缺口:未受守卫的对等体即是漏洞
大多数访问控制和缺失验证的漏洞并非异乎寻常——它们只是同一族系中一个处理程序忘记了执行其兄弟程序所做校验的检查。例如,admin_delete 检查了角色而 bulk_delete 却没有;read_bounded 验证了长度而 read_fast 却信任它。从上到下阅读文件会隐藏这些差异;比较对等体 则会暴露它们。这是最高产的白盒手段之一。
你正在寻找的不对称性
守卫 → 汇点 (预期中的安全路径)
??? → 汇点 (缺少守卫的对等路径——即漏洞)
适用场景
- 某个汇点可从多个调用点到达,且你怀疑其中一个调用点跳过了检查。
- 你正在审计一个授权模型、一个解析器家族或一组处理器中是否存在被遗忘的检查。
- 需要为一个发现提供“为什么这是错误的”理由,并将其构建为与正确对等体的具体差异。
范围检查
仅限授权来源。如果你无法指出授权方式,则停止操作。
循环步骤
-
选择一个已受守卫的锚点。 找到一个在敏感汇点前确实进行验证的函数——例如授权/所有权检查、边界检查、白名单、消毒器。这个函数是“此处正确做法是什么”的参考。
-
将守卫与其保护的汇点绑定。 明确指出具体的检查内容以及具体的汇点。“正确”意味着守卫支配该汇点:在通过锚点的每一条路径上,检查都先于汇点执行。仅仅存在于函数中并不等同于支配。
-
枚举结构上的对等体。 不要局限于同一文件中的邻居——关键在于结构上的亲缘关系:访问同一汇点的函数;同一个接口/虚方法的重写;同一路由表/调度映射/命令转换器中的处理程序;同一类中的并行成员(
get_x/set_x/delete_x);共享辅助函数的调用者,其中一些对参数进行了消毒而另一些则直接传递原始参数。能够到达同一汇点的对等体是最强的信号。 -
根据守卫所执行的内容(而非名称)将每个对等体与锚点进行差异比较。 对于每个对等体,询问是否存在等效的检查支配同一个汇点。将缺口分类为:
- 缺失 - 完全没有等效检查。
- 可绕过 - 存在但可通过某些路径绕过(提前返回、短路
||、跳过检查的分支)。 - 弱于对等体 - 一种不同类型的检查:锚点执行授权而此处执行身份验证;锚点执行边界检查而此处执行类型检查;锚点检查了所有字段而此处只检查了一个字段。
- 汇点之后 - 检查确实执行了,但在危险操作之后。
- 上下文错误 - 真实的检查但不适用于该汇点的载荷类别(例如,针对该汇点语言是错误的编码器)。
-
通过攻击者输入确认可达性。 未受守卫的汇点只有在不可信输入能够到达它时才构成漏洞。将对等体的危险参数回溯到真实来源(交给
adjudicating-taint-paths)。仅用常量调用的对等体不算发现。 -
记录为差异——使用模式。 表述为:“锚点 A 使用检查 C(支配性)守卫了汇点 S;对等体 B 到达汇点 S,
guard_status= <缺失/可绕过/弱于对等体/汇点之后/上下文错误>,并且 B 的参数通过 <来源> 受到攻击者控制。” 按照发现模式进行输出。
示例
锚点:
delete_own_post(user, post_id)- 在db.delete(post)之前检查post.owner == user.id(支配性)。
对等体:admin_bulk_delete(ids)到达同一个db.delete汇点;唯一的门禁是路由级别的@login_required,没有每个对象的所有权检查。
差异:guard_status = 弱于对等体- 存在身份验证,但缺少授权(所有权)。
可达性:ids直接来自请求体;任何经过身份验证的用户都可以调用它。确认为 IDOR/BFLA,严重性高——“任何登录用户可以通过 id 删除任何用户的帖子。”
应拒绝的合理化理由
- “函数里有检查,所以它受守卫。” → 仅当它支配汇点时才是。一个只在汇点跳过的分支上存在的检查不是守卫。
- “两个函数都有身份验证,它们等效。” → 身份验证不是授权;类型检查不是边界检查。比较它们实施了什么。
- “对等体看起来未受守卫——报告它。” → 在你确认攻击者输入到达汇点之前。不可达 ≠ 发现。
- “仅限于同一文件中的邻居。” → 危险的对等体常常位于另一个模块中,只共享同一个汇点。根据结构而不是文件来枚举。
实际执行方式
你需要能够按函数所到达的汇点进行分组,并显示每个函数的精确主体,以便逐守卫进行差异比较并检查支配性。代码属性图使得“哪些对等体到达这个汇点,以及哪些首先进行验证”可以直接回答;否则,你需要手动从共享汇点或辅助函数的调用点中枚举对等体并阅读每个函数。可达性步骤复用了 adjudicating-taint-paths。
相关技能
adjudicating-taint-paths- 确认对等体的汇点可通过输入到达。hunting-bugs-with-a-code-graph- 此技能所在的上级循环。- FINDING-SCHEMA.md - 每个发现所遵循的模式。