5

我正在为我的最后一次考试而学习(是的!),并且遇到了一个我很难弄清楚的问题。这是一个古老的考试问题,您应该在其中找到至少两个可以在读取 ppm 图像文件的函数中被利用的漏洞。我能确定的唯一问题是 cols 和/或 rows 是否被赋予了意外的值,要么太大(导致整数溢出)要么为负,这会导致 img->raster 的大小不正确,从而打开基于堆的可能性缓冲区溢出攻击。

据我所知,未经检查的 malloc 不应该是可利用的。

struct image *read_ppm(FILE *fp)
{
    int version;
    int rows, cols, maxval;
    int pixBytes=0, rowBytes=0, rasterBytes;
    uint8_t *p;
    struct image *img;
    /* Read the magic number from the file */
    if ((fscanf(fp, " P%d ", &version) < 1) || (version != 6)) {
        return NULL;
    }
    /* Read the image dimensions and color depth from the file */
    if (fscanf(fp, " %d %d %d ", &cols, &rows, &maxval) < 3) {
        return NULL;
    }
    /* Calculate some sizes */
    pixBytes = (maxval > 255) ? 6 : 3; // Bytes per pixel
    rowBytes = pixBytes * cols; // Bytes per row
    rasterBytes = rowBytes * rows; // Bytes for the whole image
    /* Allocate the image structure and initialize its fields */
    img = malloc(sizeof(*img));
    if (img == NULL) return NULL;
    img->rows = rows;
    img->cols = cols; 
    img->depth = (maxval > 255) ? 2 : 1;
    img->raster = (void*)malloc(rasterBytes);
    /* Get a pointer to the first pixel in the raster data. */
    /* It is to this pointer that all image data will be written. */
    p = img->raster;
    /* Iterate over the rows in the file */
    while (rows--) {
        /* Iterate over the columns in the file */
        cols = img->cols;
        while (cols--) {
            /* Try to read a single pixel from the file */
            if (fread(p, pixBytes, 1, fp) < 1) {
                /* If the read fails, free memory and return */
                free(img->raster);
                free(img);
                return NULL;
            }
            /* Advance the pointer to the next location to which we
            should read a single pixel. */
            p += pixBytes;
        }
    }
    /* Return the image */
    return img;
}

原文(最后一题):http ://www.ida.liu.se/~TDDC90/exam/old/TDDC90%20TEN1%202009-12-22.pdf

谢谢你的帮助。

4

3 回答 3

3

创建一个大文件,这样读取rowcols都是否定的。rasterBytes = pixBytes * rows * cols积极的,所以一切都会好起来的p = img->raster;。但是此时你有两个无限循环,程序可能会覆盖堆。

row另一种攻击是设置它们以cols使它们具有不同的符号。您可以选择其中一个值为-1,而另一个值足够大以读取您想要的数据。分配

  img->raster = (void*)malloc(rasterBytes);

将失败,这导致 img->raster 指向 NULL。意思是

 fread(p, pixBytes, 1, fp) < 1

会尝试将文件的内容读入内核内存。如果此代码在内核模式下执行,具体取决于系统(比如说旧的 unix,它不使用内存段),那么您将用文件的内容覆盖内核内存的内容。不使用内存段的内核不依赖于分段错误,而是依赖于页面错误(没有分配任何实际页面的虚拟地址)。问题是存在虚拟内存设计,因此第一个实际页面直接分配给内核页面。即内核虚拟地址 0x0 对应于 0x0 处的真实内存,并且完全有效(在内核内部)。

编辑:在这两种情况下,攻击者的目标是将输入文件的内容(完全在他的控制之下)注入他不应该访问的内存区域,同时无法修改函数read_ppm().

于 2012-12-21T13:57:19.207 回答
0

还有一个事实是,没有检查此分配是否成功。可能导致 DoS。

img->raster = (void*)malloc(rasterBytes);
于 2012-12-21T13:56:21.767 回答
0

如果分配失败:

img->raster = (void*)malloc(rasterBytes);

你可能正在写一些你不打算写的记忆。

该分配的大小由文件中的数据控制。

于 2012-12-21T14:03:23.690 回答