abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-restore-file-open
技术文章:https://abraxaslabs.tech/research/forgejo-restore-file-open
类别: 文件读取 触达范围: 本地
Forgejo 16.0.5(8d24b7d)- Forgejo
对不可信转储执行 forgejo restore-repo 时,会用原始的 filepath.Join(baseDir, download_url) 重写发布资源 URL,并加上 file:// 前缀。uri.Open 仍会对该路径执行 os.Open。空的 --units 会恢复发布。Gitea 1.27.0 添加了 localFileURL 并跳过转义条目。该辅助函数在此处不存在。
操作员恢复不可信转储时,会将 forgejo uid 可打开的主机文件复制到发布附件中。
| ID | 暂无 CVE |
| 类别 | 文件读取 |
| 触达范围 | 本地(操作员对不可信转储执行 forgejo restore-repo) |
| CWE | CWE-22 / CWE-73 |
| CVSS | 高危:7.3 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N |
| 产品 | Forgejo |
| 受影响版本 | 至 v16.0.5(8d24b7d);本地操作员恢复 |
| 认证 | 本地操作员恢复不可信转储 |
| 许可证 | GNU Affero GPL v3.0 |
| 实验环境 | 仅 127.0.0.1 |
将转储目录交给操作员(或已拥有 INTERNAL_TOKEN 以及服务器可读取的路径)。单元包括 releases / release_assets。
| 权限 | 方法 / 汇聚点 | 侦察 / 完整性 / 可用性 | 实验验证或推断 |
|---|---|---|---|
通过 .. 逃逸出转储目录,读取 forgejo uid 可打开的主机文件 | release.yml download_url: ../FORGEJO-FILE-WITNESS.txt;恢复时拼接,uri.Open 执行 os.Open,字节被存储为 witness.txt | 侦察(主机文件机密性) | 实验验证。附件正文为 FORGEJO-RESTORE-FILE-OPEN-WITNESS。转储内诱饵 INSIDE-DUMP-NOT-HOST 未被提供 |
| 在转储内植入符号链接获得相同结果 | 拼接后的路径仍位于 baseDir 下;os.Open 会跟随该链接 | 侦察 | 根据 uri.Open 的 file -> os.Open 推断。实验使用的是 ..,而非符号链接 |
| 对 PR 补丁使用相同汇聚点 | pull_request.yml 的 PatchURL 以相同方式重写,然后 uri.Open 写入 repo/pulls/<n>.patch | 侦察 | 根据 restore.go 的 GetPullRequests 推断。实验仅恢复了发布 |
| 恢复后仓库的读者可下载该主机文件 | GET /<owner>/<repo>/releases/download/<tag>/<name> | 侦察 | 实验验证:以 labadmin Basic 身份访问恢复后的公开仓库 |
典型主机文件:app.ini、INTERNAL_TOKEN、SECRET_KEY、数据库密码 | forgejo uid 可读取配置目录树 | 侦察 | 推断。实验中的见证文件是放置在转储旁的植入文件,而非真实机密 |
此处已关闭:实时 POST /repos/migrate 的 file:// LFI(已设置 DownloadFunc;PR PatchURL 会针对克隆 HTTP 基址进行前缀检查)。绝对 DownloadURL 转储根拼接逃逸(Go 的 filepath.Join("/dump", "/etc/passwd") 仍为 /dump/etc/passwd)。未认证 HTTP 恢复(仅 CLI / 内部令牌)。备份 dump 打包 app.ini(按设计包含机密,归档模式 0600)。不是操作系统 LPE。不是远程 LFI。
我有两个恢复思路。我先在脑中针对 Gitea 的绝对路径拼接进行了实验。Go 的 filepath.Join 不会像 Python 的 os.path.join 那样丢弃绝对的第二参数。有效的输入是相对路径 ..。Gitea 的 localFileURL 不在此代码树中。
已记录的误判:通过绝对路径 DownloadURL 实现 dump-root 路径拼接逃逸;实时迁移 file:// LFI;X-Forgejo-Internal-Auth(恢复操作是以 forgejo uid 通过 CLI 执行的,而非 /api/internal);将恢复 HTTP 视为远程未认证;一个反向 shell。纯属表演。
python3 forgejo-restore-file-open-Abraxas-Labs.py
或:
cd lab
./run.sh
仅针对 http://127.0.0.1:19340。镜像 codeberg.org/forgejo/forgejo:16.0.5。见证 FORGEJO-RESTORE-FILE-OPEN-WITNESS。
IOC asset name='witness.txt' ...
IOC download status=200 bytes=34 snippet=b'FORGEJO-RESTORE-FILE-OPEN-WITNESS\n'
SUCCESS forgejo-restore-file-open how=live ..-join file:// os.Open FORGEJO-RESTORE-FILE-OPEN-WITNESS
在 EvalSymlinks 之后,将拼接后的路径限制在 baseDir 之下(Gitea PR 38215 localFileURL)。拒绝 ..。不要跟随 dump 侧的符号链接离开 dump 目录。从 uri.Open 中移除 file://,仅保留一个以 dump 根目录为基准的辅助函数。
restore.go · uri.goGNU Affero GPL v3.0。参见 LICENSE。仅限回环实验环境。不提供任何担保。