5

私は最後の試験に向けて勉強していて (yey!)、理解するのに苦労している問題に出くわしました。これは、ppm イメージ ファイルを読み取る関数で悪用される可能性のある脆弱性を少なくとも 2 つ見つけることになっている古い試験問題です。私が特定できる唯一の問題は、列や行に予期しない値が与えられた場合です。これは、大きすぎる (整数オーバーフローを引き起こす) または負の値であり、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;。しかし、この時点で 2 つの無限ループがあり、プログラムがヒープを上書きする可能性があります。

もう 1 つの攻撃は、異なる符号を持つよう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 に答える