
Forgejo 16.0.5 - Alta - Remoto - Leitura de arquivo - restore-repo segue file:// do lado do dump para anexos
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · forgejo-restore-file-open
Classe: Leitura de arquivo Alcance: Local
Forgejo 16.0.5 (8d24b7d) - Forgejo
forgejo restore-repo de um dump não confiável reescreve URLs de assets de release com filepath.Join(baseDir, download_url) bruto e prefixa file://. uri.Open ainda faz os.Open nesse caminho. --units vazio restaura releases. Gitea 1.27.0 adicionou localFileURL e pulou entradas de escape. Esse helper não está aqui.
O restore pelo operador de um dump não confiável copia um arquivo do host que o uid do forgejo consegue abrir para um anexo de release.
| ID | sem CVE ainda |
| Classe | Leitura de arquivo |
| Alcance | Local (operador forgejo restore-repo de um dump não confiável) |
| CWE | CWE-22 / CWE-73 |
| CVSS | Alto: 7.3 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N |
| Produto | Forgejo |
| Afetado | até v16.0.5 (8d24b7d); restore por operador local |
| Auth | restore por operador local de um dump não confiável |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Entregue ao operador um diretório de dump (ou já tenha o INTERNAL_TOKEN e um caminho que o servidor consiga ler). As units incluem releases / release_assets.
| Privilégio | Método / sink | Recon / integridade / disponibilidade | Comprovado em lab ou inferido |
|---|---|---|---|
Ler um arquivo do host que o uid do forgejo consegue abrir, via .. para fora do dump | release.yml download_url: ../FORGEJO-FILE-WITNESS.txt; o restore faz o join, uri.Open faz os.Open, os bytes são armazenados como witness.txt | Recon (confidencialidade de arquivo do host) | Comprovado em lab. O corpo do anexo é FORGEJO-RESTORE-FILE-OPEN-WITNESS. O decoy dentro do dump INSIDE-DUMP-NOT-HOST não foi servido |
| Mesmo resultado com um symlink plantado dentro do dump | O caminho após o join permanece sob baseDir; os.Open segue o link | Recon | Inferido a partir de uri.Open file -> os.Open. O lab usou .., não um symlink |
| Mesmo sink em patches de PR | pull_request.yml PatchURL é reescrito da mesma forma, depois uri.Open para repo/pulls/<n>.patch | Recon | Inferido a partir de restore.go GetPullRequests. O lab restaurou apenas releases |
| Leitores do repositório restaurado baixam o arquivo do host | GET /<owner>/<repo>/releases/download/<tag>/<name> | Recon | Comprovado em lab como labadmin Basic no repositório público restaurado |
Arquivos típicos do host: app.ini, INTERNAL_TOKEN, SECRET_KEY, senha do BD | o uid do forgejo consegue ler a árvore de configuração | Recon | Inferido. A testemunha do lab era um arquivo plantado ao lado do dump, não segredos reais |
Fechado aqui: LFI file:// no POST /repos/migrate ao vivo (DownloadFunc definido; PatchURL de PR verificado por prefixo contra a base HTTP do clone). Escape de join da raiz do dump via DownloadURL absoluto (em Go filepath.Join("/dump", "/etc/passwd") permanece /dump/etc/passwd). Restore HTTP não autenticado (apenas CLI / token interno). Empacotamento de app.ini no dump de backup (segredos por design, modo de arquivo 0600). Não é LPE de SO. Não é LFI remoto.
Eu tinha duas ideias de restore. Primeiro testei mentalmente o join absoluto do Gitea. O filepath.Join do Go não descarta um segundo argumento absoluto como o os.path.join do Python faz. A entrada que funciona é .. relativo. O localFileURL do Gitea não está nesta árvore.
Caminhos errados já registrados: escape de join da raiz do dump via um DownloadURL absoluto; LFI file:// no migrate ao vivo; X-Forgejo-Internal-Auth (o restore é CLI como o uid do forgejo, não /api/internal); tratar o restore HTTP como remoto não autenticado; um reverse shell. Teatro.
python3 forgejo-restore-file-open-Abraxas-Labs.py
ou:
cd lab
./run.sh
Alvo apenas http://127.0.0.1:19340. Imagem codeberg.org/forgejo/forgejo:16.0.5. Testemunha 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
Contenha os caminhos após o join sob baseDir depois de EvalSymlinks (Gitea PR 38215 localFileURL). Recuse ... Não siga symlinks do lado do dump para fora do dump. Remova file:// de uri.Open exceto por um helper enraizado no dump.
restore.go · uri.goGNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.