mcpField
A
auditing-code-for-vulnerabilities

auditing-code-for-vulnerabilities

github.com/trilwu安全17760 次安装12 周前更新
代码仓库

关于 auditing-code-for-vulnerabilities

auditing-code-for-vulnerabilities 是面向代码审计人员的源代码漏洞分析方法,适用于审查仓库、变更和扫描器报告。它通过建立安全上下文、追踪攻击面、验证可利用性和寻找同类问题,区别于仅依赖模式匹配的扫描。

主要功能

  1. 01先建立资产与信任边界模型
  2. 02映射并排序输入入口
  3. 03沿数据路径追踪漏洞类别
  4. 04验证可达性、控制与影响
  5. 05确认漏洞后搜索变体
  6. 06记录审计覆盖范围

适用场景

  1. 01审计服务或代码库中的安全缺陷
  2. 02审查提交或拉取请求引入的风险
  3. 03验证扫描器告警是否属实
  4. 04为客户安全审计制定计划

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trilwu/secskills --skill auditing-code-for-vulnerabilities

安装后在 Claude Code 中输入/auditing-code-for-vulnerabilities确认已加载。

附带文件references/bug-class-checklist.md

详细介绍

审计代码中的漏洞

在源代码中发现真实漏洞,与运行扫描器是两项不同的工作。扫描器会匹配模式;审计人员则会构建代码应该保证什么的模型,然后寻找保证失效的路径。这项技能介绍的正是第二项工作的方法。

适用场景

  • 审计代码库、服务或库中的安全缺陷
  • 审查差异、分支或拉取请求中引入的漏洞
  • 在大型代码库中排查某一特定类别的漏洞
  • 验证扫描器报告或已报告的漏洞是否真实存在
  • 为客户项目制定审计计划和覆盖范围报告

