paint-brush
निक्स लिबएक्स11 में 35 साल पुरानी भेद्यता का अनावरण: भाग 1द्वारा@yairjfrog
339 रीडिंग
339 रीडिंग

निक्स लिबएक्स11 में 35 साल पुरानी भेद्यता का अनावरण: भाग 1

द्वारा Yair Mizrahi18m2024/03/08
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

यह ब्लॉग श्रृंखला X.Org libX11, अर्थात् CVE-2023-43786 और CVE-2023-43787 में पाई गई सुरक्षा कमजोरियों पर प्रकाश डालती है, XPM फ़ाइल प्रारूप की जटिलताओं की खोज करती है और इन कमजोरियों के शोषण का प्रदर्शन करती है। प्रदान की गई व्यापक जानकारी और सुधारों के साथ जानें कि अपने सिस्टम की सुरक्षा कैसे करें।
featured image - निक्स लिबएक्स11 में 35 साल पुरानी भेद्यता का अनावरण: भाग 1
Yair Mizrahi HackerNoon profile picture
0-item


मेरी टीम ने हाल ही में खोजा X.Org libX11 में दो सुरक्षा कमजोरियाँ , व्यापक रूप से लोकप्रिय ग्राफिक्स लाइब्रेरी - सीवीई-2023-43786 और सीवीई-2023-43787 (उच्च एनवीडी गंभीरता सीवीएसएस 7.8 के साथ)। ये कमजोरियाँ सेवा से इनकार और रिमोट कोड निष्पादन का कारण बनती हैं। X11 के नवीनतम संस्करणों में इन कमजोरियों के समाधान शामिल हैं।


टीम नई कमजोरियों और दुर्भावनापूर्ण पैकेजों को खोजने के लिए ओपन-सोर्स परियोजनाओं की लगातार निगरानी करती है और उनकी समग्र सुरक्षा स्थिति को बेहतर बनाने में मदद करने के लिए उन्हें व्यापक समुदाय के साथ साझा करती है।


यह 2-भाग ब्लॉग श्रृंखला कमजोर Xpm फ़ाइल प्रारूप की आंतरिक कार्यप्रणाली का विवरण प्रदान करती है और इन कमजोरियों का फायदा उठाने के बारे में गहराई से बताती है।


libX11 क्या है?

Xorg X11, जिसे अक्सर X विंडो सिस्टम के रूप में जाना जाता है, एक ओपन-सोर्स ग्राफिकल सर्वर प्रोटोकॉल है जो यूनिक्स जैसे ऑपरेटिंग सिस्टम में ग्राफिकल यूजर इंटरफेस के निर्माण और प्रबंधन को सक्षम बनाता है। यह ग्राफ़िकल एप्लिकेशन चलाने, विंडोज़ प्रबंधित करने और नेटवर्क वाले वातावरण में उपयोगकर्ता इनपुट को संभालने के लिए एक रूपरेखा प्रदान करता है।


Libx11 पैकेज आवश्यक साझा लाइब्रेरी प्रदान करता है जो क्लाइंट एप्लिकेशन को आपके डेस्कटॉप पर डेटा प्रस्तुत करने और प्रस्तुत करने के लिए आवश्यक होती है।


क्लाइंट_सर्वर एक्स आर्किटेक्चर


Xterm विंडो - एक X11 क्लाइंट एप्लिकेशन


लिबएक्सपीएम क्या है?

libXpm X Pixmap (XPM) प्रारूप में छवियों को पढ़ने, लिखने और प्रदर्शित करने के कार्य प्रदान करता है।

एक्सपीएम का मुख्य उद्देश्य पारदर्शी पिक्सल के समर्थन के साथ आइकन पिक्समैप्स उत्पन्न करना है। यह XBM सिंटैक्स पर आधारित है, और या तो XPM2 प्रारूप में एक सादा पाठ फ़ाइल हो सकती है या C प्रोग्रामिंग भाषा सिंटैक्स का उपयोग कर सकती है, जो इसे C प्रोग्राम फ़ाइल में शामिल करने के लिए उपयुक्त बनाती है।


एक्सपीएम छवि प्रारूप - संस्करण

पूर्ववर्ती - एक्सबीएम


1989 में XPM (X PixMap) आने से पहले, XBM प्रारूप (X BitMap) था।


