
Lab de preuve de concept démontrant une SSRF authentifiée dans la liste d'autorisation hostmatcher de Gitea, où un webhook vers http://0.0.0.1 atteint des services loopback que 127.0.0.1 ne peut pas atteindre.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitea-hostmatcher-0000-ssrf
Gitea 1.27.3 - Gitea
CVE-2026-22874 a ajouté reservedIPNets. CGNAT, TEST-NET, NAT64, Teredo, Azure WireServer. De vraies plages. Pas le bloc 0.0.0.0/8 de la RFC 6890, l'ancien « this network ». L'IANA le publie toujours. Le IsGlobalUnicast de Go est true pour 0.0.0.1. Ce n'est pas IsLoopback (127.0.0.0/8). Ce n'est pas IsPrivate. La liste d'autorisation externe par défaut le traite comme l'internet public. Linux livrera 0.0.0.1 à un socket local si cette adresse est sur lo. Même listener, deux noms.
Un utilisateur connecté peut webhooker http://0.0.0.1 et lire le corps HTTP depuis l'historique des hooks. 127.0.0.1 sur le même port est refusé.
| ID | pas encore de CVE |
| CWE | CWE-918 |
| CVSS | High: 7.7 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N |
| Produit | Gitea |
| Affecté | jusqu'à v1.27.3 (146cc3e) ; résidu de CVE-2026-22874 |
| Auth | utilisateur connecté pouvant créer un webhook de dépôt |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
S'inscrire (inscription ouverte par défaut), créer un dépôt, pointer un webhook vers http://0.0.0.1:<local-port>/, le tester, et lire le corps de la réponse depuis l'historique des hooks. C'est du HTTP loopback que 127.0.0.1 sur le même port ne peut pas atteindre : tout ce qui écoute dans le netns de Gitea et qui s'est lié plus largement que le loopback, y compris des services que l'opérateur croyait « localhost only » parce qu'ils bloquaient 127.0.0.0/8.
Cela ne définit pas X-Gitea-Internal-Auth. Ce n'est pas une RCE en soi. C'est un corps HTTP complet depuis une adresse que la liste d'autorisation qualifie encore d'externe.
v1.27.3 est la build qui a fermé la vague de GHSA 2026. Je me suis quand même arrêté sur ce tag. Les patchs qui ajoutent une allow-list ou une deny-list sont un cadeau : tu lis la liste, puis tu demandes ce que l'IANA a encore que la liste a oublié. Deux résidus avaient déjà des labs sur cet arbre (keys IDOR et git-redirect SSRF). Le tableau des résidus de ce post listait un webhook vers http://0.0.0.1/ comme une carte. C'est le SUCCESS.
La livraison de webhook stocke le corps HTTP dans l'historique des hooks. C'est un meilleur oracle que git clone, qui se résume surtout à « est-ce que le fetch a marché ». J'ai mis un oracle dans le netns de Gitea sur le port 8080, ajouté 0.0.0.1/8 sur lo avec NET_ADMIN, et créé deux webhooks. Contrôle négatif d'abord.
Fausses pistes déjà consignées : traiter le HTTP 201 de création de webhook comme l'oracle (l'historique est l'oracle) ; la livraison vers 127.0.0.1 qui réussit (ce serait un autre bug - le lab exige qu'elle soit refusée) ; atteindre /api/internal avec X-Gitea-Internal-Auth ; un reverse shell. Du théâtre. Le témoin est GITEA-0000-SSRF dans l'historique des hooks.
cd lab
./run.sh
Cible uniquement http://127.0.0.1:18131. L'oracle partage le netns de Gitea sur le port 8080. run.sh ajoute 0.0.0.1/8 sur lo.
create-hook name=neg-loopback status=201
negative-control 127.0.0.1 blocked
create-hook name=hit-0000 status=201
poll id=2 witness=True
SUCCESS GITEA-HOSTMATCHER-0000
Ajouter 0.0.0.0/8 à reservedIPNets, ou arrêter de traiter IsGlobalUnicast comme « sûr à contacter ». 0.0.0.1 doit être refusé de la même manière que 127.0.0.1.
hostmatcher.goGNU Affero GPL v3.0. Voir LICENSE. Lab loopback uniquement. Aucune garantie.