Yashmko/charon

GitHub: Yashmko/charon

Charon 是一款基于 LLM 语义推理与流量重放的 IDOR/BOLA 授权漏洞检测工具,通过自动推断资源所有权模型来替代传统盲目的 ID 暴力替换。

Stars: 0 | Forks: 0

# Charon — 语义化 IDOR 与授权检测工具 停止猜测 ID。开始推理所有权关系。 ![status](https://img.shields.io/badge/status-design%20phase-orange) ![python](https://img.shields.io/badge/python-3.11%2B-blue) ![license](https://img.shields.io/badge/license-MIT-green) ## 目录 - [问题所在](#the-problem) - [相关工具](#related-tools) - [工作原理](#how-it-works) - [阶段分解](#stage-breakdown) - [授权 DNA 与漂移检测](#authorization-dna--drift-detection) - [数据模型](#data-model) - [计划中的 CLI](#planned-cli) - [技术栈](#tech-stack) - [项目结构](#project-structure) - [构建路线图](#build-roadmap) - [OWASP 映射](#owasp-mapping) - [未来愿景 (v2)](#future-vision-v2) - [范围与道德](#scope--ethics) - [状态](#status) ## 问题所在 大多数 IDOR/BOLA 扫描工具都采用同样简单粗暴的方式:接收类似 `GET /api/orders/123` 的请求,将 ID 替换为 `122`、`124` 或其他用户的值,然后检查响应是否发生变化。这种暴力破解方式根本不理解 endpoint 的具体作用,也不知道谁应该拥有该资源。这不仅会产生大量噪音,还会遗漏依赖于角色或关系的授权逻辑(例如,经理可以查看下属的数据,但不能查看其他经理的),并且无法区分正确脱敏的响应与真实的数据泄露。 Charon 用推理代替猜测。它根据 API 规范和真实流量构建资源所有权模型,生成授权假设(“用户 B 绝不应该看到用户 A 的发票”),并且只有在响应确实违反了某项假设时,才会将其报告为漏洞。 ## 相关工具 像 **Autorize** 和 **AuthMatrix** 这样的 Burp 插件已经能够实现跨账号请求重放和响应差异比对了——这种机制并不新鲜,提前了解这一点很有价值。它们做不到的是推理:它们只能告诉你响应发生了变化,却无法判断这种变化是否真的是一次数据泄露,而且所有权/角色规则必须由人工提前配置好,工具才能使用。Charon 的差异化优势在更高一层——它从流量中推断所有权和策略模型,而不是依靠手工配置;它通过语义进行漏洞分诊,而不仅仅是依靠状态码。 ## 工作原理 ``` ┌─────────────────────┐ │ Input capture │ API spec + multi-account traffic └──────────┬──────────┘ │ ┌──────────▼───────────┐ │ Ownership modeling │ LLM maps fields → resource owners └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ Hypothesis + test gen│ Crafts cross-account test cases └──────────┬───────────┘ │ ┌──────────▼───────────┐ │ Live replay execution│ Fires requests with swapped tokens └──────────┬───────────┘ │ ┌──────────▼────────────┐ │ Semantic triage+report│ Maps findings to OWASP API Top 10 └───────────────────────┘ ``` 包含五个阶段,每个阶段都处理上一阶段的输出。每个阶段都可以独立测试——你可以针对已保存的抓包记录运行所有权建模,而无需访问实际的目标环境,这对于 CI 流程以及安全地迭代启发式算法非常重要。 ## 阶段分解 ### 1. 输入抓取 **目的:** 收集 API 在至少两个不同账号下实际运行情况的真实数据,以便后续阶段能够基于真实流量进行推理,而不是单凭规范进行盲目猜测。 **输入:** OpenAPI/Swagger 规范(如果没有正式规范,也可以是 Postman 集合),以及每个测试账号在正常使用时的代理抓包记录(Burp/ZAP/mitmproxy)——包括登录、浏览、创建/读取/更新一些资源。 **每笔交易记录的内容:** | 字段 | 描述 | |---|---| | `account_label` | 发起请求的测试账号(例如 `userA`, `userB`, `admin`) | | `method` | HTTP 动词 | | `raw_path` | 抓取到的字面路径,例如 `/api/orders/8821` | | `path_template` | 标准化路由,例如 `/api/orders/{id}` —— 使工具能够跨账号和不同 ID 将请求归为“同一个 endpoint” | | `query_params` | 解析后的键值对 | | `headers` | 完整的 header 集合;auth header/cookie 会被保留(供后续重放使用),其他所有内容也会保留用作上下文参考 | | `body` | 解析后的 JSON/form body(如果存在) | | `response.status` | HTTP 状态码 | | `response.headers` | 响应头 | | `response.body` | 解析后的响应体 | | `latency_ms` | 响应时间——后续在发现基于时间的权限检查差异时偶尔会用到 | **资源引用提取:** 对于每一笔交易,抓取层会扫描路径片段、query params 和 body 字段,寻找任何看起来像标识符的内容——UUID、数字 ID、slug——并将其记录为 `resource_ref`:它来自哪个字段、它的字面值,以及它出现在哪个账号的会话中。由于 `userA` 的会话自然会引用 `userA` 自己的资源,这正是下一阶段所需的原始信号:“这个 ID 属于这个账号,对应这个 endpoint 模板。” **为什么需要两个以上的账号:** 单个账号的流量只能显示该用户被允许看到的内容。跨账号抓取使得“B 的 token 是否暴露了 A 的资源”成为一个可测试的、具体的问题,而不是盲目猜测。 ### 2. 所有权建模 **目的:** 将抓取到的原始流量转化为资源所有权图——对于每个 endpoint 模板,它涉及哪种资源类型,哪个字段是所有权标识符,以及它预期具有什么样的访问范围(仅限所有者、受角色控制、公开)。 **过程:** LLM 会读取 OpenAPI 规范描述、路径模板以及响应字段名称/结构(由第 1 阶段提供),并对所有权语义进行推理。响应中名为 `user_id` 或 `owner_id` 的字段,或者像 `/users/{id}/invoices` 这样的路径,都是强烈的信号。模型还会参考 REST 约定——对 `/admin/*` 的 `DELETE` 请求意味着即使没有明确的规范注解,也存在角色访问控制。 **输出:** 生成一个图,其中每个节点代表一种资源类型(`order`, `invoice`, `profile`),并包含指向与其相关联的 endpoint 的边,以及针对每个节点推断出的所有权规则——此外,还会为每个角色生成一份通俗易懂的策略声明,例如:“访客只能访问公开资源”、“客服支持可以读取但不能编辑”、“管理员绕过租户限制”。以可读的形式展示推断出的策略(而不仅仅是作为内部图),正是让第 5 阶段能够标记出既定策略与观察到的行为之间的矛盾的关键,而不仅仅是发现孤立的异常响应。 ### 3. 假设与测试生成 **目的:** 将所有权图转化为具体的、可证伪的声明,然后将每个声明转换为实际的请求。 **假设示例:** “使用 `userB` 身份验证对 `/invoices/{id}` 发起的请求,在 `{id}` 属于 `userA` 的情况下,应当被拒绝(403/404)。” **测试生成:** 对于每一个假设,构建一个请求模板,该模板接收一个真实抓取到的请求,并在保留原始资源 ID 的同时替换其 auth 上下文(token/cookie)——这就生成了实际的跨账号测试用例。涵盖 BOLA(对象级别——B 能否读取/写入 A 的特定资源)、BFLA(功能级别——非管理员账号能否触发仅限管理员的操作),以及属性级别的测试——除了仅测试完整对象的 GET 替换外,还会针对另一个账号的资源生成单字段的 PATCH/PUT 请求,因为只写部分字段的访问权限是一个常见的漏洞,只读测试会完全漏掉它。 ### 4. 实时重放执行 **目的:** 向实时目标实际触发生成的测试用例。 **过程:** 轻量级重放引擎接收每个测试用例,将 `Authorization` header 或会话 cookie 替换为另一个账号的凭据,发送请求,并将响应与原始(同账号)响应一起记录以供比较。系统会按账号处理 session/token 的刷新,因此长时间的测试运行不会因为认证过期而失败。 ### 5. 语义分诊与报告 **目的:** 将真实漏洞与噪音区分开来。并非所有非 403 的响应都是漏洞——有些 endpoint 对于错误的账号会正确地返回空数据或脱敏数据。 **过程:** 响应体会与第 2 阶段的所有权图进行比对。只有当响应确实包含了在语义上属于其他账号的字段——姓名、电子邮件、地址、余额,以及任何被标记为所有者范围的字段——时,才会触发漏洞报告,而不是仅仅因为状态码不是 403 就报警。每个漏洞都会获得一个置信度分数和一行解释。 **影响范围:** 一旦确认漏洞,Charon 就会查询所有权图以寻找同级节点——触及相同资源类型或匹配相同路由模板族的其他 endpoint——并自动针对它们重新运行相同的跨账号测试。在 `/invoices/{id}` 上确认的一个泄露,会自动触发对 `/invoices/{id}/export`、`/invoices/{id}/attachments` 以及共享该资源类型的任何其他路径的检查,而不需要依赖人工去想到并手动测试它们。 **根本原因聚类:** 在报告输出中,共享相同潜在原因的漏洞——例如 `InvoiceController` 中的每个 endpoint 都缺少相同的所有权检查——将被归并在一个根本原因下,而不是作为单独的警报列出。一份写着“1 个根本原因,4 个受影响的 endpoint”的报告是开发者真正会去修复的东西;而“4 个漏洞”只会被塞进待办事项中然后被遗忘。 **“为什么这个没有被拦截?”:** 每个漏洞报告都包含一个简短的前后对比——该角色预期的推断策略是什么,实际观察到的情况是什么,以及可能的原因。在构建此功能时需要牢记一个诚实的事实:Charon 是一个黑盒工具,它永远看不到目标的源代码,所以这是一种推断出的假设,而不是追踪的执行日志——它无法字面意义上看到“所有权检查的 middleware 没有运行”。它能够切实做到的是将策略与行为进行比较,并指出最可能的漏洞,尤其是当影响范围显示相同的漏洞在整个路由族中反复出现时: ``` Expected (from inferred policy): guest -> invoice: forbidden Observed: guest token -> GET /invoices/8821 -> 200, returned owner_id + email + amount Likely cause: ownership check missing or misconfigured for this resource — repeats across 4 sibling endpoints in the same route family, suggesting the gap is in shared handler logic rather than one-off endpoint code. ``` 这依然具有极高的可操作性——“这个漏洞在于共享逻辑,这是证据”——同时无需声称 Charon 实际上并不具备的、对服务器内部逻辑的可见性。 **证据级别的输出:** 每个漏洞都附带原始(同账号)请求、替换账号后的请求、结构化的响应差异,以及一个最小复现步骤——即仍然能触发该泄露的最小请求。推理过程本身作为一条显式的逻辑链被存储(资源所有者、请求者身份、泄露的内容、推断策略预测的内容),而不是一句简单的置信度评语,这样审核人员就可以逐步验证它,而不是仅仅盲目相信一个数字。 **输出:** 映射到 OWASP API Security Top 10 的结构化漏洞报告——主要针对 **API1:2023 Broken Object Level Authorization** 和 **API5:2023 Broken Function Level Authorization**——可以直接放入渗透测试报告中。 ## 授权 DNA 与漂移检测 第 2 阶段已经在内部构建了策略模型。将其序列化可以为你提供超越单次运行的实用价值:一份应用程序推断授权规则的可读快照,以及两个不同时间点快照之间的差异对比。 ``` resource: invoice owner: customer_id permissions: owner: [read, download] accountant: [read, update] admin: ["*"] forbidden: guest: ["*"] ``` 在重构或重新部署后再次运行 Charon,并将新的快照与上一次的快照进行对比: ``` - guest -> read invoice ❌ + guest -> read invoice ✅ ``` 这是一种机制,而不是三个独立的功能——对策略图进行快照、存储,并将下一次的快照与它进行对比。这种单一的对比引擎涵盖了人类可读的应用程序授权规范、重构静默扩大访问权限时的漂移检测,以及(配合未来愿景中提到的 CI 集成)与特定部署绑定的回归测试。 ## 数据模型 抓取的流量和发现的漏洞存储在 SQLite 中(在这种规模下不需要更重的数据库)。 ``` CREATE TABLE captured_requests ( id INTEGER PRIMARY KEY, account_label TEXT NOT NULL, method TEXT NOT NULL, raw_path TEXT NOT NULL, path_template TEXT NOT NULL, query_params TEXT, -- JSON headers TEXT, -- JSON body TEXT, -- JSON or raw text captured_at TIMESTAMP ); CREATE TABLE captured_responses ( id INTEGER PRIMARY KEY, request_id INTEGER REFERENCES captured_requests(id), status_code INTEGER, headers TEXT, -- JSON body TEXT, -- JSON or raw text latency_ms INTEGER ); CREATE TABLE resource_refs ( id INTEGER PRIMARY KEY, request_id INTEGER REFERENCES captured_requests(id), field_location TEXT, -- 'path' | 'query' | 'body' field_name TEXT, value TEXT, inferred_type TEXT -- 'uuid' | 'int' | 'slug' ); CREATE TABLE ownership_graph ( id INTEGER PRIMARY KEY, resource_type TEXT NOT NULL, path_template TEXT NOT NULL, owner_field TEXT, scope TEXT -- 'owner_only' | 'role_gated' | 'public' ); CREATE TABLE findings ( id INTEGER PRIMARY KEY, hypothesis TEXT NOT NULL, original_request_id INTEGER REFERENCES captured_requests(id), -- same-account baseline swapped_request_id INTEGER REFERENCES captured_requests(id), -- cross-account replay leaked_fields TEXT, -- JSON list response_diff TEXT, -- JSON: field-level diff between baseline and swapped response confidence REAL, owasp_class TEXT, -- 'API1' | 'API5' | ... explanation TEXT, repro_steps TEXT, -- minimal reproduction sibling_of INTEGER REFERENCES findings(id) -- set when surfaced via blast radius ); ``` 已抓取交易的示例,及其存储格式: ``` { "account_label": "userB", "method": "GET", "raw_path": "/api/invoices/8821", "path_template": "/api/invoices/{id}", "headers": { "Authorization": "Bearer " }, "response": { "status_code": 200, "body": { "id": 8821, "owner_id": "userA", "amount": 4200, "email": "usera@example.com" } }, "resource_refs": [ { "field_location": "path", "field_name": "id", "value": "8821", "inferred_type": "int" } ] } ``` 这一条记录——userB 的 token,userA 的发票 ID,包含 userA 电子邮件的响应——正是构建漏洞报告的原始素材。 证据级别漏洞报告示例,其在报告中的呈现形式: ``` { "hypothesis": "userB should not be able to read userA's invoice", "owasp_class": "API1", "confidence": 0.93, "leaked_fields": ["email", "amount", "owner_id"], "explanation": "userB's token returned userA's invoice including PII fields tagged owner-scoped in the ownership graph", "evidence": { "baseline_request": "GET /api/invoices/8821 (as userA) -> 200", "swapped_request": "GET /api/invoices/8821 (as userB) -> 200", "response_diff": "swapped response identical to baseline; no redaction applied" }, "repro_steps": "Authenticate as userB, GET /api/invoices/8821 (an ID owned by userA)", "sibling_of": null } ``` ## 计划中的 CLI 目标接口(尚未实现——这是设计目标): ``` # 步骤 1:通过 local proxy 捕获每个账户的流量 charon capture --account userA --proxy :8080 charon capture --account userB --proxy :8080 charon capture --account admin --proxy :8080 # 步骤 2:根据 spec + captures 构建 ownership graph charon model --spec openapi.json --captures ./captures.db # 步骤 3:生成 hypotheses + test cases charon generate --captures ./captures.db --out ./testcases.json # 步骤 4:针对 live target 进行重放 charon run --testcases ./testcases.json --target https://staging.example.com # 步骤 5:triage + 报告 charon report --format markdown --out ./findings.md ``` ## 技术栈 - **语言:** Python 3.11+(实现调用 LLM、重放 HTTP 的 CLI 工具的最快途径) - **HTTP 重放:** `httpx` - **存储:** SQLite(无基础设施开销,便携的单文件数据库) - **LLM 调用:** Groq API,用于所有权建模和分诊分类步骤——这些调用是大量小型、低延迟的请求,而不是一次大型的内容生成,这正是 Groq 推理速度的强项 - **规范解析:** `openapi-spec-validator` / `prance` 用于 OpenAPI 解析 - **运行环境:** GitHub Codespaces 或任何云 shell——这里没有任何地方需要本地计算,因此在低内存硬件上也能流畅运行 ## 项目结构 ``` charon/ ├── capture/ # proxy listener, traffic recorder ├── modeling/ # ownership graph builder (LLM calls) ├── generate/ # hypothesis + test case generation ├── replay/ # live request execution engine ├── triage/ # semantic response classification + scoring ├── report/ # OWASP-mapped markdown/JSON report output ├── db/ # SQLite schema + migrations ├── cli.py # entrypoint └── tests/ ``` ## 构建路线图 旨在快速获得可供演示的版本,随后再逐步深化。 **第 1 周 — 抓取与重放骨架** 基于代理的单账号抓取,SQLite 存储,手动跨账号放(硬编码 token 替换)。目前不需要 AI。目标:证明你可以将一个请求记录为 userA,并成功地以 userB 的身份针对真实的(已授权的)目标进行重放。 **第 2 周 — 所有权建模** 将抓取的数据和 OpenAPI 规范输入给 LLM 调用,生成所有权图。通过手动对比几个你已经知道答案的 endpoint 来验证它(你已经从 Tirth.com 获得了这些信息)。 **第 3 周 — 假设生成与自动化重放** 自动将图转化为测试用例,连接重放引擎以一次性运行所有测试。 **第 4 周 — 语义分诊与报告** 添加响应分类步骤,对漏洞进行评分而不是直接输出原始数据,生成映射到 OWASP 的报告输出。 每周结束时都会有一个能够实现端到端运行的东西,哪怕它还很粗糙——这就是让它在任何时候都具备演示价值的原因,而不是变成一堆半成品。 ## OWASP 映射 | 漏洞类型 | OWASP API Security Top 10 (2023) | |---|---| | 对象级访问绕过 (IDOR) | API1 — Broken Object Level Authorization | | 功能级访问绕过 | API5 — Broken Function Level Authorization | | 响应中的过度数据暴露 | API3 — Broken Object Property Level Authorization | ## 未来愿景 (v2) 上面提到的 v1 范围——输入抓取、包含策略推断的所有权建模、包含属性级别用例的假设/测试生成、重放、带有影响范围的语义分诊——是特意设计为可在一个月左右完成的。以下想法被明确排除在 v1 范围之外,记录在此是为了证明我们的雄心,同时不会让第一次构建变成一个无法收尾的庞大工程。 **更深入的授权面** - 工作流/状态机测试——对多步骤流程(邀请 → 接受 → 升级 → 取消)进行建模,并生成针对状态转换滥用的测试用例 - 时间授权——检查在角色降级、移出组织或会话失效后,访问权限是否确实被撤销,而不仅仅是在某个单一时间点进行检查 **身份与关系建模** - 超越简单所有权的完整身份图:用户 → 团队 → 组织 → 项目,委托访问,继承权限——解答诸如“Team Red 外部的人能否访问 Repo X”这样的问题 **多协议覆盖** - 感知 GraphQL schema 的所有权推断(嵌套对象边,节点级 auth) - 文件/对象存储检查——签名 URL,S3/Firebase 存储桶,CDN 资源,导出 endpoint - 跨 REST、GraphQL、WebSockets 和后台任务的跨服务身份关联 **攻击叙事层** - 权限提升链探测器——将孤立的漏洞链接成一条完整的攻击路径(这是之前在规划此项目时提出的漏洞链合成器的想法;一旦所有权图和漏洞存储库建立起来,它自然就能完美融入) - 角色引擎——自动预配合成账号(已挂起、未验证、订阅过期、外部协作者)并以每个身份重放完整的测试套件 - 业务影响风险评分——将漏洞表示为跨租户/账号的估计影响范围,而不仅仅是一个严重性标签 **工具集成** - Burp Suite 插件,使实时抓取的流量直接流入 Charon - CI 集成的回归测试——将授权 DNA 差异对比(现在在 v1 中)接入 CI,使其在每次部署时运行,并将任何漂移与导致该漂移的提交绑定,而不是手动运行 - 组织定义的策略 DSL——允许测试人员声明自定义规则(“账单对象绝不应跨账号暴露 PII”),并直接据此验证应用程序,将 Charon 从一个检测器转变为一个验证器 这里的每一项本身都是一项需要数周甚至数月才能完成的严谨工作。在 v1 发布并可供演示后,选择其中一项作为 v2 的里程碑——不要一次启动多个项目。 ## 范围与道德 该工具会跨账号边界触发经过身份验证的请求——它是一种主动测试工具,而不是被动的扫描器。请仅在您拥有明确书面授权进行测试的系统上运行它。在没有明确测试时段和回滚计划的情况下,请勿将其指向生产系统,因为跨账号写入(如果您将其扩展到 GET 请求之外)可能会修改真实数据。 ## 状态 设计阶段。上述架构和数据模型已最终确定;实现阶段将遵循构建路线图。本 README 将随着每个阶段的发布而更新。
标签:API安全, C2, CISA项目, DLL 劫持, IDOR检测, JSON输出, Web安全, 大语言模型, 蓝队分析, 逆向工具