libX11 DoS 漏洞 - CVE-2023-43786

admin 2024年1月19日12:47:20评论11 views字数 3933阅读13分6秒阅读模式

libX11 DoS 漏洞 - CVE-2023-43786

CVE-2023-43786 漏洞本质上是由于递归停止条件计算不正确而导致的无限循环。

修复提交:

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

XPutImage是 libX11 中的一个函数,可让您将图像放置到 X Drawable(通常是 X Window)上。使用此函数,可以将像素信息从 XImage 结构传输到指定的可绘制对象(如窗口或像素图),并根据需要对其进行定位。

xpmCreatePixmapFromImage

libXpm函数xpmCreatePixmapFromImage调用此XPutImage函数:

voidxpmCreatePixmapFromImage(    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

这是XPutImagelibX11 函数:

intXPutImage (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 voidPutSubImage (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,116bits_per_pixel = 32width = 90,000 pixelsheight = 1 pixel

由于图像bits_per_pixel是 32,[1] 中的条件语句将不会通过,导致我们进入 [2] 中定义的替代代码块。

然后计算BytesPerRowon [3],然后除以 8。在我们的示例中:BytesPerRow = 90000 * 32 / 8 = 360,000

在示例中,对 [4] 的检查不会通过,因为 360000 不小于请求的大小 262116,并且无法将请求宽度的单行放入单个请求中 – 这会启动对 [5] 的else检查。

这决定了单个请求中可以包含的像素数量。然后,它启动对该函数的递归调用PutSubImage以仅传递该子集,然后进行后续递归调用以管理该行的其余部分。如果需要,还可以通过额外的递归调用进一步划分剩余部分。

然而,[6] 的计算未能考虑每像素的位数,并且递归调用使请求发送 2096928 像素而不是 2096928 位——这比单个请求所能容纳的要大。

这会导致尝试分割像素线的无限循环,始终导致数字太大而无法容纳,并再次尝试该过程以使用相同的值重试。这种递归一直持续到调用堆栈耗尽为止。

错误修复更改了 [6] 的计算并考虑了bits_per_pixel. 在示例中,这将导致递归调用请求仅发送 65529 个像素,从而导致 BytesPerRow 为 262116,完全适合可用空间,从而允许递归向前推进并只需 2 次调用即可完成。

触发错误的概念验证图像示例:https://github.com/jfrog/jfrog-CVE-2023-43786-libX11_DoS/blob/main/cve-2023-43786.xpm

如何触发该错误

调用易受攻击的 libXpm 库函数的应用程序的一个示例是 CLI 实用程序sxpm,它用于在屏幕上显示 Xpm 图像。

它调用易受攻击的xpmCreatePixmapFromImageXpm 函数,然后该函数又调用易受攻击的 libX11XPutImage函数PutSubImage

libX11 DoS 漏洞 - CVE-2023-43786

原文始发于微信公众号(Ots安全):libX11 DoS 漏洞 – CVE-2023-43786

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月19日12:47:20
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   libX11 DoS 漏洞 - CVE-2023-43786https://cn-sec.com/archives/2409435.html

发表评论

匿名网友 填写信息