paint-brush
nix libX11-এ একটি 35-বছর-পুরোনো দুর্বলতা উন্মোচন করা: পার্ট 1দ্বারা@yairjfrog
339 পড়া
339 পড়া

nix libX11-এ একটি 35-বছর-পুরোনো দুর্বলতা উন্মোচন করা: পার্ট 1

দ্বারা Yair Mizrahi18m2024/03/08
Read on Terminal Reader

অতিদীর্ঘ; পড়তে

এই ব্লগ সিরিজটি X.Org libX11-এ প্রাপ্ত নিরাপত্তা দুর্বলতাগুলি, যথা CVE-2023-43786 এবং CVE-2023-43787, XPM ফাইল ফর্ম্যাটের জটিলতাগুলি অন্বেষণ করে এবং এই দুর্বলতাগুলির শোষণ প্রদর্শন করে৷ বিস্তৃত অন্তর্দৃষ্টি এবং প্রদত্ত সংশোধন সহ আপনার সিস্টেমগুলিকে কীভাবে সুরক্ষিত করবেন তা শিখুন।
featured image - nix libX11-এ একটি 35-বছর-পুরোনো দুর্বলতা উন্মোচন করা: পার্ট 1
Yair Mizrahi HackerNoon profile picture
0-item


আমার দল সম্প্রতি আবিষ্কৃত X.Org libX11-এ দুটি নিরাপত্তা দুর্বলতা , ব্যাপকভাবে জনপ্রিয় গ্রাফিক্স লাইব্রেরি – CVE-2023-43786 এবং CVE-2023-43787 (একটি উচ্চ NVD তীব্রতা CVSS 7.8 সহ)। এই দুর্বলতাগুলি পরিষেবার অস্বীকৃতি এবং দূরবর্তী কোড কার্যকর করার কারণ। X11-এর সাম্প্রতিক সংস্করণে এই দুর্বলতাগুলির সমাধান রয়েছে।


দলটি নতুন দুর্বলতা এবং দূষিত প্যাকেজগুলি খুঁজে পেতে ওপেন সোর্স প্রকল্পগুলি ক্রমাগত নিরীক্ষণ করে এবং তাদের সামগ্রিক নিরাপত্তা ভঙ্গি উন্নত করতে সাহায্য করার জন্য বিস্তৃত সম্প্রদায়ের সাথে সেগুলি ভাগ করে।


এই 2-অংশের ব্লগ সিরিজটি দুর্বল Xpm ফাইল ফর্ম্যাটের অভ্যন্তরীণ কাজের বিবরণ এবং এই দুর্বলতাগুলিকে কাজে লাগানোর জন্য গভীর-ডুইভ প্রদান করে।


libX11 কি?

Xorg X11, প্রায়ই X উইন্ডো সিস্টেম হিসাবে পরিচিত, একটি ওপেন-সোর্স গ্রাফিকাল সার্ভার প্রোটোকল যা ইউনিক্স-এর মতো অপারেটিং সিস্টেমে গ্রাফিকাল ইউজার ইন্টারফেস তৈরি এবং পরিচালনা করতে সক্ষম করে। এটি গ্রাফিকাল অ্যাপ্লিকেশন চালানো, উইন্ডোজ পরিচালনা এবং একটি নেটওয়ার্ক পরিবেশে ব্যবহারকারীর ইনপুট পরিচালনা করার জন্য একটি কাঠামো প্রদান করে।


libx11 প্যাকেজ অপরিহার্য শেয়ার্ড লাইব্রেরিগুলি অফার করে যা ক্লায়েন্ট অ্যাপ্লিকেশনগুলিকে আপনার ডেস্কটপে ডেটা রেন্ডার এবং উপস্থাপন করার জন্য প্রয়োজন।


ক্লায়েন্ট_সার্ভার এক্স আর্কিটেকচার


Xterm উইন্ডো - একটি X11 ক্লায়েন্ট অ্যাপ্লিকেশন


libXpm কি?

libXpm X Pixmap (XPM) বিন্যাসে চিত্রগুলি পড়তে, লিখতে এবং প্রদর্শন করার ফাংশন প্রদান করে।

XPM প্রাথমিকভাবে স্বচ্ছ পিক্সেলের জন্য সমর্থন সহ আইকন পিক্সম্যাপ তৈরি করা। এটি XBM সিনট্যাক্সের উপর ভিত্তি করে, এবং এটি XPM2 ফর্ম্যাটে একটি প্লেইন টেক্সট ফাইল হতে পারে বা একটি সি প্রোগ্রামিং ভাষা সিনট্যাক্স ব্যবহার করতে পারে, এটি একটি সি প্রোগ্রাম ফাইলের মধ্যে অন্তর্ভুক্তির জন্য উপযুক্ত করে তোলে।


XPM ইমেজ ফরম্যাট – সংস্করণ

পূর্বসূরী - XBM


XPM (X PixMap) 1989 সালে অস্তিত্বে আসার আগে, XBM ফর্ম্যাট (X BitMap) ছিল।


একটি প্লেইন-টেক্সট বাইনারি ইমেজ ফরম্যাট, আইকন এবং কার্সার বিটম্যাপ সংরক্ষণের জন্য ব্যবহৃত হয় যা X GUI-তে ব্যবহৃত হয়।


XBM ফাইলগুলি সি সোর্স ফাইল হিসাবে গঠন করা হয়। এটি বর্তমানের বেশিরভাগ ইমেজ ফরম্যাট থেকে তাদের প্রধান পার্থক্য। এইভাবে, তারা সরাসরি অ্যাপ্লিকেশনগুলিতে অন্তর্ভুক্ত করা যেতে পারে। যাইহোক, এই কারণে এবং কোন কম্প্রেশন নিযুক্ত করা যাবে না (1 অক্ষর থেকে 1-বাইট ম্যাপিং), তারা তাদের কাঁচা পিক্সেল ডেটা থেকে অনেক বড়।


