
Gitea restore-repo file:// स्थानीय फ़ाइल समावेशन (CWE-73) के लिए प्रूफ-ऑफ-कॉन्सेप्ट जो अविश्वसनीय डंप के बाहर सिमलिंक लक्ष्यों को रिलीज़ अटैचमेंट में कॉपी करता है।
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · gitea-restore-file-open
Gitea 1.27.3 - Gitea
CVE-2026-59765 ने OpenWithClient पर एक hostmatcher HTTP client लगाया। file:// शाखा उस client को अनदेखा करती है और os.Open को कॉल करती है। एक dump के restore में कोई DownloadFunc नहीं होता। gitea_uploader.go फिर rewritten file:// URL को खोलता है। os.Open एक dump-side symlink का अनुसरण करता है। Join dump के अंतर्गत ही रहता है। Symlink नहीं रहता।
एक अविश्वसनीय dump का ऑपरेटर restore symlink target को एक release attachment में कॉपी कर देता है। Gitea uid के रूप में, वह कोई भी फ़ाइल है जिसे service account पढ़ सकता है।
| ID | अभी तक कोई CVE नहीं |
| CWE | CWE-73 |
| CVSS | Medium: 4.2 CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N |
| Product | Gitea |
| Affected | v1.27.3 (146cc3e) तक; local operator gitea restore-repo |
| Auth | एक अविश्वसनीय dump का local operator restore |
| License | GNU Affero GPL v3.0 |
| Lab | केवल 127.0.0.1 |
एक admin को एक अविश्वसनीय dump (एक "backup" directory, एक अविश्वसनीय remote से restore) दें जिसमें joined-under-dump path के अंतर्गत एक symlink हो। Restore target file को restored repo पर एक release attachment में कॉपी कर देता है। जो भी उस repo को पढ़ सकता है, वह इसे डाउनलोड कर सकता है।
यदि dump लेखक app.ini का नाम देता है, तो वह credential theft है (INTERNAL_TOKEN, SECRET_KEY, JWT, DB password)। Lab oracle एक planted witness file था, app.ini नहीं। यह OS LPE नहीं है। यह unauthenticated नहीं है। यह dump-root join escape नहीं है। GitHub/GitLab/Gitea से live migrate DownloadFunc सेट करता है और एक attacker file:// को os.Open नहीं करता।
दो restore maps leftover table पर पड़े थे। मैंने पहले स्पष्ट वाले को labbed किया।
Finding 8 dump-root join escape था: release.yml में एक absolute DownloadURL डालें, उम्मीद करें कि FilePathJoinAbs dump prefix को उसी तरह गिरा देगा जैसे naive filepath.Join(base, "/etc/passwd") करता है। 1.27.3 पर यह नहीं करता। प्रत्येक sub filepath.Clean("/"+s) है फिर filepath.Join(base, cleaned)। /tmp/dump + /tmp/GITEA-JOIN-OUTSIDE का Replica join /tmp/dump/tmp/GITEA-JOIN-OUTSIDE ही रहा। Restore ने dump के अंतर्गत file:// को rewrite किया और open ...: no such file or directory पर विफल रहा। यह इस tag पर join-escape नहीं है।
Finding 9 वह है जो सफल हुआ। मैंने dump के बाहर एक witness file plant की, joined-under-dump path पर एक symlink डाला, gitea restore-repo चलाया। Restore rc=0। Restored release attachment में GITEA-FILE-OPEN-WITNESS था।
पहले से दर्ज गलत मोड़: एक absolute DownloadURL के माध्यम से dump-root join escape; live migrate file:// LFI; X-Gitea-Internal-Auth (restore Gitea uid के रूप में CLI है, /api/internal नहीं); restore HTTP को remote unauth मानना (CVSS local, high privilege, user interaction है); एक reverse shell। नाटक।
cd lab
./run.sh
लक्ष्य केवल http://127.0.0.1:18137। Compose lab/dump को read-only mount करता है। run.sh container के अंदर witness plant करता है, dump बनाता है, symlink डालता है, फिर gitea restore-repo।
restore-rc=0 Restore repo labadmin/restored successfully
download status=200 snippet=GITEA-FILE-OPEN-WITNESS
SUCCESS GITEA-RESTORE-FILE-OPEN
OpenWithClient से file:// हटा दें, या dump symlinks का अनुसरण करने से इनकार करें, और अविश्वसनीय dumps को restore न करें। Restored attachment में out-of-dump witness नहीं होना चाहिए।
uri.go · gitea_uploader.go · FilePathJoinAbsGNU Affero GPL v3.0। देखें LICENSE। केवल Loopback lab। कोई वारंटी नहीं।