OWASP API Top10 实战:CrAPI 靶机指南

本文最后更新于 2026年3月12日 下午

部署

1
2
# 项目地址:
https://github.com/OWASP/crAPI

通过 docker 容器部署:

1
2
3
4
5
git clone https://github.com/OWASP/crAPI.git

cd crAPI/deploy/docker
docker compose pull
docker compose -f docker-compose.yml --compatibility up -d

对象级权限控制缺失(BOLA)漏洞

BOLA(Broken Object Level Authorization)是 OWASP API Top 10 中排名第一的漏洞类型,指的是系统在处理对象访问时,没有正确验证用户是否具备访问该对象的权限。

挑战 1 - 获取其他用户车辆的详细信息

目标: 枚举获得其他用户车辆的敏感信息。

访问:https://127.0.0.1:8443/ 注册用户并登录。

访问:http://127.0.0.1:8025/ 找到需要添加的车辆信息,将其添加到用户信息中。

点击 Refresh Location 可查看车辆位置信息。

通过 burp 抓取整个过程的数据包,发现其通过 API 请求 carId 可获车辆位置信息。

抓包访问社区模块可发现大量车辆 carId,修改数据包 carId 可遍历其余用户车辆位置信息。

挑战 2 - 获取其他用户的维修报告

目标: 访问其他用户提交的维修报告。

在联系技工的位置,输入任意内容,然后点击历史维修记录,抓包查看报告,通过更改请求 ID 可获取其他用户报告内容。

新提交的报告 ID 为 6,可以向前进行枚举,发现 ID 为 5 是 james 用户的车辆报告。

用户身份验证失效(Broken Authentication)

系统在用户身份验证流程中存在缺陷,导致攻击者可以绕过登录、冒充他人身份或接管账户。

挑战 3 - 重置其他用户密码

目标: 重置他人密码并接管账户。

通过挑战 1 可以得到其他用户的邮箱信息,利用忘记密码功能,输入用户邮箱,使用 burp 不断枚举验证码,可更改任意用户密码。

使用 v3 接口尝试枚举爆破验证码会存在次数限制。

尝试更改 API 版本至 v2,可一直执行爆破,并成功修改用户密码。

登录 Robot 用户后台。

过度数据泄露(Excessive Data Exposure)

后端返回了超过业务所需的敏感数据,而前端仅做了隐藏处理,没有真正限制数据输出。

挑战 4 - 找到泄露敏感信息的 API

目标: 发现返回其他用户敏感信息的接口。

该挑战在挑战 1 中已经体现,通过社区功能可查看用户的车辆 ID 信息。

挑战 5 - 泄露视频内部属性

目标: 找到视频对象中不应暴露的内部属性。

在个人中心上传 mp4 视频,然后抓包刷新访问,在响应头泄漏了视频属性信息。

速率限制(Lack of Rate Limiting)

系统没有限制单位时间内的请求次数,导致攻击者可以无限制地自动化发送请求进行攻击。

挑战 6 - 执行 L7 DoS 攻击

目标: 利用联系技工接口发起应用层拒绝服务攻击。

抓取联系技工数据包,在数据包 POST 请求中发现存在是否重试和重试次数的参数,修改参数请求不存在的 API 可实现 DOS 攻击。

功能级权限控制缺失(BFLA)

系统没有对不同角色的功能权限进行严格控制,导致低权限用户可以访问高权限功能接口。

挑战 7 - 删除其他用户的视频

目标: 删除他人视频。

在用户设置界面,测试修改视频名称会使用 PUT 方法,尝试在该接口使用 DELETE 方法,系统提示需要 admin 接口,修改 API 接口为 admin,可成功删除视频,通过不断枚举 ID 可删除其他用户视频。

删除其他用户视频。

大量分配漏洞(Mass Assignment)

后端在接收用户输入时,未对可修改字段进行限制,导致攻击者可以修改本不应该由用户控制的属性。

挑战 8 - 免费获得商品

目标: 未实际退货却获得退款。

通过用户购买界面购买任意商品,然后点击商品退款选项,系统会提示需要审核。

分析整个过程抓取的数据包,发现购买成功后会返回商品 ID 和剩余价格。

之后根据商品 ID 执行退款操作。

此时再次访问商品可以发现商品处于待退款的状态,按照前面挑战的案例,可尝试 PUT 方法修改退款状态。

在 PUT 数据中指定任意状态字符串,系统提示仅允许三种状态,很明显 returned 代表成功退款状态。

利用 PUT 方法修改商品为成功退款,即使没有通过二维码的验证也可以实现商品的退款,这意味着不需要管理员审核也可以成功退款,实现了零元购。

此时的账户依然是 100 美元。

挑战 9 - 增加余额 1000+ 美元

目标: 在挑战 8 基础上扩大收益。

通过挑战 8 成功实现了零元购,猜测是否可以使用单个商品的价格购买多个商品,既然通过 PUT 方法可以修改购买商品的退款状态,大概率也可以修改商品的购买数量。

重新购买商品,然后点击商品详情界面,抓取商品详情界面数据包,通过 PUT 方法修改购买的商品数量。

将数量修改为 10000,按照挑战 9 的步骤,执行退款即可获得 100090 美元。

挑战 10 - 修改视频内部属性