এক্স বিটম্যাপ (এক্সবিএম) ডেটা স্ট্যাটিক স্বাক্ষরবিহীন চার অ্যারেগুলির একটি ক্রম নিয়ে গঠিত যা কাঁচা একরঙা পিক্সেল তথ্য সংরক্ষণ করে।


উদাহরণ স্বরূপ, নিচের সি কোডটি হল ছবিতে 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 স্টেটমেন্ট থাকে। মানগুলির প্রথম জোড়া বিটম্যাপের পিক্সেল মাত্রা সংজ্ঞায়িত করে, এটির উচ্চতা এবং প্রস্থ নির্দেশ করে।


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 প্রতি পিক্সেলে অক্ষরের সংখ্যা নির্দেশ করে।


প্রতিটি a সাদা রঙ "#ffffff" দ্বারা প্রতিস্থাপিত করা হবে, এবং প্রতিটি b কালো রঙ "#000000" দ্বারা প্রতিস্থাপিত হবে।


XPM2

এক বছর পরে, 1990 সালে, বিন্যাসের দ্বিতীয় সংস্করণটি জিনিসগুলিকে উন্নত করার জন্য সেট করা হয়েছিল। এটি জিনিসগুলিকে সরল করেছে এবং চিত্র বিন্যাস থেকে সমস্ত সি কোড সরিয়ে দিয়েছে৷


সরলীকৃত কাঠামো:

 ! XPM2 <Header> <Colors> <Pixels>


হেডার লাইনটি XPM1 এর #define স্টেটমেন্টের মত ইমেজের মাত্রা নির্দেশ করে।

রং বিভাগ অক্ষর মান সংজ্ঞায়িত করে.


একটি নতুন ধরনের ধারণা চালু করা হয়েছিল:

c - কালার পিক্সেলের জন্য

m - একরঙা জন্য

g - গ্রেস্কেলের জন্য বরফ

s - প্রতীকী জন্য


সাংকেতিক বৈশিষ্ট্যটি প্রসঙ্গ অনুসারে রঙ নির্ধারণ করতে এবং সহজে পড়ার জন্য তাদের জন্য পরিবর্তনশীল নাম তৈরি করতে ব্যবহৃত হয়।


পূর্ববর্তী উদাহরণে দেখানো একই hello সহ একটি XPM2 চিত্রের উদাহরণ:

 ! 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 লোগো:

JFrog লোগো XPM3 ব্যবহার করে চিত্রিত


DoS দুর্বলতা – CVE-2023-43786

CVE-2023-43786 দুর্বলতা মূলত একটি অন্তহীন লুপ যা একটি ভুল রিকার্সন স্টপ কন্ডিশন গণনার ফলে।


স্থির প্রতিশ্রুতি:

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


XPutImage হল libX11-এর একটি ফাংশন যা আপনাকে X Drawable, সাধারণত একটি 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 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 দ্বারা ভাগ করে। আমাদের উদাহরণে: বাইটসপাররো = 90000 * 32/8 = 360,0


উদাহরণে, [4]-এর চেকটি পাস হবে না, কারণ 360000 অনুরোধ করা আকার 262116-এর চেয়ে কম নয় এবং অনুরোধ করা প্রস্থের একটি লাইনকে একটি অনুরোধে ফিট করতে সক্ষম নয় - এটি [5] এ else শুরু করে ]।


এটি একটি একক অনুরোধে অন্তর্ভুক্ত করা যেতে পারে এমন পিক্সেলের সংখ্যা নির্ধারণ করে। এটি তারপর সেই সাবসেটটি পাস করার জন্য PutSubImage ফাংশনে একটি পুনরাবৃত্ত কল শুরু করে, এর পরে লাইনের অবশিষ্ট অংশ পরিচালনা করার জন্য একটি রিকার্সিভ কল আসে। প্রয়োজনে, এই অবশিষ্ট অংশটি অতিরিক্ত রিকার্সিভ কলের মাধ্যমে আরও ভাগ করা যেতে পারে।


যাইহোক, [6]-এর গণনা পিক্সেল প্রতি বিটগুলিকে বিবেচনায় নিতে ব্যর্থ হয় এবং পুনরাবৃত্ত কলে 2096928 বিটের পরিবর্তে 2096928 পিক্সেল পাঠানোর অনুরোধ করা হয় - যা একটি একক অনুরোধে উপযুক্ত হতে পারে তার চেয়ে বড়।


এটি পিক্সেলের লাইনকে বিভক্ত করার প্রচেষ্টার একটি অন্তহীন লুপের দিকে নিয়ে যায়, যার ফলে ধারাবাহিকভাবে একটি সংখ্যা খুব বেশি মাপসই হয় না এবং একই মানগুলির সাথে পুনরায় চেষ্টা করার প্রক্রিয়াটি আবার চেষ্টা করে৷ কল স্ট্যাক শেষ না হওয়া পর্যন্ত এই পুনরাবৃত্তি অব্যাহত থাকে।


বাগ ফিক্স [6] এ গণনা পরিবর্তন করেছে এবং bits_per_pixel বিবেচনায় নিয়েছে। উদাহরণে, এটি শুধুমাত্র 65529 পিক্সেল পাঠানোর অনুরোধ করে একটি রিকার্সিভ কলের পরিণতি হবে, যার ফলে 262116-এর একটি BytesPerRow যা উপলব্ধ স্থানের মধ্যে পুরোপুরি ফিট করে, এইভাবে রিকার্সনকে সামনের দিকে অগ্রগতি করতে এবং মাত্র 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