मेरी टीम ने हाल ही में खोजा , व्यापक रूप से लोकप्रिय ग्राफिक्स लाइब्रेरी - (उच्च एनवीडी गंभीरता के साथ)। ये कमजोरियाँ सेवा से इनकार और रिमोट कोड निष्पादन का कारण बनती हैं। X11 के नवीनतम संस्करणों में इन कमजोरियों के समाधान शामिल हैं। X.Org libX11 में दो सुरक्षा कमजोरियाँ सीवीई-2023-43786 और सीवीई-2023-43787 सीवीएसएस 7.8 टीम नई कमजोरियों और दुर्भावनापूर्ण पैकेजों को खोजने के लिए ओपन-सोर्स परियोजनाओं की लगातार निगरानी करती है और उनकी समग्र सुरक्षा स्थिति को बेहतर बनाने में मदद करने के लिए उन्हें व्यापक समुदाय के साथ साझा करती है। यह 2-भाग ब्लॉग श्रृंखला कमजोर Xpm फ़ाइल प्रारूप की आंतरिक कार्यप्रणाली का विवरण प्रदान करती है और इन कमजोरियों का फायदा उठाने के बारे में गहराई से बताती है। libX11 क्या है? Xorg X11, जिसे अक्सर X विंडो सिस्टम के रूप में जाना जाता है, एक ग्राफिकल सर्वर प्रोटोकॉल है जो यूनिक्स जैसे ऑपरेटिंग सिस्टम में ग्राफिकल यूजर इंटरफेस के निर्माण और प्रबंधन को सक्षम बनाता है। यह ग्राफ़िकल एप्लिकेशन चलाने, विंडोज़ प्रबंधित करने और नेटवर्क वाले वातावरण में उपयोगकर्ता इनपुट को संभालने के लिए एक रूपरेखा प्रदान करता है। ओपन-सोर्स Libx11 पैकेज आवश्यक साझा लाइब्रेरी प्रदान करता है जो क्लाइंट एप्लिकेशन को आपके डेस्कटॉप पर डेटा प्रस्तुत करने और प्रस्तुत करने के लिए आवश्यक होती है। लिबएक्सपीएम क्या है? libXpm (XPM) प्रारूप में छवियों को पढ़ने, लिखने और प्रदर्शित करने के कार्य प्रदान करता है। X Pixmap एक्सपीएम का मुख्य उद्देश्य पारदर्शी पिक्सल के समर्थन के साथ आइकन पिक्समैप्स उत्पन्न करना है। यह XBM सिंटैक्स पर आधारित है, और या तो XPM2 प्रारूप में एक सादा पाठ फ़ाइल हो सकती है या C प्रोग्रामिंग भाषा सिंटैक्स का उपयोग कर सकती है, जो इसे C प्रोग्राम फ़ाइल में शामिल करने के लिए उपयुक्त बनाती है। एक्सपीएम छवि प्रारूप - संस्करण पूर्ववर्ती - एक्सबीएम 1989 में XPM (X PixMap) आने से पहले, XBM प्रारूप (X BitMap) था। एक सादा-पाठ बाइनरी छवि प्रारूप, जिसका उपयोग एक्स जीयूआई में उपयोग किए गए आइकन और कर्सर बिटमैप्स को संग्रहीत करने के लिए किया जाता है। XBM फ़ाइलें C स्रोत फ़ाइलों के रूप में संरचित हैं। यह आज के अधिकांश छवि प्रारूपों से उनका मुख्य अंतर है। इस तरह, उन्हें सीधे अनुप्रयोगों में शामिल किया जा सकता है। हालाँकि, इस और इस तथ्य के कारण कि कोई संपीड़न नियोजित नहीं किया जा सकता है (1 वर्ण से 1-बाइट मैपिंग), वे अपने कच्चे पिक्सेल डेटा से भी कहीं बड़े हैं। एक्स बिटमैप (एक्सबीएम) डेटा में स्थिर अहस्ताक्षरित चार सरणियों का एक क्रम शामिल होता है जो कच्चे मोनोक्रोम पिक्सेल जानकारी को संग्रहीत करता है। उदाहरण के लिए, निम्न C कोड छवि में के लिए XBM फ़ाइल है: hello #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 प्रत्येक सफेद रंग "#ffffff" से बदल दिया जाएगा, और प्रत्येक काले रंग "#000000" से बदल दिया जाएगा। a b एक्सपीएम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 ", " ", " ", " ", " ", " ", " ", " ", " " }; जैसा कि चर्चा की गई है, एक्सपीएम प्रारूप अधिक परिष्कृत छवियों का भी प्रतिनिधित्व कर सकता है, जैसे कि जेफ्रॉग लोगो: DoS भेद्यता - CVE-2023-43786 CVE-2023-43786 भेद्यता अनिवार्य रूप से एक गलत रिकर्सन स्टॉप स्थिति गणना के परिणामस्वरूप उत्पन्न होने वाला एक अंतहीन लूप है। निश्चित प्रतिबद्धता: https://gitlab.freedesktop.org/xorg/lib/libx11/-/commit/204c3393c4c90a29ed6bef64e43849536e863a86 libX11 में एक फ़ंक्शन है जो आपको छवियों को X ड्रॉएबल, आमतौर पर एक X विंडो पर रखने की सुविधा देता है। इस फ़ंक्शन के साथ, कोई व्यक्ति XImage संरचना से पिक्सेल जानकारी को एक निर्दिष्ट ड्रॉएबल, जैसे विंडो या पिक्समैप में स्थानांतरित कर सकता है, और इसे आवश्यकतानुसार स्थान दे सकता है। XPutImage xpmCreatePixmapFromImage libXpm फ़ंक्शन इस फ़ंक्शन के लिए कॉल करता है: xpmCreatePixmapFromImage 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 यहाँ libX11 फ़ंक्शन है: XPutImage 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 चूँकि छवि 32 है, [1] पर सशर्त विवरण पास नहीं होगा, जिससे हमें [2] में परिभाषित वैकल्पिक कोड ब्लॉक में प्रवेश करना पड़ेगा। bits_per_pixel इसके बाद यह [3] पर गणना करता है और फिर इसे 8 से विभाजित करता है। हमारे उदाहरण में: BytesPerRow = 90000 * 32 / 8 = 360,0 BytesPerRow उदाहरण में, [4] पर चेक पास नहीं होगा, क्योंकि 360000 अनुरोधित आकार 262116 से कम नहीं है, और अनुरोधित चौड़ाई की एक भी पंक्ति को एक अनुरोध में फिट करने में सक्षम नहीं है - यह [5 पर आरंभ करता है ]. else यह उन पिक्सेल की संख्या निर्धारित करता है जिन्हें एक अनुरोध में शामिल किया जा सकता है। इसके बाद यह केवल उस सबसेट को पास करने के लिए फ़ंक्शन के लिए एक पुनरावर्ती कॉल शुरू करता है, इसके बाद लाइन के शेष भाग को प्रबंधित करने के लिए बाद में पुनरावर्ती कॉल करता है। यदि आवश्यक हो, तो इस शेष भाग को अतिरिक्त पुनरावर्ती कॉल के माध्यम से भी विभाजित किया जा सकता है। PutSubImage हालाँकि, [6] पर गणना प्रति पिक्सेल बिट्स को ध्यान में रखने में विफल रहती है, और पुनरावर्ती कॉल 2096928 बिट्स के बजाय 2096928 पिक्सेल भेजने का अनुरोध करता है - जो कि एक अनुरोध में फिट होने से बड़ा है। इससे शुरू हो जाता है, जिसके परिणामस्वरूप लगातार इतनी बड़ी संख्या होती है कि वह फिट नहीं हो पाती है और उसी मान के साथ पुनः प्रयास करने की प्रक्रिया फिर से शुरू हो जाती है। यह पुनरावृत्ति तब तक बनी रहती है जब तक कॉल स्टैक समाप्त नहीं हो जाता। पिक्सल की लाइन को विभाजित करने के प्रयास का एक अंतहीन चक्र [6] पर गणना बदल दी और को ध्यान में रखा। उदाहरण में, इसके परिणामस्वरूप एक पुनरावर्ती कॉल होगी जिसमें केवल 65529 पिक्सेल भेजने का अनुरोध किया जाएगा, जिसके परिणामस्वरूप 262116 का बाइट्सपेरो होगा जो उपलब्ध स्थान के भीतर पूरी तरह से फिट होगा, इस प्रकार पुनरावर्ती को आगे बढ़ने और केवल 2 कॉल में समाप्त करने की अनुमति मिलेगी। बग फिक्स ने bits_per_pixel बग को ट्रिगर करने के लिए उदाहरण प्रमाण-अवधारणा छवि: https://github.com/jfrog/jfrog-CVE-2023-43786-libX11_DoS/blob/main/cve-2023-43786.xpm बग को कैसे ट्रिगर किया जा सकता है एक ऐप का एक उदाहरण जो कमजोर libXpm लाइब्रेरी फ़ंक्शन को कॉल करता है वह CLI उपयोगिता है, जिसका उपयोग स्क्रीन पर Xpm छवियों को प्रदर्शित करने के लिए किया जाता है। sxpm यह कमजोर XPM फ़ंक्शन को कॉल करता है, जो फिर कमजोर libX11 फ़ंक्शन और फिर कॉल करता है। xpmCreatePixmapFromImage XPutImage PutSubImage यहाँ भी प्रकाशित किया गया।