
Prueba de concepto y laboratorio para un SSRF autenticado en el endpoint repo migrate de Gitea, donde git sigue redirecciones HTTP hacia git HTTP en loopback y filtra objetos internos.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitea-git-redir-ssrf
Gitea 1.27.3 - Gitea
IsMigrateURLAllowed es un net.LookupIP de un solo uso sobre la URL que escribiste. Los bytes luego pasan por git clone --mirror. Se supone que HandleGitCmdHTTPRedirection impide que git siga ese salto. No hace nada. El comentario es el hallazgo: dejaron http.followRedirects=false desactivado porque GitLab responde 301 sin .git. La obtención del pull-mirror llama al mismo no-op.
Un usuario autenticado puede migrar desde un host cebo en la lista de permitidos y git sigue el 302 hacia git HTTP en loopback. Los objetos internos terminan en un repositorio que él controla.
| ID | sin CVE aún |
| CWE | CWE-918 |
| CVSS | Alto: 7.7 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N |
| Producto | Gitea |
| Afectado | hasta v1.27.3 (146cc3e) |
| Autenticación | autenticado (registro abierto por defecto) |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1 |
Registrarse, migrar desde una URL de aspecto externo que responde 302 hacia http://127.0.0.1:.../internal.git. La migración directa a loopback se deniega. El clon que sigue la redirección no. El archivo testigo termina en su repositorio.
No es lectura de disco mediante file://. No es X-Gitea-Internal-Auth en /api/internal (git no establecerá esa cabecera). No es RCE no autenticado. No es RCE de metadatos a menos que demuestres por separado que git almacenó el cuerpo.
Restos de la misma etiqueta: keys IDOR, hostmatcher 0.0.0.0/8.
La v1.27.3 cerró la oleada de GHSA de 2026: CVE-2026-60004 (RCE por hook diffpatch, CISA KEV), CVE-2026-59774 (#+INCLUDE de Org-mode sin autenticación), controles de Actions en fork-PR, X-WEBAUTH-USER por defecto en proxy inverso. Mantente en 1.27.3+ por esos. Aun así me quedé en esa etiqueta.
CVE-2026-59765 corrigió uri.Open de Go. CVE-2026-22874 corrigió reservedIPNets de Go. El redirector de git sigue siendo un FIXME. El "disable HTTP redirects on pull mirror sync" del changelog no es esta función.
El laboratorio pone Gitea en 8.8.4.2 para que un host cebo en 8.8.4.10 parezca externo al hostmatcher. El git HTTP interno se enlaza solo a loopback en el netns de Gitea (network_mode: service:gitea, puerto 9418). La migración directa a 127.0.0.1 debe fallar. El clon que sigue la redirección debe tener éxito. redir.py responde 302 a /bait.git hacia http://127.0.0.1:9418/internal.git. El archivo testigo WITNESS contiene GHSA-GITEA-GIT-REDIR-SSRF.
Caminos equivocados ya registrados: ALLOW_LOCALNETWORKS true (entonces la lista de permitidos desaparece); file://; X-Gitea-Internal-Auth; una reverse shell. Teatro. La migración directa a loopback denegada es el control.
Los bugs del cliente parecen bugs del producto. Un helper que ensombrece http.client nunca envía un paquete. .recv() sobre un HTTPResponse no es .read(). Lo menciono una vez porque costó tiempo y pareció, por un minuto, que la 1.27.3 había terminado el trabajo.
cd lab
./run.sh
Objetivo solo http://127.0.0.1:18103. ALLOW_LOCALNETWORKS=false.
negative-loopback status=422 You can not import from disallowed hosts
migrate-bait status=201 clone_addr=http://8.8.4.10/bait.git
fetch raw/WITNESS status=200 GHSA-GITEA-GIT-REDIR-SSRF
SUCCESS Gitea #2 git HTTP redirect SSRF
No trates el DNS en el momento del envío como la frontera. Fuerza http.followRedirects=false (y normaliza las URLs de clonado a .git para que GitLab siga funcionando), o haz proxy del git HTTP a través de un dialer que vuelva a ejecutar hostmatcher en cada salto.
HandleGitCmdHTTPRedirection · IsMigrateURLAllowedGNU Affero GPL v3.0. Ver LICENSE. Solo laboratorio en loopback. Sin garantía.