আমার দল সম্প্রতি আবিষ্কৃত , ব্যাপকভাবে জনপ্রিয় গ্রাফিক্স লাইব্রেরি – (একটি উচ্চ NVD তীব্রতা সহ)। এই দুর্বলতাগুলি পরিষেবার অস্বীকৃতি এবং দূরবর্তী কোড কার্যকর করার কারণ। X11-এর সাম্প্রতিক সংস্করণে এই দুর্বলতাগুলির সমাধান রয়েছে। X.Org libX11-এ দুটি নিরাপত্তা দুর্বলতা CVE-2023-43786 এবং CVE-2023-43787 CVSS 7.8 দলটি নতুন দুর্বলতা এবং দূষিত প্যাকেজগুলি খুঁজে পেতে ওপেন সোর্স প্রকল্পগুলি ক্রমাগত নিরীক্ষণ করে এবং তাদের সামগ্রিক নিরাপত্তা ভঙ্গি উন্নত করতে সাহায্য করার জন্য বিস্তৃত সম্প্রদায়ের সাথে সেগুলি ভাগ করে। এই 2-অংশের ব্লগ সিরিজটি দুর্বল Xpm ফাইল ফর্ম্যাটের অভ্যন্তরীণ কাজের বিবরণ এবং এই দুর্বলতাগুলিকে কাজে লাগানোর জন্য গভীর-ডুইভ প্রদান করে। libX11 কি? Xorg X11, প্রায়ই X উইন্ডো সিস্টেম হিসাবে পরিচিত, একটি গ্রাফিকাল সার্ভার প্রোটোকল যা ইউনিক্স-এর মতো অপারেটিং সিস্টেমে গ্রাফিকাল ইউজার ইন্টারফেস তৈরি এবং পরিচালনা করতে সক্ষম করে। এটি গ্রাফিকাল অ্যাপ্লিকেশন চালানো, উইন্ডোজ পরিচালনা এবং একটি নেটওয়ার্ক পরিবেশে ব্যবহারকারীর ইনপুট পরিচালনা করার জন্য একটি কাঠামো প্রদান করে। ওপেন-সোর্স libx11 প্যাকেজ অপরিহার্য শেয়ার্ড লাইব্রেরিগুলি অফার করে যা ক্লায়েন্ট অ্যাপ্লিকেশনগুলিকে আপনার ডেস্কটপে ডেটা রেন্ডার এবং উপস্থাপন করার জন্য প্রয়োজন। libXpm কি? libXpm (XPM) বিন্যাসে চিত্রগুলি পড়তে, লিখতে এবং প্রদর্শন করার ফাংশন প্রদান করে। X Pixmap XPM প্রাথমিকভাবে স্বচ্ছ পিক্সেলের জন্য সমর্থন সহ আইকন পিক্সম্যাপ তৈরি করা। এটি XBM সিনট্যাক্সের উপর ভিত্তি করে, এবং এটি XPM2 ফর্ম্যাটে একটি প্লেইন টেক্সট ফাইল হতে পারে বা একটি সি প্রোগ্রামিং ভাষা সিনট্যাক্স ব্যবহার করতে পারে, এটি একটি সি প্রোগ্রাম ফাইলের মধ্যে অন্তর্ভুক্তির জন্য উপযুক্ত করে তোলে। XPM ইমেজ ফরম্যাট – সংস্করণ পূর্বসূরী - XBM XPM (X PixMap) 1989 সালে অস্তিত্বে আসার আগে, XBM ফর্ম্যাট (X BitMap) ছিল। একটি প্লেইন-টেক্সট বাইনারি ইমেজ ফরম্যাট, আইকন এবং কার্সার বিটম্যাপ সংরক্ষণের জন্য ব্যবহৃত হয় যা X GUI-তে ব্যবহৃত হয়। XBM ফাইলগুলি সি সোর্স ফাইল হিসাবে গঠন করা হয়। এটি বর্তমানের বেশিরভাগ ইমেজ ফরম্যাট থেকে তাদের প্রধান পার্থক্য। এইভাবে, তারা সরাসরি অ্যাপ্লিকেশনগুলিতে অন্তর্ভুক্ত করা যেতে পারে। যাইহোক, এই কারণে এবং কোন কম্প্রেশন নিযুক্ত করা যাবে না (1 অক্ষর থেকে 1-বাইট ম্যাপিং), তারা তাদের কাঁচা পিক্সেল ডেটা থেকে অনেক বড়। এক্স বিটম্যাপ (এক্সবিএম) ডেটা স্ট্যাটিক স্বাক্ষরবিহীন চার অ্যারেগুলির একটি ক্রম নিয়ে গঠিত যা কাঁচা একরঙা পিক্সেল তথ্য সংরক্ষণ করে। উদাহরণ স্বরূপ, নিচের সি কোডটি হল ছবিতে জন্য 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 X BitMap (XBM) ইমেজ ডেটা পিক্সেল মানগুলির একটি ক্রমাগত ক্রম হিসাবে গঠন করা হয়, যা একটি স্ট্যাটিক অ্যারের মধ্যে সংরক্ষণ করা হয়। প্রদত্ত যে প্রতিটি পিক্সেল একটি একক বিট দ্বারা প্রতীকী (0 সহ সাদা এবং 1টি কালো প্রতিনিধিত্ব করে), অ্যারের প্রতিটি বাইট আটটি পৃথক পিক্সেলের ডেটা অন্তর্ভুক্ত করে। উল্লেখযোগ্যভাবে, প্রথম বাইটের সর্বনিম্ন উল্লেখযোগ্য বিট বিটম্যাপের মধ্যে উপরের-বাম পিক্সেলের জন্য অ্যাঙ্কর হিসাবে কাজ করে। XPM1 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 XPM2 এক বছর পরে, 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 XPM3 এটি 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 ", " ", " ", " ", " ", " ", " ", " ", " " }; যেমন আলোচনা করা হয়েছে, XPM ফরম্যাট আরও পরিশীলিত চিত্র উপস্থাপন করতে পারে, যেমন JFrog লোগো: DoS দুর্বলতা – CVE-2023-43786 CVE-2023-43786 দুর্বলতা মূলত একটি অন্তহীন লুপ যা একটি ভুল রিকার্সন স্টপ কন্ডিশন গণনার ফলে। স্থির প্রতিশ্রুতি: https://gitlab.freedesktop.org/xorg/lib/libx11/-/commit/204c3393c4c90a29ed6bef64e43849536e863a86 হল libX11-এর একটি ফাংশন যা আপনাকে X Drawable, সাধারণত একটি 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 এক্সপুট ইমেজ এখানে 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 দ্বারা ভাগ করে। আমাদের উদাহরণে: বাইটসপাররো = 90000 * 32/8 = 360,0 BytesPerRow উদাহরণে, [4]-এর চেকটি পাস হবে না, কারণ 360000 অনুরোধ করা আকার 262116-এর চেয়ে কম নয় এবং অনুরোধ করা প্রস্থের একটি লাইনকে একটি অনুরোধে ফিট করতে সক্ষম নয় - এটি [5] এ শুরু করে ]। else এটি একটি একক অনুরোধে অন্তর্ভুক্ত করা যেতে পারে এমন পিক্সেলের সংখ্যা নির্ধারণ করে। এটি তারপর সেই সাবসেটটি পাস করার জন্য ফাংশনে একটি পুনরাবৃত্ত কল শুরু করে, এর পরে লাইনের অবশিষ্ট অংশ পরিচালনা করার জন্য একটি রিকার্সিভ কল আসে। প্রয়োজনে, এই অবশিষ্ট অংশটি অতিরিক্ত রিকার্সিভ কলের মাধ্যমে আরও ভাগ করা যেতে পারে। PutSubImage যাইহোক, [6]-এর গণনা পিক্সেল প্রতি বিটগুলিকে বিবেচনায় নিতে ব্যর্থ হয় এবং পুনরাবৃত্ত কলে 2096928 বিটের পরিবর্তে 2096928 পিক্সেল পাঠানোর অনুরোধ করা হয় - যা একটি একক অনুরোধে উপযুক্ত হতে পারে তার চেয়ে বড়। এটি দিকে নিয়ে যায়, যার ফলে ধারাবাহিকভাবে একটি সংখ্যা খুব বেশি মাপসই হয় না এবং একই মানগুলির সাথে পুনরায় চেষ্টা করার প্রক্রিয়াটি আবার চেষ্টা করে৷ কল স্ট্যাক শেষ না হওয়া পর্যন্ত এই পুনরাবৃত্তি অব্যাহত থাকে। পিক্সেলের লাইনকে বিভক্ত করার প্রচেষ্টার একটি অন্তহীন লুপের [6] এ গণনা পরিবর্তন করেছে এবং বিবেচনায় নিয়েছে। উদাহরণে, এটি শুধুমাত্র 65529 পিক্সেল পাঠানোর অনুরোধ করে একটি রিকার্সিভ কলের পরিণতি হবে, যার ফলে 262116-এর একটি BytesPerRow যা উপলব্ধ স্থানের মধ্যে পুরোপুরি ফিট করে, এইভাবে রিকার্সনকে সামনের দিকে অগ্রগতি করতে এবং মাত্র 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 এছাড়াও এখানে প্রকাশিত.