Vulnerabilities > CVE-2017-2780 - Out-of-bounds Write vulnerability in Matrixssl 3.8.7B

047910
CVSS 9.8 - CRITICAL
Attack vector
NETWORK
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
HIGH
Integrity impact
HIGH
Availability impact
HIGH
network
low complexity
matrixssl
CWE-787
critical

Summary

An exploitable heap buffer overflow vulnerability exists in the X509 certificate parsing functionality of InsideSecure MatrixSSL 3.8.7b. A specially crafted x509 certificate can cause a buffer overflow on the heap resulting in remote code execution. To trigger this vulnerability, a specially crafted x509 certificate must be presented to the vulnerable client or server application when initiating secure connection.

Vulnerable Configurations

Part Description Count
Application
Matrixssl
1

Common Weakness Enumeration (CWE)

Seebug

bulletinFamilyexploit
description### Summary An exploitable heap buffer overflow vulnerability exists in the X509 certificate parsing functionality of InsideSecure MatrixSSL 3.8.7b. A specially crafted x509 certificate can cause a buffer overflow on the heap resulting in remote code execution. To trigger this vulnerability, a specially crafted x509 certificate must be presented to the vulnerable client or server application when initiating secure connection. ### Tested Versions InsideSecure MatrixSSL 3.8.7b ### Product URLs http://www.matrixssl.org/ ### CVSSv3 Score 8.1 - CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H ### CWE CWE-122: Heap-based Buffer Overflow ### Details MatrixSSL is a secure socket layer cryptographic library aimed at embedded and IoT systems due to it’s low code footprint and RAM utilization. It is supported on many embedded platforms, fully compatible with other SSL implementations and FIPS140-2 compliant. While parsing an x509 certificate in DER form there exist an issue in with ASN1 encoded sequences. Specifically, while parsing x509 SubjectDomainPolicy PolicyMappings extension, an array of one size is allocated on the heap, but due to specially encoded OIDs, one more element can be copied into it. Specifically in the following code in `crypto/keyformat/x509.c` in fucntion `parsePolicyMappings`: ``` if (getAsnLength(&p, (uint32)(polMappingsEnd - p), &len) < 0 || [1] (uint32)(polMappingsEnd - p) < len) { psTraceCrypto("getAsnLength failure in policyMappings parsing\n"); return PS_PARSE_FAIL; } memset(oid, 0, sizeof(oid)); if ((oidlen = psParseOid(p, len, oid)) < 1) { [2] psTraceCrypto("Malformed extension OID\n"); return PS_PARSE_FAIL; } p += len; pol_map->subjectDomainPolicy = psMalloc(pool, len*sizeof(uint32_t)); [3] memset(pol_map->subjectDomainPolicy, 0, len*sizeof(uint32_t)); for (i = 0; i < oidlen; i++) { pol_map->subjectDomainPolicy[i] = oid[i]; [4] } ``` At [1] `getAsnLength`is called to determine the length of the following ASN1 OID field, the value is stored in `len` variable. At [2], `len` is used as a parameter to `psParseOid` function. At [3], an array for OIDs is allocated using `len` for number of elements. In a for loop at [4], OIDs are coppied into the allocated array. If `oidlen` is bigger than `len`, an overflow can happen. If we take a look at `psParseOid` we can observe the following key points: ``` oid[0] = *der / 40; oid[1] = *der % 40; [1] der++; /* Zero the remainder of OID and leave n == 2 */ for (n = MAX_OID_LEN - 1; n > 2; n--) { oid[n] = 0; } while (der < end && n < MAX_OID_LEN) { /* If the high bit is 0, it's short form variable length quantity */ if (!(*der & 0x80)) { [2] oid[n++] = *der++; } else { sanity = 0; /* Long form. High bit means another (lower) 7 bits following */ do { oid[n] |= (*der & 0x7F); [3] /* A clear high bit ends the byte sequence */ if (!(*der & 0x80)) { break; } /* Allow a maximum of 4 x 7 bit shifts (28 bits) */ if (++sanity > 4) { return 0; } /* Make room for the next 7 bits */ oid[n] <<= 7; der++; } while (der < end); der++; n++; } } ``` In the above code, an important thing to note is that at [1], a single byte from the buffer initializes two oid entries. Then, at [2], is the soft form is used, both `n` counter and `der` buffer pointer are incremented by one. And finaly, in a do-while loop around [3], a long form OIDs are parsed, which can consume more than one byte per OID entry. Therefore, if a specially crafted x509 certificate can have a PolicyMapping with an ASN1 buffer of length N bytes (as returned by `getAsnLength`), but actually contain N+1 OIDs (two from first byte, and all other bytes being short form). As an example, the attached PoC x509 certificate has the following OID sequence: ``` 060a60764801650302010502 ``` This decodes to length 10. An array `subjectDomainPolicy` will be allocated for 10 entries only, but 11 will be copied into it (since none are in long form), causing a buffer overflow. A simple fix for this issue would be to use `oidLen` instead of `len` when allocating mentioned arrays. ### Crash Information ``` ==70539==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60400000dd38 at pc 0x00000050df22 bp 0x7fff86e24df0 sp 0x7fff86e24de8 WRITE of size 4 at 0x60400000dd38 thread T0 #0 0x50df21 in parsePolicyMappings /ramdisk/triage/matrixssl/crypto/keyformat/x509.c:2299 #1 0x50df21 in getExplicitExtensions /ramdisk/triage/matrixssl/crypto/keyformat/x509.c:3071 #2 0x50df21 in ?? ??:0 #3 0x4ff704 in psX509ParseCert /ramdisk/triage/matrixssl/crypto/keyformat/x509.c:871 #4 0x4ff704 in ?? ??:0 #5 0x4e73ad in main /ramdisk/triage/matrixssl/matrixssl/test/certValidate.c:171 #6 0x4e73ad in ?? ??:0 #7 0x7f0345b6f82f in __libc_start_main /build/glibc-Qz8a69/glibc-2.23/csu/../csu/libc-start.c:291 #8 0x7f0345b6f82f in ?? ??:0 #9 0x418a98 in _start ??:? #10 0x418a98 in ?? ??:0 0x60400000dd38 is located 0 bytes to the right of 40-byte region [0x60400000dd10,0x60400000dd38) allocated by thread T0 here: #0 0x4b8a38 in __interceptor_malloc ??:? #1 0x4b8a38 in ?? ??:0 #2 0x50a23f in parsePolicyMappings /ramdisk/triage/matrixssl/crypto/keyformat/x509.c:2295 #3 0x50a23f in getExplicitExtensions /ramdisk/triage/matrixssl/crypto/keyformat/x509.c:3072 #4 0x50a23f in ?? ??:0 #5 0x4ff704 in psX509ParseCert /ramdisk/triage/matrixssl/crypto/keyformat/x509.c:871 #6 0x4ff704 in ?? ??:0 #7 0x4e73ad in main /ramdisk/triage/matrixssl/matrixssl/test/certValidate.c:171 #8 0x4e73ad in ?? ??:0 #9 0x7f0345b6f82f in __libc_start_main /build/glibc-Qz8a69/glibc-2.23/csu/../csu/libc-start.c:291 #10 0x7f0345b6f82f in ?? ??:0 SUMMARY: AddressSanitizer: heap-buffer-overflow (/ramdisk/triage/matrixssl/matrixssl/test/certValidate+0x50df21) Shadow bytes around the buggy address: 0x0c087fff9b50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9b60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9b70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c087fff9b90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c087fff9ba0: fa fa 00 00 00 00 00[fa]fa fa 00 00 00 00 00 fa 0x0c087fff9bb0: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa 0x0c087fff9bc0: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa 0x0c087fff9bd0: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa 0x0c087fff9be0: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa 0x0c087fff9bf0: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==70539==ABORTING ``` ### Mitigation ``` diff --git a/crypto/keyformat/x509.c b/crypto/keyformat/x509.c index 33559b5..8822a2d 100644 --- a/crypto/keyformat/x509.c +++ b/crypto/keyformat/x509.c @@ -2266,8 +2266,8 @@ int32_t parsePolicyMappings(psPool_t *pool, } p += len; - pol_map->issuerDomainPolicy = psMalloc(pool, len*sizeof(uint32_t)); - memset(pol_map->issuerDomainPolicy, 0, len*sizeof(uint32_t)); + pol_map->issuerDomainPolicy = psMalloc(pool, oidlen*sizeof(uint32_t)); + memset(pol_map->issuerDomainPolicy, 0, oidlen*sizeof(uint32_t)); for (i = 0; i < oidlen; i++) { pol_map->issuerDomainPolicy[i] = oid[i]; @@ -2292,8 +2292,8 @@ int32_t parsePolicyMappings(psPool_t *pool, } p += len; - pol_map->subjectDomainPolicy = psMalloc(pool, len*sizeof(uint32_t)); - memset(pol_map->subjectDomainPolicy, 0, len*sizeof(uint32_t)); + pol_map->subjectDomainPolicy = psMalloc(pool, oidlen*sizeof(uint32_t)); + memset(pol_map->subjectDomainPolicy, 0, oidlen*sizeof(uint32_t)); for (i = 0; i < oidlen; i++) { pol_map->subjectDomainPolicy[i] = oid[i]; ``` ### Timeline * 2017-02-07 - Vendor Disclosure * 2017-06-22 - Public Release ### CREDIT * Discovered by Aleksandar Nikolic of Cisco Talos.
idSSV:96481
last seen2017-11-19
modified2017-09-14
published2017-09-14
reporterRoot
titleInsideSecure MatrixSSL x509 certificate SubjectDomainPolicy Remote Code Execution Vulnerability(CVE-2017-2780)

Talos

idTALOS-2017-0276
last seen2019-05-29
published2017-06-22
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2017-0276
titleInsideSecure MatrixSSL x509 certificate SubjectDomainPolicy Remote Code Execution Vulnerability