不适用场景

  • 对运行中的应用进行黑盒测试——使用 testing-web-applications 或 testing-apis
  • 专门针对 PHP 代码库(类型混淆、unserialize/phar POP 链、php:// 包装器)——使用本方法以及 auditing-php-applications
  • 排查植入的 WebShell 或后门,而非漏洞——使用 hunting-web-backdoors
  • 仅有二进制文件的目标——使用 analyzing-binaries
  • 依赖和构建流水线风险——使用 auditing-supply-chain
  • 密码学构造审查——使用 reviewing-cryptography
  • 撰写已完成发现的问题报告——使用 reporting-security-findings
  • 使用构建者/批评者分工和迭代,在整个目标范围内开展多 Agent 漏洞发现活动——使用 orchestrating-vulnerability-research,它会将本技能分派为每个切片的排查者

工作循环

审计分为四轮,而不是一轮。不要跳到第 3 轮。

1. Context      → what does this system protect, and from whom?
2. Attack surface → where does untrusted input enter, and what does it reach?
3. Hunt          → trace specific bug classes along those paths
4. Verify        → prove exploitability before you write a word
第 1 轮:阅读代码前先建立上下文

不要随意打开文件。先花时间回答以下问题:

问题查看位置
有哪些与安全相关的资产?README、文档、数据模型、数据库架构
有哪些参与者和信任层级?身份验证中间件、角色枚举、租户模型
声明了哪些不变量?测试、断言、包含“must”“never”“invariant”的注释
此处已修复过哪些问题?使用 git log --grep 搜索安全关键词、CVE 文件、SECURITY.md
哪些内容不在范围内?项目简报、供应商代码、生成文件
# Prior security work is the cheapest source of bug leads
git log --oneline --grep='security\|CVE\|vuln\|injection\|auth bypass\|overflow' -i | head -40

# Stated invariants often mark where the author was nervous
rg -n --stats 'MUST NOT|must never|SECURITY|XXX|HACK|TODO.*(auth|secur|valid)' -i

# Where does privilege actually get checked?
rg -n 'is_admin|require_role|authorize|has_permission|@login_required|checkAccess'

开始排查前,先写一份简短的目标模型:资产、参与者、信任边界,以及违反后影响最大的三个不变量。之后的所有工作,都是在寻找这些不变量的反例。

第 2 轮:绘制攻击面

列出所有入口点,然后按优先级排序。入口点在未经验证前能触达多深,决定了它的重要程度。

# HTTP/RPC routes
rg -n '@(app|router)\.(get|post|put|delete|patch)|app\.(get|post)\(|@RequestMapping|http\.HandleFunc'

# Deserialization, template rendering, and dynamic execution sinks
rg -n 'pickle\.loads|yaml\.load\(|Marshal|unserialize|ObjectInputStream|eval\(|new Function|exec\(|Runtime\.getRuntime'

# Command, SQL, and path sinks
rg -n 'os\.system|subprocess.*shell\s*=\s*True|child_process\.exec\(|execSync|Statement\.execute|\.raw\(|fmt\.Sprintf.*SELECT'

# Where authentication is decided rather than enforced
rg -n 'verify=False|InsecureSkipVerify|jwt\.decode\(.*verify.*False|algorithms=\[.*none'

按以下顺序排列入口点:无需身份验证即可访问 > 低权限层级可访问 > 仅管理员可访问。然后沿着优先级最高的入口点向内追踪。深度胜过广度——完整追踪一条路径,胜过找到二十条 grep 匹配结果。

grep 匹配结果是候选项,不是发现的问题。 上述命令只是低成本地广撒网;每个匹配项在完成追踪之前都是尚未解决的线索。保留候选集——以 (file:line, bug class, entry point) 形式建立工作清单——并逐一给出明确结论:已追踪且安全、已确认或需要 PoC。先低成本扩大搜索范围,再针对每个候选项投入高成本推理——顺序绝不可反过来。常见的失败并非缺少 grep 模式,而是列出五十个候选项,只粗略查看五个,就宣称整个代码库没有问题。对于大型代码库,应将项目自身的惯例纳入搜索范围——例如 ORM 的原始查询绕过方式、身份验证装饰器的名称、模板调用方式——因为通用模式容易漏掉产出最高的危险点。

第 3 轮:沿追踪路径排查漏洞类别

对于每条有希望的路径,从源头到汇点追踪污点,并思考代码作了哪些假设。以下是高收益漏洞类别,按其进入生产环境的频率大致排序:

授权,而非身份验证。 大多数真实的数据泄露源于缺少对象级检查,而不是登录机制失效。对于每个接收 ID 的处理程序,都要问:对象是否限定在调用者的租户或用户范围内,还是仅按 ID 查询?检查查询,而不是装饰器。

信任边界混淆。 数据在一层经过验证,却在另一层重新解析。留意跨越序列化边界的值——例如经过验证的字符串又被解析为 URL、路径、模板或查询。

状态与并发。 检查后使用的间隙、非原子余额更新、实际上并不唯一的幂等键,以及会重放副作用的重试路径。查找没有锁或事务保护的先读后写操作。

注入到次级解释器。 SQL、shell、LDAP、XPath、模板引擎、日志格式和正则表达式。问题从来不是“是否有过滤”,而是“过滤器与解释器是否采用相同的语法”。

内存安全(C/C++/不安全 Rust/CGo)。边界检查前进行长度运算、使用受攻击者影响的大小调用 memcpy、循环边界差一错误、有符号与无符号转换,以及错误路径上的释放后使用。

错误与清理路径。 通常有人审查正常路径,却不会审查 except、catch、defer 和 goto fail 分支。要专门审查这些路径。

机密信息与密码学误用。 硬编码密钥、对令牌进行非恒定时间比较、由 Math.random/rand() 生成可预测 ID、缺少签名验证。深入的密码学审查应归入 reviewing-cryptography。

第 4 轮:变体分析

漏洞是一个模式,不是单一事件。确认漏洞后,立即搜索其同类问题——同一作者犯下的相同错误、复制的代码块,或相邻路由中缺失的相同检查。

# You found one unscoped lookup. Find every other one.
rg -n 'find_by_id|findOne\(\{ *_id|get_object_or_404' -A3 | rg -v 'tenant|owner|user_id'

变体分析能让审计产生不成比例的价值。应明确为其安排时间——每确认一项发现,大约投入同等时间搜索变体。

报告前验证

无法演示的发现只是一个假设。将其写入报告前,请回答以下四个问题:

  1. 可达性——指出具体入口点和所需的调用者权限。“攻击者无需身份验证即可访问 POST /api/export。”
  2. 可控性——说明攻击者可以控制危险值的哪一部分。
  3. 影响——说明哪些内容会被破坏:第 1 轮中的哪项不变量,以及攻击者能获得什么。
  4. 没有缓解控制措施——检查是否存在 WAF 规则、框架默认设置、中间件、DB 约束,或已经执行清理的调用方。

如果工作范围包含概念验证,请编写能够证明汇点受控的最小示例,而不是武器化的漏洞利用。

重新验证,剔除误报

上述四项检查用于确认发现;这一轮则试图推翻它。在每个已确认的候选项进入报告前都执行此步骤——报告的可信度取决于其中最严重的误报,而非最有力的真实发现。

  • 问题是否已经修复? 你正在查看的代码树可能没有包含修复,或者修复可能位于尚未拉取的分支上。提交报告前,请确认存在漏洞的代码确实会随产品发布。

    git log -S'<dangerous token>' --oneline -- <file>   # when this line changed, and toward what
    git log --oneline <checkout>..origin/main -- <file> # a fix on main you are not reading
    git blame -L <line>,<line> <file>                    # the commit that introduced it, for context
    
  • 从对立角度重新推导。 论证相反的情况:假设代码是安全的,然后查找使其安全的控制措施——中间件、DB 约束,或已执行清理的调用方。经受住真正反证尝试的发现,才是你能够辩护的发现。

  • 确认汇点仍然接收到你的值。 重新追踪最后一跳。重构常会在源头和汇点之间加入验证器或编码器,初次阅读时很容易忽略。

剔除未通过此处检查的候选项,并在覆盖范围备注中说明。无法重新验证的候选项只是给自己的备忘,不是发现。

应当摒弃的自我说服

这些想法会让审计沦为走形式。每一种都不对。

  • “上游应该已经验证过了。” 那就去查阅上游代码。对调用方未经验证的假设,是最常见的漏报原因。
  • “框架会处理这个问题。” 框架只会处理默认路径。检查版本,检查配置,确认这次调用是否使用了安全 API。
  • “这个输入是内部的。” 今天是内部的。追踪它的来源;队列消费者或管理员导入通常都能从外部触发。
  • “只有经过身份验证的用户才能利用这个漏洞。” 这是评估严重性时的一个因素,不是忽略问题的理由。
  • “这看起来是有意为之。” 意图不是防护措施。记录这一意图,并保留该发现。
  • “扫描器没有标记它。” 扫描器只能找到规则覆盖的问题。
  • “我已经确认了,所以它是真的。” 你只是在一次代码检出中、根据自己的第一印象确认了它。在将其写入报告之前,请针对实际发布的内容重新验证,并认真尝试推翻这一结论。
  • “我已经审查了足够多的文件。” 覆盖范围应根据第 2 轮中梳理的攻击面衡量,而不是根据文件数量衡量。

工具辅助,而非工具替代

静态分析用于扩大覆盖范围,以及在你了解某个模式后搜索变体。确认漏洞后编写规则,让它找出其余问题。

# Semgrep: broad pass, then a rule you write for your specific finding
semgrep --config=auto --severity=ERROR --json -o semgrep.json .
semgrep --config=./rules/my-variant-rule.yaml .

# CodeQL for dataflow questions grep cannot answer
codeql database create db --language=<lang> && codeql database analyze db --format=sarif-latest -o out.sarif

# Language-specific
bandit -r . -f json            # Python
gosec -fmt=json ./...          # Go
cargo audit && cargo geiger    # Rust deps + unsafe surface
npm audit --json               # JS deps

使用上述四个验证问题对每项工具发现进行分流。未经验证的扫描器输出报告比不报告更糟——它会消耗读者的信任,并掩盖真正的漏洞。

审计交付物

在审计过程中跟踪覆盖范围,并如实说明:

## Coverage
| Component | Files | Depth      | Notes                          |
|-----------|-------|------------|--------------------------------|
| auth/     | 12    | Full trace | All routes traced to sinks     |
| billing/  | 30    | Partial    | Webhook handlers only          |
| vendor/   | -     | Excluded   | Out of scope per brief         |

## Findings
F1. [High] Tenant isolation bypass in GET /api/reports/:id — <impact> — <repro>

说明你没有覆盖哪些内容。声称实现了实际上并未达到的全面覆盖,是你能产出的危害最大的交付物。

参考资料

  • references/bug-class-checklist.md — 各语言的漏洞搜寻清单
  • reporting-security-findings — 严重性评分和报告撰写格式
  • OWASP 应用程序安全验证标准(ASVS),用于基于要求的审查
  • CWE Top 25 和 CWE 层级结构,用于分类

评论

支持 Markdown