Menu

#334 A NULL pointer dereference exists in function ReadPalette() located in PluginTIFF.cpp

open
nobody
None
5
2021-08-26
2021-08-26
0x79h
No

tl;dr:
When Load TIFF format files, "bitspersample" and "samplesperpixel" are read from file. If the variable biBitCount < 16 witch calc by "bitspersample" and "samplesperpixel", FreeImage will try to write nullptr.

When the program reads a TIFF format file, it will be handed to the Load() function of the 'PluginTIFF.cpp' file. And it will call ReadPalette().
In ReadPalette function, it call FreeImage_GetPalette() to get variable "pal", then write to variable "pal" without check.

static void 
ReadPalette(TIFF *tiff, uint16_t photometric, uint16_t bitspersample, FIBITMAP *dib) {
    RGBQUAD *pal = FreeImage_GetPalette(dib);               // <---- get pal (maybe null)

    switch(photometric) {                                   // <---- write pal every case
        case PHOTOMETRIC_MINISBLACK:    // bitmap and greyscale image types
        case PHOTOMETRIC_MINISWHITE:
            // Monochrome image

            if (bitspersample == 1) {
                if (photometric == PHOTOMETRIC_MINISWHITE) {
                    pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255;         //<---- write
                    pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 0;
                } else {
                    pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;          //<---- write
                    pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
                }

            } else if ((bitspersample == 4) ||(bitspersample == 8)) {
                // need to build the scale for greyscale images
                int ncolors = FreeImage_GetColorsUsed(dib);

                if (photometric == PHOTOMETRIC_MINISBLACK) {
                    for (int i = 0; i < ncolors; i++) {
                        pal[i].rgbRed   =                                        //<---- write
                        pal[i].rgbGreen =
                        pal[i].rgbBlue  = (BYTE)(i*(255/(ncolors-1)));
                    }
                } else {
                    for (int i = 0; i < ncolors; i++) {
                        pal[i].rgbRed   =                                        //<---- write
                        pal[i].rgbGreen =
                        pal[i].rgbBlue  = (BYTE)(255-i*(255/(ncolors-1)));
                    }
                }
            }

            break;

        case PHOTOMETRIC_PALETTE:   // color map indexed
            uint16_t *red;
            uint16_t *green;
            uint16_t *blue;

            TIFFGetField(tiff, TIFFTAG_COLORMAP, &red, &green, &blue); 

            // load the palette in the DIB

            if (CheckColormap(1<<bitspersample, red, green, blue) == 16) {
                for (int i = (1 << bitspersample) - 1; i >= 0; i--) {
                    pal[i].rgbRed =(BYTE) CVT(red[i]);                             //<---- write
                    pal[i].rgbGreen = (BYTE) CVT(green[i]);
                    pal[i].rgbBlue = (BYTE) CVT(blue[i]);
                }
            } else {
                for (int i = (1 << bitspersample) - 1; i >= 0; i--) {
                    pal[i].rgbRed = (BYTE) red[i];                                 //<---- write
                    pal[i].rgbGreen = (BYTE) green[i];
                    pal[i].rgbBlue = (BYTE) blue[i];
                }
            }

            break;
    }
}

function FreeImage_GetPalette() maybe return NULL.

FreeImage_GetPalette(FIBITMAP *dib) {
    return (dib && FreeImage_GetBPP(dib) < 16) ? (RGBQUAD *)(((BYTE *)FreeImage_GetInfoHeader(dib)) + sizeof(BITMAPINFOHEADER)) : NULL;
}

unsigned DLL_CALLCONV
FreeImage_GetBPP(FIBITMAP *dib) {
    return dib ? FreeImage_GetInfoHeader(dib)->biBitCount : 0;
}

Variable biBitCount is calc by "bitspersample" and "samplesperpixel" in function "CreateImageType", and these two variable are read from file.
So if variable biBitCount less than 16, FreeImage will try to write nullptr. It allows an attacker to cause Denial of Service.


windbg:

ModLoad: 10000000 105ee000   D:\temp\_zzz\FreeImage.dll
ModLoad: 752b0000 752c4000   C:\Windows\SysWOW64\VCRUNTIME140.dll
ModLoad: 755e0000 75643000   C:\Windows\SysWOW64\WS2_32.dll
ModLoad: 77050000 7710f000   C:\Windows\SysWOW64\RPCRT4.dll
(17dc.5d5c): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=2b110000 edx=00000000 esi=77442044 edi=7744260c
eip=774e1b72 esp=0095f420 ebp=0095f44c iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!LdrpDoDebuggerBreak+0x2b:
774e1b72 cc              int     3
0:000> g
(17dc.5d5c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** WARNING: Unable to verify checksum for D:\temp\_zzz\FreeImage.dll
eax=000000ff ebx=069ceff8 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=10034fbc esp=0095f63c ebp=00000000 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
FreeImage!_TIFFmemcmp+0x3fc:
10034fbc 884500          mov     byte ptr [ebp],al          ss:002b:00000000=??
0:000> kv
 # ChildEBP RetAddr      Args to Child
00 0095f658 10037780     00000001 00000010 06982fc8 FreeImage!_TIFFmemcmp+0x3fc (FPO: [Uses EBP] [2,5,4])
01 0095f8a0 1000d9de     0095f8f4 06982fc8 00000010 FreeImage!_TIFFmemcmp+0x2bc0 (FPO: [5,139,3])
02 0095f8d4 1000da60     00000012 0095f8f4 06982fc8 FreeImage!FreeImage_LoadFromHandle+0x8e (FPO: [Uses EBP] [4,3,2])
03 0095f900 00b0107b     00000012 0697efee 00000000 FreeImage!FreeImage_Load+0x50 (FPO: [3,4,2])

TestFile:

data:image/tiff;base64,SUkqAAgAAAAHAAABAwABAAAAIAAAAAEBAwABAAAAIAAAABcBBAAMAAAACAAAABEBBAAEAAAACAAAABYBAwABAAAAAAQAABUBAwABAAAAEAAAAEMBAwABAAAAAQAAAAAAAAA=
2 Attachments

Discussion


Log in to post a comment.

MongoDB Logo MongoDB