एक सादा-पाठ बाइनरी छवि प्रारूप, जिसका उपयोग एक्स जीयूआई में उपयोग किए गए आइकन और कर्सर बिटमैप्स को संग्रहीत करने के लिए किया जाता है।


XBM फ़ाइलें C स्रोत फ़ाइलों के रूप में संरचित हैं। यह आज के अधिकांश छवि प्रारूपों से उनका मुख्य अंतर है। इस तरह, उन्हें सीधे अनुप्रयोगों में शामिल किया जा सकता है। हालाँकि, इस और इस तथ्य के कारण कि कोई संपीड़न नियोजित नहीं किया जा सकता है (1 वर्ण से 1-बाइट मैपिंग), वे अपने कच्चे पिक्सेल डेटा से भी कहीं बड़े हैं।


एक्स बिटमैप (एक्सबीएम) डेटा में स्थिर अहस्ताक्षरित चार सरणियों का एक क्रम शामिल होता है जो कच्चे मोनोक्रोम पिक्सेल जानकारी को संग्रहीत करता है।


उदाहरण के लिए, निम्न C कोड छवि में hello के लिए XBM फ़ाइल है:

हैलो Xbm छवि XnView में दिखाई गई है

 #define hello_width 35 #define hello_height 25 static char hello_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x88, 0x00, 0x00, 0x10, 0x00, 0x88, 0x00, 0x00, 0x10, 0x00, 0x88, 0x00, 0x00, 0xD0, 0xE1, 0x88, 0x78, 0x00, 0x30, 0x13, 0x89, 0xC4, 0x00, 0x10, 0x12, 0x89, 0x84, 0x00, 0x10, 0xF2, 0x89, 0x84, 0x00, 0x10, 0x12, 0x88, 0x84, 0x00, 0x10, 0x12, 0x88, 0x44, 0x00, 0x10, 0xE2, 0x89, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

सामान्य छवि फ़ाइल प्रारूप हेडर के बजाय, XBM फ़ाइलों में #define कथन होते हैं। मानों की पहली जोड़ी बिटमैप के पिक्सेल आयामों को परिभाषित करती है, जो इसकी ऊंचाई और चौड़ाई को दर्शाती है।


एक्स बिटमैप (एक्सबीएम) छवि डेटा को पिक्सेल मानों के निरंतर अनुक्रम के रूप में संरचित किया जाता है, जो एक स्थिर सरणी के भीतर संग्रहीत होते हैं। यह देखते हुए कि प्रत्येक पिक्सेल को एक बिट द्वारा दर्शाया गया है (0 सफेद को दर्शाता है और 1 काले को दर्शाता है), सरणी में प्रत्येक बाइट आठ अलग-अलग पिक्सेल के लिए डेटा को समाहित करता है। विशेष रूप से, पहले बाइट का सबसे कम महत्वपूर्ण बिट बिटमैप के भीतर ऊपरी-बाएँ पिक्सेल के लिए एंकर के रूप में कार्य करता है।


एक्सपीएम1

XPM संस्करण से मिलें


पहली बार 1989 में रिलीज़ किया गया, इसमें ऊपर उल्लिखित XBM प्रारूप के साथ बहुत सारी समानताएँ हैं। जबकि XBM मोनोक्रोम था, XPM1 ने छवियों में रंग पेश किए।


यह रंगों के लिए अतिरिक्त मैक्रोज़ और वेरिएबल्स का उपयोग करता है और पिक्सेल डेटा के लिए बाइट्स को वर्णों से बदल देता है।


उदाहरण के लिए, यहाँ XPM1 प्रारूप में वही hello -श्याम चित्र है:


 /* XPM */ static char *_hello[] = { /* columns rows colors chars-per-pixel */ "35 25 2 1 ", " c white", "bc black", /* pixels */ " ", " ", " ", " ", " ", " ", " ", " bbb ", " bbb ", " bbb ", " b bbb bbb bb bbbb ", " bb bb bbbbb bb ", " bbbbbbbb ", " bb bbbbb bbbb ", " bbbbbbb ", " bbbbbbb ", " bb bbbb bb bbb ", " ", " ", " ", " ", " ", " ", " ", " " };

