abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-keys-idor
类别: IDOR 可达性: 远程
Forgejo 16.0.5 (8d24b7d) - Forgejo
GET /api/v1/user/keys/{id} 位于当前用户组(reqToken,用户作用域)。该处理程序仍按数字 ID 加载 public_key,且没有所有者检查。同一张表存放用户密钥、部署密钥和主体。此版本上的 GPG 处理正确:GetGPGKeyForUserByID(ctx, ctx.Doer().ID, id)。私有额外字段受到限制。但公钥材料、标题和指纹没有。ID 是顺序的。
一个 read:user 令牌遍历 1、2、3,即可清点他人的 SSH 密钥和部署密钥。
| ID | 暂无 CVE |
| 类别 | IDOR |
| 可达性 | 远程(已认证的 read:user / 会话) |
| CWE | CWE-639 |
| CVSS | 高危:7.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
| 产品 | Forgejo |
| 受影响版本 | 至 v16.0.5 (8d24b7d) |
| 认证 | 已认证(read:user 令牌或会话) |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
注册或使用任意账户,生成一个 read:user 令牌(或使用会话 cookie),遍历 /api/v1/user/keys/{id}。他们就能获取不属于自己的密钥的标题、指纹和公钥材料。他们无法获取私钥。他们无法获取 shell。他们可以清点谁拥有什么访问权限。
| 权限 | 方法 / 汇聚点 | 侦察 / 完整性 / 可用性 | 实验验证或推断 |
|---|---|---|---|
| 以外部所有者身份读取其他用户的 SSH 公钥标题、指纹和密钥材料 | GET /api/v1/user/keys/{id} | 侦察(公钥清单的机密性) | 实验验证。id 1 上的见证标题 FORGEJO-KEYS-IDOR-WITNESS;攻击者列表仅有 id 2 |
| 以同样方式清点部署密钥 | 同一处理程序,public_key 中的 KeyTypeDeploy 行(OwnerID 0) | 侦察 | 从表推断。实验植入的是用户 SSH 密钥,而非部署密钥 |
| 读取 SSH 证书主体 | 同一处理程序,KeyTypePrincipal 行。ListPublicKeys 排除此类型 | 侦察 | 从表推断 |
| 查看属于受限或私有用户的密钥 | 此查询没有可见性检查 | 侦察 | 从处理程序推断 |
额外 JSON(user、key_type、read_only) | appendPrivateInformation 仅在管理员或所有者时执行 | 侦察 | 实验验证已关闭:非所有者响应没有 user 字段 |
此路由上已关闭:私钥材料、shell、GET /users/{username}/keys(按用户名作用域的公开列表)、GPG GET /api/v1/user/gpg_keys/{id}(外部 id 返回 404)、DeletePublicKey(所有者/管理员 403)。当 RepoID 不匹配时,跨仓库 GET /repos/{owner}/{repo}/keys/{id} 返回 404。
v16.0.5 安全补丁(#14370)是 git-apply RCE 和 OpenID CSRF。它们没有关闭此查询。与 gitea-user-keys-idor 同类,在此处独立地仍然开放。
在 2026-09 浪潮之后,我锁定了 Forgejo v16.0.5。Gitea 1.27.3 仍有此查询。Forgejo 已经分化,因此我重新阅读了当前用户密钥处理程序并与 GPG 对比,而不是照搬 Gitea 的包。GPG 对外部 id 返回 404。SSH 不会。
已记录的弯路:将攻击者自己的列表视为泄露(并非如此——列表有作用域,按 id 的 GET 没有);将安装程序上的 DISABLE_REGISTRATION=true 视为关闭(任何现有账户就足够);反向 shell。都是做戏。
python3 forgejo-keys-idor-Abraxas-Labs.py
或:
cd lab
./run.sh
目标仅为 http://127.0.0.1:19310。镜像 codeberg.org/forgejo/forgejo:16.0.5。两个账户。见证 FORGEJO-KEYS-IDOR-WITNESS。
IOC planted victim-id=1 attacker-id=2
IOC attacker-list status=200 ... title=attacker-own-key
IOC get id=1 status=200 ... FORGEJO-KEYS-IDOR-WITNESS
IOC gpg-neg id=1 status=404
SUCCESS forgejo-keys-idor victim-id=1 get-http=200 list-has-id=no gpg-http=404 FORGEJO-KEYS-IDOR-WITNESS
除非 key.OwnerID == ctx.Doer().ID(或站点管理员),否则返回 404。在此路由上拒绝 KeyTypeDeploy / KeyTypePrincipal。与 GetGPGKeyForUserByID 保持一致。
GetPublicKeyGNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。无担保。