目标: 修改视频隐藏字段。

用户偏好设置中设置完视频后,存在更改视频名称的功能,该功能依然通过 PUT 方法更改,同理,也可以通过 PUT 方法修改视频的内部属性。

思考: 这里可通过 PUT 方法修改视频属性为反弹 shell,但一直没有找到触发执行的条件,有师傅知道如何利用可以留言告知一下,非常感谢。

服务器端请求伪造(SSRF)

攻击者诱导服务器向任意地址发起请求,从而访问内部网络或敏感资源。

挑战 11 - 触发 SSRF

目标: 让 crAPI 请求:百度。

在联系工程师的地方通过抓包发现 POST 数据包含指定的 API URL,将请求的 URL 更换为百度,可触发 SSRF 攻击。

NoSQL 注入(NoSQL Injection)

攻击者通过构造特殊输入,操控 NoSQL 查询语句,从而绕过认证或获取未授权数据。

挑战 12 - 免费优惠券

目标: 绕过验证直接获取优惠券。

容器使用了 MongoDB 数据库,对于 NoSQl 类型的数据库注入,可尝试通过 $ne、$mg 关键词注入。

常用 payload:

  • $gt:"" :非空字符串
  • $ne:null :非 null
  • $regex:".+" :至少 1 字符
1
2
# 查询 coupon_code 字段大于空字符串的所有文档
{"coupon_code":{"$gt": ""}}

SQL 注入(SQL Injection)

攻击者通过构造恶意输入,干扰数据库查询逻辑,从而读取、修改或破坏数据库数据。

挑战 13 - 重复兑换优惠券

目标: 通过数据库修改重复兑换优惠券。

一旦成功领取了优惠券,再次输入会提示已经领取,请尝试其他优惠券。

抓取输入优惠券的数据包,发现会跳转至另外一个 API 接口。

我们输入单引号服务器会返回 500 错误,而输入恒成立语句则返回正常。

1
{"coupon_code":"1' or '1'='1","amount":75  }

按照靶机的原本思路需要执行 SQL 注入得到一些表信息,但是尝试查询服务器总返回 500,这里执行去容器执行查看。

1
docker exec -it postgresdb psql -U admin -d crapi

查看数据库 applied_coupon 表,发现 ID 为 8 的用户已经申请了邀请码,二 ID 为 8 正式我们注册的用户,所以系统才会提示我们无法重新领取。

只需要利用 SQL 注入堆叠查询删除该表即可重复领取。

1
"coupon_code":"TRAC075';DELETE FROM applied_coupon WHERE coupon_code='TRAC075';--"

虽然服务器 500 错误,但实际在数据库已经成功删除,可以再次领取优惠券。

未经身份验证的访问(Unauthenticated Access)

挑战 14 - 未鉴权接口

系统未对接口进行身份验证,攻击者无需登录即可直接访问敏感功能或数据。

目标: 发现无需身份验证的 API。

有很多不需要鉴权就能访问的 API 接口,比如挑战 2 中查看其他用户报告。

JWT 漏洞(JWT Vulnerabilities)

在 JSON Web Token 的生成、验证或使用过程中存在安全缺陷,导致攻击者可伪造身份、绕过认证或提权。

挑战 15 - 伪造 JWT

目标: 构造合法 JWT 获取完全访问权限。

JWT 由三部分组成:Header(头部)、Payload(载荷)和 Signature(签名)。

  • Header 和 Payload 使用 Base64URL 编码,可以被解码查看内容,因此默认不具备保密性。
  • Signature 是根据 Header 中声明的签名算法(如 HS256、RS256),对 base64url(header) + "." + base64url(payload) 进行数字签名生成的,用于保证数据的完整性和来源可信性。
  • 服务端在接收到 JWT 后,会重新计算签名并进行比对,若签名一致,则说明 Token 未被篡改且由可信方签发,从而基于 Payload 中的身份信息完成鉴权。

可以尝试直接修改 JWT 头部,将签名算法设置为 none,这样服务器就会直接信任载荷部分。

1
2
3
4
# 第一部分
{"alg":"none"}
# 第二部分,邮箱可通过社区泄漏的信息获取
{"sub":"adam007@example.com","iat":1771996721,"exp":1772601521,"role":"user"}

分别将第一部分和第二部分使用 base64 编码,然后通过点进行拼接组成新的 JWT。

1
eyJhbGciOiJub25lIn0=.eyJzdWIiOiJhZGFtMDA3QGV4YW1wbGUuY29tIiwiaWF0IjoxNzcxOTk2NzIxLCJleHAiOjE3NzI2MDE1MjEsInJvbGUiOiJ1c2VyIn0=.

通过新生成的 JWT 可登录任意用户。

Thanks

如果我的文章对您有帮助或您希望与我更多交流,欢迎点击「关于我」,通过页面中的微信公众号、邮箱或 Discord 与我联系;若您发现文章中存在任何错误或不足之处,也非常欢迎通过以上方式指出,在此一并致以衷心的感谢。 😊🫡

最后,祝您生活愉快!🌞✨


OWASP API Top10 实战:CrAPI 靶机指南
https://www.f0nesec.top/2026/02/25/owasp-api/
作者
F0ne
发布于
2026年2月25日
许可协议