inikep / lizard

Lizard (formerly LZ5) is an efficient compressor with very fast decompression. It achieves compression ratio that is comparable to zip/zlib and zstd/brotli (at low and medium compression levels) at decompression speed of 1000 MB/s and faster.
Other
644 stars 40 forks source link

Negative size passed to memcpy resulting in memory corruption (lib/lizard_decompress_liz.h:207) #16

Closed glen-mac closed 5 years ago

glen-mac commented 6 years ago

Hey there,

I have come across a vulnerability in the lizard decompressor, whereby a negative size integer is passed to memcpy(). This occurs in lib/lizard_decompress_liz.h:207.

memcpy(op, ctx->literalsPtr, length);

Since memcpy() takes the length and treats it as a size_t, this results in an excessive copy from ctx->literalsPtr into op.

void *memcpy(void *dest, const void *src, size_t n);

This was found while fuzzing commit 6a1ed71450148c8aed57de3179b1bdd81800bada (current latest as of this date).

By controlling the number of bytes passed as length, this results in memory corruption which can lead to execution control.

Find the POC file here: poc.zip.

As follows is the ASAN output:

$ ./lizard_afl -d crash.file /dev/null
=================================================================
==26522==ERROR: AddressSanitizer: negative-size-param: (size=-8)
    #0 0x4ae273 in __asan_memcpy (/root/lizard/lizard_afl+0x4ae273)
    #1 0x51a9b2 in Lizard_decompress_LIZv1 /root/lizard/programs/../lib/lizard_decompress_liz.h:207:5
    #2 0x51a9b2 in Lizard_decompress_generic /root/lizard/programs/../lib/lizard_decompress.c:241
    #3 0x51a9b2 in Lizard_decompress_safe_usingDict /root/lizard/programs/../lib/lizard_decompress.c:362
    #4 0x634386 in LizardF_decompress /root/lizard/programs/../lib/lizard_frame.c:1197:31
    #5 0x645fc1 in LizardIO_decompressLizardF /root/lizard/programs/lizardio.c:676:26
    #6 0x645fc1 in selectDecoder /root/lizard/programs/lizardio.c:767
    #7 0x645fc1 in LizardIO_decompressSrcFile /root/lizard/programs/lizardio.c:803
    #8 0x644379 in LizardIO_decompressDstFile /root/lizard/programs/lizardio.c:831:5
    #9 0x643b80 in LizardIO_decompressFilename /root/lizard/programs/lizardio.c:850:30
    #10 0x64caf8 in main /root/lizard/programs/lizardcli.c:560:32
    #11 0x7f4d32b69f44 in __libc_start_main /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:287
    #12 0x419cb5 in _start (/root/lizard/lizard_afl+0x419cb5)

0x7f4d33c1e86e is located 110 bytes inside of 131072-byte region [0x7f4d33c1e800,0x7f4d33c3e800)
allocated by thread T0 here:
    #0 0x4c418c in calloc (/root/lizard/lizard_afl+0x4c418c)
    #1 0x636a0b in LizardF_decodeHeader /root/lizard/programs/../lib/lizard_frame.c:840:33

SUMMARY: AddressSanitizer: negative-size-param (/root/lizard/lizard_afl+0x4ae273) in __asan_memcpy
==26522==ABORTING

In the example above, with a memcpy size of -8, this value is interpreted as an unsigned integer and the memcpy continues until there is a page fault due to unmapped memory and the process terminates:

root at s127422 in ~/lizard (lizard●●)
$ ./lizard -d crash.file /dev/null
[1]    17128 segmentation fault  ./lizard -d crash.file /dev/null

To demonstrate that the memcpy size value can be controlled by an attacker, I have attached a series of crashes that result from a differing memcpy size value. lizard_crashes.zip

inikep commented 6 years ago

Thanks for reporting. It is fixed with https://github.com/inikep/lizard/commit/02491c71c2e6fd5c10997404df2f18d0fc7afadb

Grossdm commented 5 years ago

@inikep, if this is indeed fixed and @glen-mac has no other concerns, perhaps you can close this issue now?

Just trying to help keep your repo tidy. 😆

Thanks, Doug®