
CVE-2023-4911 (Looney Tunables) analysis report and Docker reproduction lab
| आइटम | विषय |
|---|---|
| CVE ID | CVE-2023-4911 |
| हमले का प्रकार | हीप बफर ओवरफ्लो → स्थानीय विशेषाधिकार वृद्धि (Local Privilege Escalation) |
| CVSS 3.1 | 7.8 (उच्च) |
| प्रकाशन तिथि | 2023-10-03 |
| भेद्यता बिंदु | glibc डायनामिक लोडर (ld.so) का GLIBC_TUNABLES पार्सर |
| भेद्य संस्करण | glibc 2.34~2.38 |
CVE-2023-4911 GNU C Library (glibc) के डायनामिक लोडर द्वारा GLIBC_TUNABLES पर्यावरण चर को पार्स करने की प्रक्रिया में उत्पन्न होने वाली हीप बफर ओवरफ्लो भेद्यता है। हमलावर इस ओवरफ्लो का उपयोग करके डायनामिक लोडर की लाइब्रेरी खोज पथ (RPATH) में हेरफेर कर सकता है, जिससे SUID रूट बाइनरी (su, sudo आदि) के निष्पादित होने पर हमलावर द्वारा तैयार की गई दुर्भावनापूर्ण साझा लाइब्रेरी को लोड करके मनमाना कोड रूट अधिकारों से निष्पादित किया जा सकता है। चूंकि glibc लगभग सभी प्रमुख लिनक्स वितरणों का मुख्य घटक है, यह भेद्यता अप्रैल 2021 के बाद जारी अधिकांश glibc-आधारित वितरणों को प्रभावित करती है।
while (true)
{
char *name = p;
size_t len = 0;
/* नाम (name) की लंबाई ज्ञात करना */
while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
len++;
/* '=' के बिना समाप्त होने पर समाप्त */
if (p[len] == '\0')
{
if (__libc_enable_secure)
tunestr[off] = '\0';
return;
}
/* पहले ':' मिलने पर अमान्य आइटम */
if (p[len] == ':')
{
p += len + 1;
continue;
}
/* '=' मिलने पर value की शुरुआत की ओर बढ़ना */
p += len + 1;
/* मूल स्ट्रिंग से value की गणना */
char *value = &valstring[p - tunestr];
len = 0;
/* value की लंबाई ज्ञात करना */
while (p[len] != ':' && p[len] != '\0')
len++;
...
/* tunestr में कॉपी करना */
...
if (p[len] != '\0')
p += len + 1;
}
__tunables_init() पर्यावरण चर सूची में GLIBC_TUNABLES ढूंढता है।tunables_strdup() __minimal_malloc() के साथ एक बफर आवंटित करता है और मूल स्ट्रिंग की प्रतिलिपि बनाता है (इस बिंदु पर malloc एक बहुत प्रारंभिक, अभी तक पूरी तरह से प्रारंभ नहीं हुआ, कार्यान्वयन है)।parse_tunables() इस बफर को : (कोलन) के आधार पर पार करता है और प्रत्येक key=value जोड़े को अलग करके संबंधित ट्यूनबल में मान निर्दिष्ट करता है।parse_tunables() एक ट्यूनबल को name पार्स करना → p आगे बढ़ाना → value पार्स करना → p आगे बढ़ाना के क्रम में संसाधित करता है। सामान्य इनपुट में, value को पूरी तरह से संसाधित करने के बाद, p अगले ट्यूनबल के प्रारंभिक स्थान पर चला जाता है और अगले आइटम को पार्स करता है।
हालाँकि, जब निम्नलिखित name=name=value प्रारूप का इनपुट दिया जाता है:
GLIBC_TUNABLES=glibc.malloc.mxfast=glibc.malloc.mxfast=AAAA...(लंबी स्ट्रिंग)
पहली पार्सिंग प्रक्रिया में, glibc.malloc.mxfast=AAAA... पूरे को एक value के रूप में पहचाना जाता है और tunestr बफर में कॉपी किया जाता है। इसके बाद, value के बाद अगले ट्यूनबल को अलग करने वाला कोलन (:) मौजूद नहीं होता है, जिससे पार्सिंग पॉइंटर (p) अगले आइटम पर नहीं जा पाता है और पहले से कॉपी की गई value के प्रारंभिक स्थान को फिर से इंगित करता है।
समस्या यह है कि यह value स्वयं name=value प्रारूप में है। अगले पुनरावृत्ति में, पार्सर इसे एक नए ट्यूनबल के रूप में गलत तरीके से पहचानता है और बफर में डुप्लिकेट डेटा लिखता है। tunestr केवल मूल स्ट्रिंग के आकार के बराबर आवंटित किया गया है, इसलिए डुप्लिकेट लेखन के कारण हीप बफर ओवरफ्लो होता है।
उत्पन्न हीप बफर ओवरफ्लो __minimal_malloc() द्वारा लगातार आवंटित आसन्न हीप क्षेत्रों को भी अधिलेखित कर देता है। हमलावर इसका उपयोग डायनामिक लोडर (ld.so) के आंतरिक संरचना link_map के l_info[DT_RPATH] पॉइंटर को नियंत्रित स्टैक पते में बदलने के लिए कर सकता है।
उस स्टैक क्षेत्र में पहले से ही एक हेरफेर किया गया Elf64_Dyn संरचना रखी गई है, और यह संरचना हमलावर द्वारा वांछित निर्देशिका को नए लाइब्रेरी खोज पथ (RPATH) के रूप में निर्दिष्ट करती है। परिणामस्वरूप, ld.so सामान्य सिस्टम लाइब्रेरी के बजाय हमलावर द्वारा तैयार की गई साझा लाइब्रेरी को प्राथमिकता से लोड करता है।
name=name=value प्रारूप का GLIBC_TUNABLES पर्यावरण चर तैयार करता है।su आदि) निष्पादित करता है।parse_tunables() में हीप बफर ओवरफ्लो होता है।link_map के l_info[DT_RPATH] पॉइंटर को हमलावर द्वारा तैयार किए गए नकली Elf64_Dyn संरचना वाले स्टैक पते में हेरफेर किया जाता है।libc.so.6 लोड करता है।libc.so.6 का प्रारंभिक कोड (या परिवर्तित प्रारंभिक रूटीन) रूट अधिकारों के साथ निष्पादित होता है, जो setuid(0), setgid(0) और /bin/sh का निष्पादन करता है।PoC यादृच्छिकता (ASLR) के प्रभाव के कारण वांछित मेमोरी लेआउट बनने तक execve() को बार-बार दोहराने वाली ब्रूट-फोर्स विधि का उपयोग करता है। इसलिए हमले की सफलता और लगने वाला समय पर्यावरण पर निर्भर करता है, और आमतौर पर सैकड़ों से हजारों पुनरावृत्तियों की आवश्यकता होती है।
पहले git में मौजूद सामग्री को निर्देशिका में क्लोन करें
git clone https://github.com/baeseungwon1010/CVE-2023-4911

नीचे दिए गए आदेश के माध्यम से डॉकर इमेज बनाएं
cd C* && docker compose run --rm cve-2023-4911-lab

कंटेनर में प्रवेश करने के बाद शोषण कोड निष्पादित करें
cd /home/student/exploit && ./exp
निष्पादित करने के बाद प्रतीक्षा करें, आप देख सकते हैं कि सामान्य उपयोगकर्ता sudo(0) में बदल गया है

glibc के संस्करण को भेद्य संस्करण से नवीनतम संस्करण में पैच करें। पैच करने के बाद, यदि संभव हो तो रीबूट/रीस्टार्ट करें ताकि पिछले संस्करण का glibc मेमोरी में न रहे। यदि तुरंत पैच करना मुश्किल है, तो अनावश्यक SUID, SGID आदि प्रक्रियाओं को हटाना एक अस्थायी उपाय है।
su के प्रमाणीकरण तर्क के निष्पादित होने से पहले होती है, इसलिए बिना पासवर्ड सत्यापन के रूट शेल प्राप्त होता है।