यहां XFACE_ncolors छवि में रंगों की संख्या को दर्शाता है, और XFACE_chars_per_pixel प्रति पिक्सेल वर्णों की संख्या को दर्शाता है।


प्रत्येक a सफेद रंग "#ffffff" से बदल दिया जाएगा, और प्रत्येक b काले रंग "#000000" से बदल दिया जाएगा।


एक्सपीएम2

एक साल बाद, 1990 में, चीजों को बेहतर बनाने के लिए प्रारूप का दूसरा संस्करण तैयार किया गया। इसने चीजों को सरल बना दिया और छवि प्रारूप से सभी सी कोड हटा दिए।


सरलीकृत संरचना:

 ! XPM2 <Header> <Colors> <Pixels>


हेडर लाइन XPM1 के #define कथनों के समान छवि आयामों को दर्शाती है।

रंग अनुभाग वर्ण मानों को परिभाषित करता है।


एक नई प्रकार की अवधारणा पेश की गई:

c - रंग पिक्सेल के लिए है

m - मोनोक्रोम के लिए है

g - ग्रेस्केल के लिए बर्फ

s - प्रतीकात्मक के लिए है


प्रतीकात्मक सुविधा का उपयोग संदर्भ के आधार पर रंग निर्दिष्ट करने और आसानी से पढ़ने के लिए उनके लिए परिवर्तनीय नाम बनाने के लिए किया जाता है।


XPM2 छवि का उदाहरण, उसी hello के साथ जैसा पिछले उदाहरणों में दिखाया गया है:

 ! XPM2 35 25 2 1 ac #000000 bc #ffffff aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaabaaaaaaaaaaaaaabaaabaaaaaaaaaaa aaaabaaaaaaaaaaaaaabaaabaaaaaaaaaaa aaaabaaaaaaaaaaaaaabaaabaaaaaaaaaaa aaaababbbaaaabbbaaabaaabaaabbbbaaaa aaaabbaabbaabaaabaabaaabaabaaabbaaa aaaabaaaabaabaaabaabaaabaabaaaabaaa aaaabaaaabaabbbbbaabaaabaabaaaabaaa aaaabaaaabaabaaaaaabaaabaabaaaabaaa aaaabaaaabaabaaaaaabaaabaabaaabaaaa aaaabaaaabaaabbbbaabaaabaaabbbaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

हेक्साडेसिमल रंग कोड के अलावा, रंगों को किसी भी X11 रंग नाम (जैसे red ) का उपयोग करके भी निर्दिष्ट किया जा सकता है, जिसमें None पारदर्शिता का संकेत नहीं देता है।


एक्सपीएम3

यह XPM प्रारूप का वर्तमान संस्करण है.


1991 में जारी संस्करण, C कोड को वापस लाया, लेकिन शुद्ध C कोड शैली का उपयोग करने के बजाय, अंदर के मान अनिवार्य रूप से XPM2 प्रारूप के समान हैं।


उदाहरण:

 /* XPM */ static char *_hello[] = { /* columns rows colors chars-per-pixel */ "35 25 2 1 ", " c white", "bc black", /* pixels */ " ", " ", " ", " ", " ", " ", " ", " bbb ", " bbb ", " bbb ", " b bbb bbb bb bbbb ", " bb bb bbbbb bb ", " bbbbbbbb ", " bb bbbbb bbbb ", " bbbbbbb ", " bbbbbbb ", " bb bbbb bb bbb ", " ", " ", " ", " ", " ", " ", " ", " " };


जैसा कि चर्चा की गई है, एक्सपीएम प्रारूप अधिक परिष्कृत छवियों का भी प्रतिनिधित्व कर सकता है, जैसे कि जेफ्रॉग लोगो:

JFrog लोगो को XPM3 का उपयोग करके दर्शाया गया है


DoS भेद्यता - CVE-2023-43786

CVE-2023-43786 भेद्यता अनिवार्य रूप से एक गलत रिकर्सन स्टॉप स्थिति गणना के परिणामस्वरूप उत्पन्न होने वाला एक अंतहीन लूप है।


निश्चित प्रतिबद्धता:

https://gitlab.freedesktop.org/xorg/lib/libx11/-/commit/204c3393c4c90a29ed6bef64e43849536e863a86


