আমার দল সম্প্রতি আবিষ্কৃত
দলটি নতুন দুর্বলতা এবং দূষিত প্যাকেজগুলি খুঁজে পেতে ওপেন সোর্স প্রকল্পগুলি ক্রমাগত নিরীক্ষণ করে এবং তাদের সামগ্রিক নিরাপত্তা ভঙ্গি উন্নত করতে সাহায্য করার জন্য বিস্তৃত সম্প্রদায়ের সাথে সেগুলি ভাগ করে।
এই 2-অংশের ব্লগ সিরিজটি দুর্বল Xpm ফাইল ফর্ম্যাটের অভ্যন্তরীণ কাজের বিবরণ এবং এই দুর্বলতাগুলিকে কাজে লাগানোর জন্য গভীর-ডুইভ প্রদান করে।
Xorg X11, প্রায়ই X উইন্ডো সিস্টেম হিসাবে পরিচিত, একটি ওপেন-সোর্স গ্রাফিকাল সার্ভার প্রোটোকল যা ইউনিক্স-এর মতো অপারেটিং সিস্টেমে গ্রাফিকাল ইউজার ইন্টারফেস তৈরি এবং পরিচালনা করতে সক্ষম করে। এটি গ্রাফিকাল অ্যাপ্লিকেশন চালানো, উইন্ডোজ পরিচালনা এবং একটি নেটওয়ার্ক পরিবেশে ব্যবহারকারীর ইনপুট পরিচালনা করার জন্য একটি কাঠামো প্রদান করে।
libx11 প্যাকেজ অপরিহার্য শেয়ার্ড লাইব্রেরিগুলি অফার করে যা ক্লায়েন্ট অ্যাপ্লিকেশনগুলিকে আপনার ডেস্কটপে ডেটা রেন্ডার এবং উপস্থাপন করার জন্য প্রয়োজন।
libXpm X Pixmap (XPM) বিন্যাসে চিত্রগুলি পড়তে, লিখতে এবং প্রদর্শন করার ফাংশন প্রদান করে।
XPM প্রাথমিকভাবে স্বচ্ছ পিক্সেলের জন্য সমর্থন সহ আইকন পিক্সম্যাপ তৈরি করা। এটি XBM সিনট্যাক্সের উপর ভিত্তি করে, এবং এটি XPM2 ফর্ম্যাটে একটি প্লেইন টেক্সট ফাইল হতে পারে বা একটি সি প্রোগ্রামিং ভাষা সিনট্যাক্স ব্যবহার করতে পারে, এটি একটি সি প্রোগ্রাম ফাইলের মধ্যে অন্তর্ভুক্তির জন্য উপযুক্ত করে তোলে।
XPM ইমেজ ফরম্যাট – সংস্করণ
পূর্বসূরী - XBM
XPM (X PixMap) 1989 সালে অস্তিত্বে আসার আগে, XBM ফর্ম্যাট (X BitMap) ছিল।
একটি প্লেইন-টেক্সট বাইনারি ইমেজ ফরম্যাট, আইকন এবং কার্সার বিটম্যাপ সংরক্ষণের জন্য ব্যবহৃত হয় যা X GUI-তে ব্যবহৃত হয়।
XBM ফাইলগুলি সি সোর্স ফাইল হিসাবে গঠন করা হয়। এটি বর্তমানের বেশিরভাগ ইমেজ ফরম্যাট থেকে তাদের প্রধান পার্থক্য। এইভাবে, তারা সরাসরি অ্যাপ্লিকেশনগুলিতে অন্তর্ভুক্ত করা যেতে পারে। যাইহোক, এই কারণে এবং কোন কম্প্রেশন নিযুক্ত করা যাবে না (1 অক্ষর থেকে 1-বাইট ম্যাপিং), তারা তাদের কাঁচা পিক্সেল ডেটা থেকে অনেক বড়।
এক্স বিটম্যাপ (এক্সবিএম) ডেটা স্ট্যাটিক স্বাক্ষরবিহীন চার অ্যারেগুলির একটি ক্রম নিয়ে গঠিত যা কাঁচা একরঙা পিক্সেল তথ্য সংরক্ষণ করে।
উদাহরণ স্বরূপ, নিচের সি কোডটি হল ছবিতে hello
জন্য XBM ফাইল:
#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টি কালো প্রতিনিধিত্ব করে), অ্যারের প্রতিটি বাইট আটটি পৃথক পিক্সেলের ডেটা অন্তর্ভুক্ত করে। উল্লেখযোগ্যভাবে, প্রথম বাইটের সর্বনিম্ন উল্লেখযোগ্য বিট বিটম্যাপের মধ্যে উপরের-বাম পিক্সেলের জন্য অ্যাঙ্কর হিসাবে কাজ করে।
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" দ্বারা প্রতিস্থাপিত হবে।
এক বছর পরে, 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
স্বচ্ছতা নির্দেশ করে না।
এটি 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
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
কল করে।
এছাড়াও এখানে প্রকাশিত.