首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第51期->最新漏洞
期刊号: 类型: 关键词:
libpng png_handle_tRNS远程缓冲区溢出漏洞

日期:2004-09-06

发布日期:2004-08-04
更新日期:2004-08-05

受影响系统:
libpng libpng 1.2.5
描述:
--------------------------------------------------------------------------------
libpng是多种应用程序使用的解析PNG图象格式的库。

libpng png_handle_tRNS对数据缺少正确边界缓冲区检查,远程攻击者可以利用这个漏洞以用户进程权限在系统上执行任意指令。

如果PNG文件格式正确,libpng库在把PNG数据填充到缓冲区时缺少正确的长度检查。此问题应该是个逻辑错误,问题存在于如下代码:

      if (!(png_ptr->mode & PNG_HAVE_PLTE))
      {
         /* Should be an error, but we can cope with it */
         png_warning(png_ptr, "Missing PLTE before tRNS");
      }
      else if (length > (png_uint_32)png_ptr->num_palette)
      {
         png_warning(png_ptr, "Incorrect tRNS chunk length");
         png_crc_finish(png_ptr, length);
         return;
      }

我们可以看到,如果第一个警告条件成立,那么由于使用"else if"的长度检查将会忽略。

攻击者可以构建恶意PNG文件,诱使用户解析,可能以用户进程权限在系统上执行任意指令。

<*来源:chris (chris@cr-secure.net)
  
  链接:http://marc.theaimsgroup.com/?l=bugtraq&m=109164344215165&w=2
        http://www.us-cert.gov/cas/techalerts/TA04-217A.html
*>

建议:
--------------------------------------------------------------------------------
厂商补丁:

libpng
------
使用如下补丁程序:

diff -ru libpng-1.2.5/png.h libpng-1.2.5.fix/png.h
--- libpng-1.2.5/png.h    2002-10-03 12:32:26.000000000 +0100
+++ libpng-1.2.5.fix/png.h    2004-07-13 23:18:10.000000000 +0100
@@ -835,6 +835,9 @@
/* Maximum positive integer used in PNG is (2^31)-1 */
#define PNG_MAX_UINT ((png_uint_32)0x7fffffffL)

+/* Constraints on width, height, (2 ^ 24) - 1*/
+#define PNG_MAX_DIMENSION 16777215
+
/* These describe the color_type field in png_info. */
/* color type masks */
#define PNG_COLOR_MASK_PALETTE    1
diff -ru libpng-1.2.5/pngpread.c libpng-1.2.5.fix/pngpread.c
--- libpng-1.2.5/pngpread.c    2002-10-03 12:32:28.000000000 +0100
+++ libpng-1.2.5.fix/pngpread.c    2004-07-13 23:03:58.000000000 +0100
@@ -209,6 +209,8 @@

       png_push_fill_buffer(png_ptr, chunk_length, 4);
       png_ptr->push_length = png_get_uint_32(chunk_length);
+      if (png_ptr->push_length > PNG_MAX_UINT)
+         png_error(png_ptr, "Invalid chunk length.");
       png_reset_crc(png_ptr);
       png_crc_read(png_ptr, png_ptr->chunk_name, 4);
       png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
@@ -638,6 +640,8 @@

       png_push_fill_buffer(png_ptr, chunk_length, 4);
       png_ptr->push_length = png_get_uint_32(chunk_length);
+      if (png_ptr->push_length > PNG_MAX_UINT)
+         png_error(png_ptr, "Invalid chunk length.");

       png_reset_crc(png_ptr);
       png_crc_read(png_ptr, png_ptr->chunk_name, 4);
diff -ru libpng-1.2.5/pngrutil.c libpng-1.2.5.fix/pngrutil.c
--- libpng-1.2.5/pngrutil.c    2004-07-13 13:36:37.000000000 +0100
+++ libpng-1.2.5.fix/pngrutil.c    2004-07-13 23:43:02.000000000 +0100
@@ -350,7 +350,11 @@
    png_crc_finish(png_ptr, 0);

    width = png_get_uint_32(buf);
+   if (width > PNG_MAX_DIMENSION)
+      png_error(png_ptr, "Width is too large");
    height = png_get_uint_32(buf + 4);
+   if (height > PNG_MAX_DIMENSION)
+      png_error(png_ptr, "Height is too large");
    bit_depth = buf[8];
    color_type = buf[9];
    compression_type = buf[10];
@@ -675,7 +679,7 @@
    else
       truelen = (png_size_t)png_ptr->channels;

-   if (length != truelen)
+   if (length != truelen || length > 4)
    {
       png_warning(png_ptr, "Incorrect sBIT chunk length");
       png_crc_finish(png_ptr, length);
@@ -1244,7 +1248,8 @@
          /* Should be an error, but we can cope with it */
          png_warning(png_ptr, "Missing PLTE before tRNS");
       }
-      else if (length > (png_uint_32)png_ptr->num_palette)
+      if (length > (png_uint_32)png_ptr->num_palette ||
+          length > PNG_MAX_PALETTE_LENGTH)
       {
          png_warning(png_ptr, "Incorrect tRNS chunk length");
          png_crc_finish(png_ptr, length);
@@ -1400,7 +1405,7 @@
void /* PRIVATE */
png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
-   int num, i;
+   unsigned int num, i;
    png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];

    png_debug(1, "in png_handle_hIST\n");
@@ -1426,8 +1431,8 @@
       return;
    }

-   num = (int)length / 2 ;
-   if (num != png_ptr->num_palette)
+   num = length / 2 ;
+   if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH)
    {
       png_warning(png_ptr, "Incorrect hIST chunk length");
       png_crc_finish(png_ptr, length);
@@ -2868,6 +2873,9 @@
                png_read_data(png_ptr, chunk_length, 4);
                png_ptr->idat_size = png_get_uint_32(chunk_length);

+               if (png_ptr->idat_size > PNG_MAX_UINT)
+                  png_error(png_ptr, "Invalid chunk length.");
+
                png_reset_crc(png_ptr);
                png_crc_read(png_ptr, png_ptr->chunk_name, 4);
                if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
版权所有,未经许可,不得转载