XPutImage libX11 में एक फ़ंक्शन है जो आपको छवियों को X ड्रॉएबल, आमतौर पर एक X विंडो पर रखने की सुविधा देता है। इस फ़ंक्शन के साथ, कोई व्यक्ति XImage संरचना से पिक्सेल जानकारी को एक निर्दिष्ट ड्रॉएबल, जैसे विंडो या पिक्समैप में स्थानांतरित कर सकता है, और इसे आवश्यकतानुसार स्थान दे सकता है।


xpmCreatePixmapFromImage

xpmCreatePixmapFromImage libXpm फ़ंक्शन इस XPutImage फ़ंक्शन के लिए कॉल करता है:

 void xpmCreatePixmapFromImage( Display *display, Drawable d, XImage *ximage, Pixmap *pixmap_return) { GC gc; XGCValues values; *pixmap_return = XCreatePixmap(display, d, ximage->width, ximage->height, ximage->depth); /* set fg and bg in case we have an XYBitmap */ values.foreground = 1; values.background = 0; gc = XCreateGC(display, *pixmap_return, GCForeground | GCBackground, &values); XPutImage(display, *pixmap_return, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height); XFreeGC(display, gc); }


इस फ़ंक्शन में, ximage प्रदर्शित होने वाला स्रोत छवि पिक्सेल डेटा है और इसे X Drawable ऑब्जेक्ट में कॉपी किया जाता है (इस मामले में pixmap_return )।


XPutImage

यहाँ XPutImage libX11 फ़ंक्शन है:

 int XPutImage ( register Display *dpy, Drawable d, GC gc, register XImage *image, int req_xoffset, int req_yoffset, int x, int y, unsigned int req_width, unsigned int req_height){ ..... PutSubImage(dpy, d, gc, &img, 0, 0, x, y, (unsigned int) width, (unsigned int) height, dest_bits_per_pixel, dest_scanline_pad); UnlockDisplay(dpy); SyncHandle(); Xfree(img.data); return 0; } }
 LockDisplay(dpy); FlushGC(dpy, gc); PutSubImage(dpy, d, gc, image, req_xoffset, req_yoffset, x, y, (unsigned int) width, (unsigned int) height, dest_bits_per_pixel, dest_scanline_pad);......... }


यह PutSubImage फ़ंक्शन को कॉल करता है:

 static void PutSubImage ( register Display *dpy, Drawable d, GC gc, register XImage *image, int req_xoffset, int req_yoffset, int x, int y, unsigned int req_width, unsigned int req_height, int dest_bits_per_pixel, int dest_scanline_pad) { int left_pad, BytesPerRow, Available; if ((req_width == 0) || (req_height == 0)) return; Available = ((65536 < dpy->max_request_size) ? (65536 << 2) : (dpy->max_request_size << 2)) - SIZEOF(xPutImageReq); if ((image->bits_per_pixel == 1) || (image->format != ZPixmap)) { [1] left_pad = (image->xoffset + req_xoffset) & (dpy->bitmap_unit - 1); BytesPerRow = (ROUNDUP((long)req_width + left_pad, dpy->bitmap_pad) >> 3) * image->depth; } else { [2] left_pad = 0; BytesPerRow = ROUNDUP((long)req_width * dest_bits_per_pixel, [3] dest_scanline_pad) >> 3; } if ((BytesPerRow * req_height) <= Available) { [4] PutImageRequest(dpy, d, gc, image, req_xoffset, req_yoffset, x, y, req_width, req_height, dest_bits_per_pixel, dest_scanline_pad); } else if (req_height > 1) { int SubImageHeight = Available / BytesPerRow; if (SubImageHeight == 0) SubImageHeight = 1; PutSubImage(dpy, d, gc, image, req_xoffset, req_yoffset, x, y, req_width, (unsigned int) SubImageHeight, dest_bits_per_pixel, dest_scanline_pad); PutSubImage(dpy, d, gc, image, req_xoffset, req_yoffset + SubImageHeight, x, y + SubImageHeight, req_width, req_height - SubImageHeight, dest_bits_per_pixel, dest_scanline_pad); } else { [5] int SubImageWidth = (((Available << 3) / dest_scanline_pad) [6] * dest_scanline_pad) - left_pad; PutSubImage(dpy, d, gc, image, req_xoffset, req_yoffset, x, y, (unsigned int) SubImageWidth, 1, dest_bits_per_pixel, dest_scanline_pad); PutSubImage(dpy, d, gc, image, req_xoffset + SubImageWidth, req_yoffset, x + SubImageWidth, y, req_width - SubImageWidth, 1, dest_bits_per_pixel, dest_scanline_pad); } }


