Hadrian+Vespasian+crAPI:API越权自动化检测实战

发布时间:2026/9/16 5:15:37
Hadrian+Vespasian+crAPI:API越权自动化检测实战 1. 为什么偏偏是这三件套Hadrian、Vespasian 与 crAPI 的组合逻辑说实话第一次看到 Hadrian、Vespasian、crAPI 这三个名字凑在一起时很多人第一反应是“又有人把罗马皇帝的名字拿来搞安全工具了”。实际上这套组合恰好覆盖了 API 越权漏洞检测从靶场准备、主动扫描到被动验证的完整闭环。crAPI 是 OWASP 维护的故意脆弱 API 靶场Hadrian 负责自动化侦察与漏洞扫描Vespasian 则聚焦于越权类逻辑漏洞的深度验证。三者配合能在一小时左右跑出一份初步的越权风险报告这个效率在传统人工测试里很难做到。先解释一下越权漏洞本身。API 越权大致分两种水平越权IDOR是指普通用户 A 访问普通用户 B 的资源垂直越权是指低权限用户调用高权限接口。前者在 JSON 请求里换个 id 参数就能触发后者往往藏在未校验角色字段的管理接口中。自动化检测的核心难点在于越权不是简单的签名或注入问题而是业务逻辑层的鉴权缺失所以单纯靠流量重放或规则匹配很难发现。Hadrian 的定位是“自动化的攻击面梳理与漏洞扫描器”它会把目标 API 的主机、端口、路径、参数、认证方式全部枚举出来并尝试注入常见 Payload。Vespasian 更像一个专门针对逻辑漏洞的验证框架能自定义用户角色、会话 Token 和请求链把 Hadrian 发现的疑似越权点逐一带入真实业务场景进行复现。crAPI 则提供了汽车相关的模拟业务包含车辆管理、维修预约、优惠券、支付等多组接口里面故意埋了十几种越权漏洞正好用来验证工具链的有效性。我在实际使用中对这套组合的评价是crAPI 解决了“没有合法靶场”的问题Hadrian 解决了“不知道从哪下手”的问题Vespasian 解决了“扫出来但不确定是不是真漏洞”的问题。三个工具分别对应了目标确认、主动探测、验证利用三个阶段彼此之间没有功能重叠组合起来非常顺。如果你已经熟悉 Burp Suite 或 Postman 的常规测试流程把这套自动化链路当作前哨侦察再结合人工研判效果会更好。这套组合的另一个优势是对部署环境要求低。Hadrian 和 Vespasian 都可以跑在 Docker 容器里crAPI 官方也提供了一键启动的 docker-compose 文件宿主机的 CPU 和内存压力很小。我实测在 4 核 8G 的云主机上同时运行三个容器占用的内存大约在 3.5G 左右CPU 峰值不会超过 60%完全可以接受。即使是新手只要会基本的 Docker 命令跟着下面的流程走就能搭起来。2. 部署前必须搞清楚的三个基础概念2.1 API 越权漏洞在自动化工具眼里是什么样的自动化工具不会像人一样“理解”业务它只会看请求和响应的差异。以水平越权为例工具会先记录两个不同用户的 Token然后发送两个内容完全一致、只有 Token 不同的请求如果响应体中包含对方的敏感信息就判定存在越权。这个过程听起来简单但实际实现时有很多细节Token 从哪来、请求顺序怎么控制、响应怎么比对。通常会把越权检测拆成三个阶段。第一阶段是基线采集用正常用户 A 的 Token 请求目标接口记录响应内容。第二阶段是身份替换把 Token 换成用户 B 的或者干脆去掉 Token重新发送同一请求。第三阶段是结果比对如果两次响应在状态码、响应体长度、关键字段上存在明显差异就说明接口的鉴权逻辑有问题。Hadrian 在第二阶段做了大量自动化工作它会把 URL 中的数字 ID、UUID、Base64 编码参数自动标记为可疑位置并尝试替换成其他值。垂直越权的检测思路类似但重点在接口路径上。工具会枚举常见的管理路径比如 /admin、/api/v1/users、/internal然后用普通用户 Token 去访问。如果返回 200 而不是 403基本可以断定存在垂直越权。Hadrian 的路径字典里内置了数千条常见接口路径覆盖率比手动猜测高得多。2.2 Hadrian 与 Vespasian 各自负责哪一块Hadrian 是“广撒网”的角色。它会先对目标域名做子域名枚举、端口扫描、HTTP 服务指纹识别然后爬取所有可访问的 API 路径分析 Swagger/OpenAPI 文档收集请求参数、Header 和认证方式。扫描结束后它会输出一份结构化的资产清单标出哪些接口存在参数型越权嫌疑、哪些接口暴露了敏感信息、哪些接口缺少身份认证。Vespasian 是“深挖洞”的角色。它读取 Hadrian 的扫描报告选取其中疑似越权的接口按照用户在配置文件中预设的两个角色比如普通用户和管理员自动生成验证请求。Vespasian 支持多步骤请求链比如先登录获取 Token、再携带 Token 访问资源、最后修改资源这种链式操作在越权测试中非常关键因为很多漏洞只有执行完整流程后才能触发。两个工具的衔接方式很简单Hadrian 输出 JSON 或 CSV 格式的报告Vespasian 通过命令行参数直接读入。我建议把 Hadrian 输出的所有接口都导入 Vespasian 验证不要只挑高危的因为越权漏洞的危害等级在自动化扫描阶段往往被低估很多看似低危的接口反而是越权重灾区。2.3 crAPI 靶场里到底埋了哪些漏洞crAPI 是 Completely Ridiculous API 的缩写设计目标就是“故意做得离谱”。它模拟的是一个车辆售后服务平台包含注册登录、车辆绑定、维修记录查询、优惠券领取、预约服务、支付等模块漏洞点覆盖了从 Web 端到移动端的常见 API 缺陷。按照官方文档和社区复现结果crAPI 至少包含以下越权相关漏洞注册接口存在用户枚举、车辆信息接口存在水平越权、维修记录接口未校验车辆所有权、优惠券接口可无限领取、管理后台接口缺少角色校验、密码重置逻辑存在 Token 可预测问题、任意文件上传导致存储型 XSS 等。此外它还有一个隐藏的“未完成功能”模块里面埋了更深的逻辑漏洞适合进阶练习。把 crAPI 当作自动化工具链的靶标最大的好处是漏洞点明确且可复现。你不用担心误报或环境干扰如果工具报告某个接口越权你在浏览器里手动操作一遍通常也能验证。这就像练射击必须有靶子crAPI 就是那个画着十环的靶子。3. 完整部署流程从零开始搭建自动化越权检测环境3.1 环境准备与 docker-compose 编排我在 Ubuntu 22.04 和 macOS 上都跑通过这套环境依赖项只有 Docker、Docker Compose 和 Git。如果你是 Windows 用户建议优先启用 WSL2 后安装 Docker Desktop否则容器网络模式可能会有兼容性问题。先把 crAPI 的源码拉下来git clone https://github.com/OWASP/crAPI.git cd crAPI/deploy/docker目录下已经预置好了 docker-compose.yml里面定义了 crAPI 的 Web 服务、后端 API、数据库、邮件服务和依赖的第三方组件。直接启动即可docker-compose up -d首次启动会拉取镜像耗时取决于网络。完成后访问http://localhost:8888应该能看到 crAPI 的登录页面。默认注册入口对外开放你随便用一个邮箱就能注册账号邮件验证环节在本地邮件服务中自动完成不需要真实邮箱。Hadrian 的部署方式是以源码形式运行因为它的爬虫模块需要调用本地浏览器内核打包成容器反而麻烦。我建议在宿主机上直接拉取源码并创建 Python 虚拟环境git clone https://github.com/owasp/hadrian.git cd hadrian python3 -m venv venv source venv/bin/activate pip install -r requirements.txtHadrian 依赖的库比较多包括 FastAPI、Playwright、httpx、sqlalchemy安装时间稍长。如果中途报缺少某个系统库通常是浏览器内核依赖缺失按提示安装即可。Vespasian 走 Docker 部署最省事git clone https://github.com/cckuailong/vespasian.git cd vespasian docker build -t vespasian .镜像构建完成后后续每次运行只需要通过docker run加载配置文件和目标清单即可。镜像本身不包含任何业务逻辑配置文件通过卷挂载注入这样便于你维护多套测试场景。3.2 crAPI 靶场的快速验证环境启动后不要急着上扫描器先手动过一遍 crAPI 的核心流程确保靶场本身是健康的。注册一个新账号登录绑定一台模拟车辆创建一条维修记录领取一张优惠券整个过程大约五分钟。这一步的目的很实在如果你对靶场的正常业务逻辑不熟悉后面看扫描报告时会一头雾水。比如 crAPI 的维修记录接口/identity/api/v2/vehicle/{vehicle_id}/repairs正常请求需要携带车辆 ID如果你在浏览器里把车辆 ID 改成另一辆车的 ID响应里会直接返回那辆车的维修记录这就是一个典型的水平越权点。我还建议在验证过程中顺便抓包。用 Burp Suite 或浏览器开发者工具记录下注册、登录、绑定车辆、查询维修记录这几个关键请求保存成 HAR 文件。后面配置 Vespasian 时这些请求的 URL、Header 格式、Token 获取方式都是现成的参考资料。3.3 Hadrian 的配置与首次扫描Hadrian 的运行入口是main.py它接受目标 URL 或域名作为参数。针对 crAPI直接指向http://localhost:8888即可python3 main.py -u http://localhost:8888 -o report.json首次扫描会经历几个阶段。先是资产发现Hadrian 会尝试从页面 URL、JavaScript 文件、robots.txt、API 文档中提取接口路径这一步大约耗时一到两分钟。然后是主动探测它会逐个请求发现的接口注入各种 Payload包括路径穿越、SQL 注入、参数污染、未授权访问等耗时取决于接口数量。最后是结果汇总生成 JSON 报告。我实测时crAPI 爆出的接口数量在 60 到 80 个之间。Hadrian 完整扫描一遍大约需要 10 分钟如果开启更深度的爬虫模式时间可能翻倍。扫描途中尽量不要手动访问 crAPI避免干扰爬虫的状态判断。3.4 Vespasian 的规则配置与验证执行Vespasian 的核心是一个 YAML 格式的规则文件在里面定义角色、请求链和断言逻辑。下面是一份简化配置演示如何验证 crAPI 的维修记录水平越权roles: - name: userA login: url: http://localhost:8888/identity/api/auth/login method: POST json: {email: userAexample.com, password: password} token_path: $.authentication_token - name: userB login: url: http://localhost:8888/identity/api/auth/login method: POST json: {email: userBexample.com, password: password} token_path: $.authentication_token requests: - name: fetch_repairs_cross_user url: http://localhost:8888/identity/api/v2/vehicle/{vehicle_id}/repairs method: GET roles: [userA, userB] params: vehicle_id: source: userA value: 1 assert: - type: status_code value: 200 - type: json_field path: $.repairs[0] present: true配置的语义是分别用 userA 和 userB 的 Token 去请求vehicle_id1的维修记录接口如果两个角色都能获取到数据说明该接口存在越权。Vespasian 会自动完成登录拿 Token、替换请求参数、比对响应这一整套动作。执行命令如下docker run -v $(pwd)/config.yaml:/app/config.yaml vespasian -c /app/config.yaml如果你配置了多个规则文件可以用-d参数指定目录Vespasian 会遍历执行并输出汇总报告。4. 越权检测中的关键配置与参数调优4.1 认证明文与 Token 提取路径的坑很多人在配置 Vespasian 时卡在 Token 提取上。crAPI 的登录接口返回的是 JSON 格式数据Token 在authentication_token字段但其他项目的返回结构可能完全不一样可能是嵌套在data对象里可能是 Base64 编码的 JWT甚至可能在响应 Header 的Set-Cookie中。Vespasian 使用 JSONPath 表达式提取 Token所以你必须先手动确认目标的响应结构。我常用的方法是在命令行用 curl 直接登录一次然后复制响应体到 JSONPath 在线解析器里测试提取表达式。一个典型的踩坑场景是响应里同时存在access_token和refresh_token如果你只配置了前者而接口实际校验的是后者Vespasian 会一直报 401很多人会误以为是工具问题其实是配置错了字段。另外还要注意 Token 的有效期。Hadrian 扫描耗时较长如果 Token 过期了后续探测可能会全部 401导致报告里出现大量“未授权”误报。解决办法是给 Hadrian 配置一个较长的会话保持时间或者在中间层加个 Token 刷新脚本。crAPI 的 Token 有效期是一小时正常情况下够用。4.2 请求链在复杂越权场景中的必要性单个请求只能验证“接口是否校验了当前用户的资源归属”但实际业务中的越权往往隐藏在多步骤操作里。比如“先创建维修预约再查看预约详情最后修改预约状态”这三个步骤如果前两步都正常第三步没有校验操作者身份那你单测任何一步都发现不了问题。Vespasian 支持在规则文件的请求列表中按顺序定义多个请求并允许把前一个请求的响应字段作为后一个请求的参数。我在验证 crAPI 的预约接口时配置了三步请求链第一步创建预约捕获返回的booking_id第二步查询预约参数带上booking_id第三步更新预约状态使用 userB 的 Token。如果第三步返回 200 且状态变更成功就说明存在垂直越权。这种场景用 Postman 也能手动测但 Vespasian 的优势在于批量。你可以配置几十条请求链一键跑完结果自动输出效率完全不在一个量级。4.3 响应相似度比对与误报抑制自动化越权检测最怕的是误报。有些接口虽然不会校验用户身份但它返回的数据本身是公开的比如天气接口、配置信息接口即使你用两个不同用户的 Token 都能拿到相同结果也不能算越权。Vespasian 的规则系统提供了多种断言方式包括状态码断言、响应体长度断言、JSON 字段断言你可以组合使用。最常用的是 JSON 字段存在性断言。比如你请求车辆信息接口如果响应中包含owner_id字段且该字段值不是你当前登录用户的 ID那就说明接口存在越权。这种断言比单纯比对响应长度精准得多。我还习惯再叠加一个响应体 hash 比对如果两个用户请求的响应体 hash 完全一致且响应中包含敏感字段那么大概率是越权。不过要注意有些接口的响应里会带上当前用户信息比如返回current_user: userA这会导致两个用户的响应体 hash 不同容易被工具误判为“无越权”。所以我在配置断言时通常会显式忽略这类无关字段把注意力集中在目标数据字段上。4.4 扫描深度与速度的权衡Hadrian 的配置项里有多个影响扫描深度的参数比如--max-depth控制爬虫跟踪链接的层级--threads控制并发数。默认配置下Hadrian 以 10 个并发线程扫描对 crAPI 这种小型靶场压力不大。但如果你扫描的是生产环境并发数过高容易触发 WAF 导致封 IP低并发又会让扫描时间成倍增加。我的习惯是先跑一遍快速模式--max-depth 2、--threads 5目的是摸清 API 资产全貌。拿到报告后再针对高危接口做精细化验证这时候用 Vespasian 按需配置请求链而不是盲目加大扫描深度。自动化工具在越权检测里的角色是“开荒”不是“精准打击”把重活交给人工研判会更合理。5. 常见问题与排错实录5.1 crAPI 启动失败或页面打不开现象执行 docker-compose up -d 后访问 localhost:8888 一直转圈或报连接拒绝。排查步骤先看容器状态执行docker-compose ps。如果某个容器没有处于 Up 状态用docker-compose logs查看日志。最常见的错误是数据库容器初始化未完成而后端 API 容器已经启动导致 API 无法连接数据库表现为登录接口返回 500。解决办法是重启后端容器或者干脆docker-compose down后重新up -d。端口冲突也是常见原因。crAPI 默认占用 8888、8889、8890 等端口如果你本机有服务占用了 8888需要修改 docker-compose.yml 里的端口映射。另外如果你在云服务器上部署记得在安全组里放行对应端口。5.2 Hadrian 爬虫无法抓取 crAPI 的接口现象Hadrian 扫描报告里只有首页和登录页API 接口列表是空的。原因通常有两个。第一Hadrian 默认从 HTML 页面中提取接口路径但 crAPI 的前端是单页应用接口调用都在 JavaScript 里动态拼接爬虫不一定能执行 JS 完成页面渲染。第二crAPI 的接口请求大多带有自定义 Header如果 Hadrian 没有携带这些 Header可能被后端拒绝。解决办法给 Hadrian 指定一个真实的浏览器上下文让它像人一样访问页面。在main.py的配置中启用 Playwright 的 Chromium 内核并把 User-Agent 调整为 Chrome 的默认值。同时把 crAPI 的 Swagger 文档地址手动提供给 Hadrian例如http://localhost:8888/openapi.json直接解析 API 定义比爬虫更有效。这里还想补充一点Hadrian 扫描结果中的接口路径并不总是完整的可能是因为它拼接相对路径时出了偏差。如果遇到这种问题可以直接打开 crAPI 的 Swagger 页面手动对照接口列表修正 Hadrian 报告里的路径。5.3 Vespasian 执行后没有输出或提示权限错误现象docker run 能正常启动但控制台只输出几行日志就结束报告中没有任何请求记录。这一步十有八九是配置文件格式问题。Vespasian 使用严格模式的 YAML 解析器如果你的 YAML 里出现了制表符缩进、重复键、错误的数据类型它会在解析阶段静默跳过整个规则。我的排查技巧是在本地用 Python 的 yaml 库验证配置文件import yaml with open(config.yaml, r) as f: data yaml.safe_load(f) print(data)如果打印出来是空字典或报错说明配置有问题。另外确认 docker 挂载路径是否正确。很多人在 Windows 上用$(pwd)会因为路径分隔符问题导致配置文件挂载失败建议在 Linux 或 WSL2 环境执行或者写绝对路径。5.4 扫描报告与实际漏洞不一致现象Hadrian 报告显示某个接口存在未授权访问但你手动用浏览器访问却返回 403或者 Hadrian 漏报手动测试却发现越权。先说漏报。Hadrian 的检测逻辑基于单一请求如果漏洞只在多步骤请求链中出现它就发现不了。这一点靠 Vespasian 补你必须在规则里把请求链定义完整单请求规则无法覆盖复杂逻辑。再说误报。Hadrian 可能会把“接口返回了统一错误信息但状态码是 200”误判为越权。比如 crAPI 的某些接口在 Token 无效时返回{error: unauthorized}但 HTTP 状态码是 200 而不是 401Hadrian 只检查状态码就会误报。处理方式是引入 Vespasian 的 JSON 字段断言当响应中出现error字段时直接判定为验证失败。还有一个经验是不要完全信任报告中的“高危”标记。工具只能给你一个候选清单真正的人工验证永远不可替代。把自动化工具当成“放大镜”而不是“裁判”。6. 从自动化扫描到人工研判我的实操经验总结整套工具链跑下来我最深刻的体会是越权检测的瓶颈从来不是工具数量而是对业务逻辑的理解。Hadrian 能帮你把几十个接口的越权嫌疑列出来Vespasian 能帮你验证八成以上的候选点但最终确认“这个越权是否真的具备危害性”“攻击者能否稳定利用”仍然需要你回到业务本身去看。具体来说拿到 Vespasian 的验证报告后我会按照危害程度人工复核一遍。先看接口是否涉及敏感数据比如手机号、身份证、维修记录、支付信息这类数据的越权风险最高。再看接口是否有写操作比如修改密码、解绑车辆、取消订单写操作型越权比只读型越权严重得多。最后看是否有前置条件限制比如接口是否需要特殊权限角色才能访问、是否进行了频率限制这些都会影响漏洞的可利用性。另一个建议是给 crAPI 靶场增加难度。默认靶场跑通之后你可以把容器里的数据库复制一份在本地跑一个持久化实例再结合 Postman 手动构造一些复杂的越权场景用来测试 Hadrian 和 Vespasian 的覆盖率。工具只有经过反复的靶场验证才能在真实项目里发挥稳定作用。如果你想把这套流程搬进实际的漏洞赏金项目记得先获得授权所有的越权测试必须限定在合法的测试范围内。自动化的高效建立在合规的前提下这个底线不能破。最后再分享一个小技巧把 Hadrian 的报告输出到 Elasticsearch配合 Kibana 做可视化可以看到所有接口的越权可疑点分布。我在一次内部测试中用这个方式在几分钟内定位到了两个隐藏在旧版本接口中的水平越权漏洞效率确实惊人。希望这套组合工具也能帮你把越权检测从“碰运气”变成“流水线”。