Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2021-44591: Memory allocation failure caused by the missing boundary check in parseSWF_DEFINELOSSLESS2 · Issue #235 · libming/libming

In libming 0.4.8, the parseSWF_DEFINELOSSLESS2 function in util/parser.c lacks a boundary check that would lead to denial-of-service attacks via a crafted SWF file.

CVE
#linux

version: master(commit 04aee52 )
command: listswf $FILE

root:/path_to_libming/build/bin# ./listswf poc
==26225==WARNING: AddressSanitizer failed to allocate 0xfffffffffffffff9 bytes
==26225==AddressSanitizer's allocator is terminating the process instead of returning 0
==26225==If you don't like this behavior set allocator_may_return_null=1
==26225==AddressSanitizer CHECK failed: /mnt/d/CLib/llvm-6.0.1/projects/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc:225 "((0)) != (0)" (0x0, 0x0)
    #0 0x4e3385 in __asan::AsanCheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) /mnt/d/CLib/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_rtl.cc:69
    #1 0x500c45 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) /mnt/d/CLib/llvm-6.0.1/projects/compiler-rt/lib/sanitizer_common/sanitizer_termination.cc:79
    #2 0x4e9786 in __sanitizer::ReportAllocatorCannotReturnNull() /mnt/d/CLib/llvm-6.0.1/projects/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc:225
    #3 0x4e97c6 in __sanitizer::ReturnNullOrDieOnFailure::OnBadRequest() /mnt/d/CLib/llvm-6.0.1/projects/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc:241
    #4 0x41f676 in __asan::asan_malloc(unsigned long, __sanitizer::BufferedStackTrace*) /mnt/d/CLib/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_allocator.cc:856
    #5 0x4da20b in malloc /mnt/d/CLib/llvm-6.0.1/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:89
    #6 0x5b7e7e in readBytes /path_to_libming/util/read.c:252:17
    #7 0x59b963 in parseSWF_DEFINELOSSLESS2 /path_to_libming/util/parser.c:2168:38
    #8 0x546cf9 in blockParse /path_to_libming/util/blocktypes.c:145:14
    #9 0x53bc13 in readMovie /path_to_libming/util/main.c:269:11
    #10 0x53a0d6 in main /path_to_libming/util/main.c:354:2
    #11 0x7fce52d93bf6 in __libc_start_main /build/glibc-S9d2JN/glibc-2.27/csu/../csu/libc-start.c:310
    #12 0x41a2f9 in _start (/path_to_libming/build/bin/listswf+0x41a2f9)

The cause of this bug is the lack of boundary checks. Specifically, in the parseSWF_DEFINELOSSLESS2 function, the size of end and fileOffset is not compared when readBytes is called. As a result, end-fileOffset may be a negative integer, which eventually leads to allocation failure.

The detailed call chain analysis is as follows.
Download poc

static void readMovie(FILE *f) { int block, type, length, nextFrame=0; SWF_Parserstruct *blockp; for (;;) { if(filelen_check_fails(2)) break; // Read 16 bits from the input file, the block is controlled by the attacker block = readUInt16 (f); type = block >> 6;

             // length = block & 0x3f, which means length<=3f
    length = block & ((1 << 6) - 1);
    if (length == 63)       /\* it's a long block. \*/ 
    {
        if(filelen\_check\_fails(4))
            break;
        unsigned long real\_length = readUInt32 (f);

                    if (real\_length > INT\_MAX) {
                SWF\_warn(" Could not process long block with length %lu:"
                                 " blocks with length > %d not supported on this system\\n",
                                 real\_length, INT\_MAX);
                        continue;
                    } else {
                        length = (int) real\_length;
                    }
    }
    nextFrame = fileOffset+length;
    
    if(filelen\_check\_fails(length))
        break;
    blockp= blockParse(f, length, type);
            ......
}
......

}

SWF_Parserstruct * blockParse (FILE *f, int length, SWFBlocktype header) { int i;

for (i = 0; i < numBlocks; i++) { // Select the corresponding parser to parse if (blocks[i].type == header) { return blocks[i].parser(f,length); } } return parseSWF_UNKNOWNBLOCK(f, length); }

SWF_Parserstruct * parseSWF_DEFINELOSSLESS2 (FILE * f, int length) { int end = fileOffset + length; PAR_BEGIN (SWF_DEFINELOSSLESS2);

parserrec->CharacterID = readUInt16 (f); // Read 16 bits from the input file, and fileOffset = fileOffset+2 parserrec->BitmapFormat = readUInt8 (f); // Read 8 bits from the input file, and fileOffset = fileOffset+1 parserrec->BitmapWidth = readUInt16 (f); // Read 16 bits from the input file, and fileOffset = fileOffset+2 parserrec->BitmapHeight = readUInt16 (f); Read 16 bits from the input file, and fileOffset = fileOffset+2 if( parserrec->BitmapFormat == 3 /* 8-bit */ ) { parserrec->BitmapColorTableSize = readUInt8 (f); } // When length=0, at this moment end=Old_fileOffset, fileOffset=Old_fileOffset+7, then end-fileOffset will be equal to -7 which is a negative integer parserrec->ZlibBitmapData = (UI8 *)readBytes (f,end-fileOffset);

PAR_END; }

char *readBytes(FILE *f, unsigned long size) {

if (size < 1) { #if DEBUG SWF_warn("readBytes: want to read %lu < 1 bytes: Handling a 0\n", size); #endif size = 0; }

unsigned long i; char *buf; // The parameter size’s type is unsigned long. Given a negative integer as input, it will be treated as a large unsigned integer and passed to malloc, causing allocation failures. buf = (char *)malloc(sizeof(char)*size);

if (buf == NULL) { fprintf(stderr, "readBytes: Failed to allocate %lu bytes", sizeof(char) * size); exit(-1); }

for(i=0;i<size;i++) { buf[i]=(char)readUInt8(f); }

return buf; }

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907