
Proof-of-Concept und Lab für eine authentifizierte SSRF im Repo-Migrate-Endpunkt von Gitea, bei der git HTTP-Redirects in lokales git HTTP folgt und interne Objekte preisgibt.
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitea-git-redir-ssrf
Gitea 1.27.3 - Gitea
IsMigrateURLAllowed ist ein einmaliger net.LookupIP auf die von dir eingegebene URL. Die Bytes gehen dann durch git clone --mirror. HandleGitCmdHTTPRedirection soll git davon abhalten, diesem Hop zu folgen. Es tut nichts. Der Kommentar ist der Befund: Sie haben http.followRedirects=false weggelassen, weil GitLab ohne .git mit 301 antwortet. Der Pull-Mirror-Fetch ruft dieselbe No-Op auf.
Ein angemeldeter Benutzer kann von einem allow-gelisteten Köder-Host migrieren, und git folgt dem 302 in Loopback-git-HTTP. Interne Objekte landen in einem Repository, das ihm gehört.
| ID | noch keine CVE |
| CWE | CWE-918 |
| CVSS | Hoch: 7.7 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N |
| Produkt | Gitea |
| Betroffen | bis v1.27.3 (146cc3e) |
| Auth | authentifiziert (standardmäßig offene Registrierung) |
| Lizenz | GNU Affero GPL v3.0 |
| Lab | nur 127.0.0.1 |
Registrieren, von einer extern wirkenden URL migrieren, die mit 302 auf http://127.0.0.1:.../internal.git umleitet. Direkte Migration zu Loopback wird verweigert. Der Redirect-gefolgte Clone nicht. Die Witness-Datei landet in seinem Repository.
Kein file://-Festplattenlesen. Kein X-Gitea-Internal-Auth auf /api/internal (git setzt diesen Header nicht). Kein unauthentifizierter RCE. Kein Metadata-RCE, es sei denn, du zeigst separat, dass git den Body gespeichert hat.
Überreste desselben Tags: keys IDOR, hostmatcher 0.0.0.0/8.
v1.27.3 schloss die GHSA-Welle 2026: CVE-2026-60004 (diffpatch-Hook-RCE, CISA KEV), CVE-2026-59774 (unauth Org-Mode #+INCLUDE), Fork-PR-Actions-Gates, Reverse-Proxy X-WEBAUTH-USER-Standard. Bleib für diese auf 1.27.3+. Ich habe trotzdem auf diesem Tag gesessen.
CVE-2026-59765 behob Go uri.Open. CVE-2026-22874 behob Go reservedIPNets. Gits Redirector ist immer noch ein FIXME. Der Changelog-Eintrag „disable HTTP redirects on pull mirror sync" ist nicht diese Funktion.
Das Lab platziert Gitea auf 8.8.4.2, damit ein Köder-Host auf 8.8.4.10 für hostmatcher extern aussieht. Internes git HTTP bindet nur Loopback im Gitea-Netns (network_mode: service:gitea, Port 9418). Direkte Migration zu 127.0.0.1 muss fehlschlagen. Der Redirect-gefolgte Clone muss gelingen. redir.py leitet /bait.git mit 302 auf http://127.0.0.1:9418/internal.git um. Die Witness-Datei WITNESS enthält GHSA-GITEA-GIT-REDIR-SSRF.
Bereits dokumentierte Irrwege: ALLOW_LOCALNETWORKS true (dann ist die Allow-List weg); file://; X-Gitea-Internal-Auth; eine Reverse Shell. Theater. Die verweigerte direkte Loopback-Migration ist die Kontrolle.
Client-Bugs sehen wie Produkt-Bugs aus. Ein Helper, der http.client überschattet, sendet nie ein Paket. .recv() auf einer HTTPResponse ist nicht .read(). Ich erwähne das einmal, weil es Zeit gekostet hat und für eine Minute so aussah, als hätte 1.27.3 die Sache erledigt.
cd lab
./run.sh
Ziel nur 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
Behandle DNS zum Submit-Zeitpunkt nicht als die Grenze. Erzwinge http.followRedirects=false (und normalisiere Clone-URLs zu .git, damit GitLab weiterhin funktioniert), oder proxy git HTTP durch einen Dialer, der hostmatcher bei jedem Hop erneut ausführt.
HandleGitCmdHTTPRedirection · IsMigrateURLAllowedGNU Affero GPL v3.0. Siehe LICENSE. Nur Loopback-Lab. Keine Gewährleistung.