Tarantool Msgpuck mp_check Denial Of Service Vulnerability(CVE-2016-9036)

ID SSV:96590
Type seebug
Reporter Root
Modified 2017-09-26T00:00:00



An exploitable incorrect return value vulnerability exists in the mpcheck function of Tarantool's Msgpuck library 1.0.3. A specially crafted packet can cause the mpcheck function to incorrectly return success when trying to check if decoding a map16 packet will read outside the bounds of a buffer, resulting in a denial of service vulnerability.

Tested Versions

Msgpuck 1.0.3

Product URLs


CVSSv3 Score

7.5 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H


CWE-125: Out-of-bounds Read


The Msgpuck library is used to encode and decode data that is serialized with the MsgPack (http://msgpack.org) format. This library was originally implemented to be the default library used for serialization and deserialization for the Tarantool Application Server, but is also distributed as an independent library to provide support for the MsgPack format to other C or C++ applications.

When deserializing data that is encoded with the MsgPack format, the Msgpuck library provides a function named mp_check that's used to validate the Msgpack data before it is decoded. This function takes two arguments, one to the beginning of the MsgPack data and another to the end of the data which is used to determine if decoding the packet will read outside the bounds of the data. An example of how this is intended to be used is as follows: ``` // Validate char buf[1024]; const char* b = buf; if (!mp_check(&b, b+sizeof(buf))) return FAILURE;

// Decode const char* r = buf; uint32_t count = mp_decode_map(&r); for (int i = 0; i < count; i++) { k = mp_decode_uint(&r); v = mp_decode_uint(&r); } ... ```

For optimization purposes, each of the Msgpuck functions are inlined. When calling mpcheck, the following code will be executed. First the library will read a byte that determines the type. This type will then be used to determine how many more bytes are expected for the encoded type. When the type is a map16 type, the library will check to see if the sum of the current read position and the size of a uint16t seeks past the end pointer. Due to a typo, however, the library will incorrectly return false which is a result that's different from the function's failure result. One can see that the result of a map32 returns a constant 1 when that particular failure occurs. This means that if the 2 bytes determining the map16's length cause the sum to seek past the end pointer, the function will succeed. Later when the library tries to decode this data, the library will read outside the bounds of the source data buffer. ``` msgpuck/msgpuck.h:1819

MP_IMPL int mp_check(const char data, const char end) { int k; for (k = 1; k > 0; k--) { if (mp_unlikely(data >= end)) return 1;

    uint8_t c = mp_load_u8(data);
    int l = mp_parser_hint[c];
    if (mp_likely(l &gt;= 0)) {
        *data += l;
    } else if (mp_likely(l &gt; MP_HINT)) {
        k -= l;

    uint32_t len;
    switch (l) {

... case MP_HINT_MAP_16: / MP_MAP (16) / if (mp_unlikely(data + sizeof(uint16_t) > end)) return false; // XXX: Should return 1 on failure. k += 2 * mp_load_u16(data); break; case MP_HINT_MAP_32: / MP_MAP (32) / if (mp_unlikely(data + sizeof(uint32_t) > end)) return 1; k += 2 * mp_load_u32(data); break; ... default: mp_unreachable(); } }

if (mp_unlikely(*data &gt; end))
    return 1;

return 0;

} ```

Crash Information

``` $ gdb --quiet --args ./poc-server.out ...

$ python poc

... Catchpoint 4 (signal SIGSEGV), 0x0000000000402bdc in mp_load_u16 () (gdb) x/i $pc => 0x402bdc <mp_load_u16+15>: movzwl (%rax),%eax (gdb) i r rax rax 0x7ffff7ff6fff 0x7ffff7ff6fff ```

Exploit Proof-of-Concept

In order to demonstrate the out-of-bounds read, a server that reads a MsgPack decoded map type is provided. This server allocates space for the source buffer followed by a guard-page to show the exact instruction that reads outside the allocated buffer. To compile this, simply copy the poc-server.cc file to the root of the Tarantool directory and type in the following. This will create a binary named poc-server.out which will run the MsgPack server. The arguments to this binary control which interface and port the server will bind to. $ g++ -Wall -Isrc/lib/msgpuck src/lib/msgpuck/msgpuck.c -std=c++11 -o poc-server.out poc-server.cc $ ./poc-server.out Usage: ./poc-server.out host:port $ ./poc-server.out Listening on ...

Once the server is running, the proof-of-concept can be executed against the server using python. This is done using a similar syntax. The proof-of-concept will send 5 packets. The first 3 packets that are sent will exercise the fixmap, map16, and map32 encoded types. The 4th packet will send a malformed map16 type. The 5th and last packet will trigger the vulnerability causing the out-of-bounds read. $ python poc host:port Sending a valid fixmap {1:1, 2:2, 3:3, 4:4, 5:5} Sending a valid map16 {1:1, 2:2, 3:3, 4:4, 5:5} Sending a valid map32 {1:1, 2:2, 3:3, 4:4, 5:5} Sending a invalid map16 {1:1, 2:2, 3:3, 4:4, 5:5} Sending a vulnerable map16 {1:1, 2:2, 3:3, 4:4, 5:5}


  • 2016-12-14 - Vendor Disclosure
  • 2016-12-16 - Public Release


  • Discovered by the Cisco Talos Team