तकनीकी भेद्यता विवरण

आइए निम्नलिखित उदाहरण छवि लें:


 Available [the requested size] = (65,536 * 4) - 28 = 262,116 bits_per_pixel = 32 width = 90,000 pixels height = 1 pixel


चूँकि छवि bits_per_pixel 32 है, [1] पर सशर्त विवरण पास नहीं होगा, जिससे हमें [2] में परिभाषित वैकल्पिक कोड ब्लॉक में प्रवेश करना पड़ेगा।


इसके बाद यह [3] पर BytesPerRow गणना करता है और फिर इसे 8 से विभाजित करता है। हमारे उदाहरण में: BytesPerRow = 90000 * 32 / 8 = 360,0


उदाहरण में, [4] पर चेक पास नहीं होगा, क्योंकि 360000 अनुरोधित आकार 262116 से कम नहीं है, और अनुरोधित चौड़ाई की एक भी पंक्ति को एक अनुरोध में फिट करने में सक्षम नहीं है - यह [5 पर else आरंभ करता है ].


यह उन पिक्सेल की संख्या निर्धारित करता है जिन्हें एक अनुरोध में शामिल किया जा सकता है। इसके बाद यह केवल उस सबसेट को पास करने के लिए PutSubImage फ़ंक्शन के लिए एक पुनरावर्ती कॉल शुरू करता है, इसके बाद लाइन के शेष भाग को प्रबंधित करने के लिए बाद में पुनरावर्ती कॉल करता है। यदि आवश्यक हो, तो इस शेष भाग को अतिरिक्त पुनरावर्ती कॉल के माध्यम से भी विभाजित किया जा सकता है।


हालाँकि, [6] पर गणना प्रति पिक्सेल बिट्स को ध्यान में रखने में विफल रहती है, और पुनरावर्ती कॉल 2096928 बिट्स के बजाय 2096928 पिक्सेल भेजने का अनुरोध करता है - जो कि एक अनुरोध में फिट होने से बड़ा है।


इससे पिक्सल की लाइन को विभाजित करने के प्रयास का एक अंतहीन चक्र शुरू हो जाता है, जिसके परिणामस्वरूप लगातार इतनी बड़ी संख्या होती है कि वह फिट नहीं हो पाती है और उसी मान के साथ पुनः प्रयास करने की प्रक्रिया फिर से शुरू हो जाती है। यह पुनरावृत्ति तब तक बनी रहती है जब तक कॉल स्टैक समाप्त नहीं हो जाता।


बग फिक्स ने [6] पर गणना बदल दी और bits_per_pixel को ध्यान में रखा। उदाहरण में, इसके परिणामस्वरूप एक पुनरावर्ती कॉल होगी जिसमें केवल 65529 पिक्सेल भेजने का अनुरोध किया जाएगा, जिसके परिणामस्वरूप 262116 का बाइट्सपेरो होगा जो उपलब्ध स्थान के भीतर पूरी तरह से फिट होगा, इस प्रकार पुनरावर्ती को आगे बढ़ने और केवल 2 कॉल में समाप्त करने की अनुमति मिलेगी।


बग को ट्रिगर करने के लिए उदाहरण प्रमाण-अवधारणा छवि: https://github.com/jfrog/jfrog-CVE-2023-43786-libX11_DoS/blob/main/cve-2023-43786.xpm


बग को कैसे ट्रिगर किया जा सकता है

एक ऐप का एक उदाहरण जो कमजोर libXpm लाइब्रेरी फ़ंक्शन को कॉल करता है वह CLI उपयोगिता sxpm है, जिसका उपयोग स्क्रीन पर Xpm छवियों को प्रदर्शित करने के लिए किया जाता है।


यह कमजोर xpmCreatePixmapFromImage XPM फ़ंक्शन को कॉल करता है, जो फिर कमजोर libX11 फ़ंक्शन XPutImage और फिर PutSubImage कॉल करता है।

xpmCreatePixmapFromImage_XPutImage_PutSubImage