abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitea-artifact-v4-readall
Gitea 1.27.3 - Gitea
job_summary.go 已经通过 io.LimitReader 限制在 MaxJobSummarySize(1 MiB)。artifact v4 中的 parseProtobufBody 执行 io.ReadAll(ctx.Req.Body) 且没有任何上限。CreateArtifact、Finalize、List、Get、Delete 都经过它。仅凭一个随机用户 PAT 是不够的。你需要一个正在运行的 Actions 作业令牌。在 1.27.3 上,Fork-PR 作业仍然需要 NeedApproval。
Job-summary 学会了 LimitReader。Artifact v4 没有照搬。一个活跃作业可以 POST 一个 12 MiB 的 CreateArtifact,Gitea 会全部缓冲。
| ID | 暂无 CVE |
| CWE | CWE-400 |
| CVSS | 中危:6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H |
| 产品 | Gitea |
| 受影响版本 | 至 v1.27.3(146cc3e),且启用了 Actions |
| 认证 | 正在运行的 Actions 作业令牌 |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
从一个正在运行的 Actions 作业(自己的仓库,或已通过 NeedApproval 的 fork-PR),POST 一个任意大的 v4 CreateArtifact 请求体,迫使 Gitea 将其全部缓冲。同一实例上的 job-summary 已经会拒绝任何超过 1 MiB 的内容。
这就是对 Gitea 进程的内存压力。实验证明了缺失的上限(12 MiB -> 200)。它没有杀死进程。它不是 RCE。它不是未认证的。一个被盗的用户 PAT 如果没有活跃作业,无法到达此路径。
GHSA 浪潮之后遗留的映射包括 Actions 请求体处理。在 1.27.3 上,Fork-PR 作业仍然需要 NeedApproval,所以这不是未认证的 fork-PR 绕过。我查看了 Actions API 如何读取请求体。Job-summary 有一个数字。Artifact v4 没有。
我启动了 gitea/act_runner:0.2.13,预置了一个保持工作流,使作业令牌存在,然后 POST 了一个 12 MiB 的 CreateArtifact。HTTP 200 ok 加上 signedUploadUrl。然后 8 MiB 的 job-summary:400 invalid summary。GET /api/v1/version 仍然返回 200。Gitea 保持运行。实验环境的 mem_limit 是 1g。请求体上限设为 12 MiB,因此主机不是实验对象。仅主机执行器。没有 docker.sock。
已记录的弯路:没有作业令牌的 CreateArtifact(401 不是漏洞);进程杀死 / OOM(SUCCESS 是 12 MiB -> 200,而 8 MiB summary -> 400);将 signedUploadUrl 视为 RCE;fork-PR 未认证;反向 shell。都是表演。
cd lab
./run.sh
目标仅为 http://127.0.0.1:18135。compose 内的 ROOT_URL 是 http://gitea:3000/,以便 runner 可以注册。
v4-create status=200 sent=12582912
v4-unbounded-readall=1
job-summary status=400 sent=8388608 invalid summary cap=MaxJobSummarySize=1048576
gitea-still-up status=200
SUCCESS GITEA-ARTIFACT-V4-READALL
将 parseProtobufBody 用 io.LimitReader 包裹,设置一个 proto 大小的上限,与 MaxJobSummarySize 相同的模式。12 MiB 的 CreateArtifact 必须以与 8 MiB job-summary 已经失败相同的方式失败。
GNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。无担保。