Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Qualys Security Advisory
- LibreSSL (CVE-2015-5333 and CVE-2015-5334)
- ========================================================================
- Contents
- ========================================================================
- Summary
- Memory Leak (CVE-2015-5333)
- Buffer Overflow (CVE-2015-5334)
- Acknowledgments
- ========================================================================
- Summary
- ========================================================================
- In order to achieve remote code execution against the vulnerabilities
- that we recently discovered in OpenSMTPD (CVE-2015-7687), a memory leak
- is needed. Because we could not find one in OpenSMTPD itself, we started
- to review the malloc()s and free()s of its libraries, and eventually
- found a memory leak in LibreSSL's OBJ_obj2txt() function; we then
- realized that this function also contains a buffer overflow (an
- off-by-one, usually stack-based).
- The vulnerable function OBJ_obj2txt() is reachable through
- X509_NAME_oneline() and d2i_X509(), which is called automatically to
- decode the X.509 certificates exchanged during an SSL handshake (both
- client-side, unless an anonymous mode is used, and server-side, if
- client authentication is requested).
- These vulnerabilities affect all LibreSSL versions, including LibreSSL
- 2.0.0 (the first public release) and LibreSSL 2.3.0 (the latest release
- at the time of writing). OpenSSL is not affected.
- ========================================================================
- Memory Leak (CVE-2015-5333)
- ========================================================================
- OBJ_obj2txt() converts an ASN.1 object identifier (the ASN1_OBJECT a)
- into a null-terminated string of numerical subidentifiers separated by
- dots (at most buf_len bytes are written to buf).
- Large subidentifiers are temporarily stored in a BIGNUM (bl) and
- converted by BN_bn2dec() into a printable string of decimal characters
- (bndec). Many such bndec strings can be malloc()ated and memory-leaked
- in a loop, because only the last one will be free()d, after the end of
- the loop:
- 489 int
- 490 OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name)
- 491 {
- ...
- 494 char *bndec = NULL;
- ...
- 516 len = a->length;
- ...
- 519 while (len > 0) {
- ...
- 570 bndec = BN_bn2dec(bl);
- 571 if (!bndec)
- 572 goto err;
- 573 i = snprintf(buf, buf_len, ".%s", bndec);
- ...
- 598 }
- ...
- 601 free(bndec);
- ...
- 609 }
- This memory leak allows remote attackers to cause a denial of service
- (memory exhaustion) or trigger the buffer overflow described below.
- ========================================================================
- Buffer Overflow (CVE-2015-5334)
- ========================================================================
- As a result of CVE-2014-3508, OBJ_obj2txt() was modified to "Ensure
- that, at every state, |buf| is NUL-terminated." However, in LibreSSL,
- the error-handling code at the end of the function may write this
- null-terminator out-of-bounds:
- 489 int
- 490 OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name)
- 491 {
- ...
- 516 len = a->length;
- 517 p = a->data;
- 518
- 519 while (len > 0) {
- ...
- 522 for (;;) {
- 523 unsigned char c = *p++;
- 524 len--;
- 525 if ((len == 0) && (c & 0x80))
- 526 goto err;
- ...
- 528 if (!BN_add_word(bl, c & 0x7f))
- 529 goto err;
- ...
- 535 if (!bl && !(bl = BN_new()))
- 536 goto err;
- 537 if (!BN_set_word(bl, l))
- 538 goto err;
- ...
- 542 if (!BN_lshift(bl, bl, 7))
- 543 goto err;
- ...
- 546 }
- ...
- 553 if (!BN_sub_word(bl, 80))
- 554 goto err;
- ...
- 561 if (buf_len > 1) {
- 562 *buf++ = i + '0';
- 563 *buf = '\0';
- 564 buf_len--;
- 565 }
- ...
- 569 if (use_bn) {
- 570 bndec = BN_bn2dec(bl);
- 571 if (!bndec)
- 572 goto err;
- 573 i = snprintf(buf, buf_len, ".%s", bndec);
- 574 if (i == -1)
- 575 goto err;
- 576 if (i >= buf_len) {
- 577 buf += buf_len;
- 578 buf_len = 0;
- 579 } else {
- 580 buf += i;
- 581 buf_len -= i;
- 582 }
- ...
- 584 } else {
- 585 i = snprintf(buf, buf_len, ".%lu", l);
- 586 if (i == -1)
- 587 goto err;
- 588 if (i >= buf_len) {
- 589 buf += buf_len;
- 590 buf_len = 0;
- 591 } else {
- 592 buf += i;
- 593 buf_len -= i;
- 594 }
- ...
- 597 }
- 598 }
- 599
- 600 out:
- ...
- 603 return ret;
- 604
- 605 err:
- 606 ret = 0;
- 607 buf[0] = '\0';
- 608 goto out;
- 609 }
- First, in order to trigger this off-by-one buffer overflow, buf must be
- increased until it points to the first out-of-bounds character (i.e.,
- until buf_len becomes zero):
- - on the one hand, this is impossible with the code blocks at lines
- 561-564, 579-581, and 591-593;
- - on the other hand, this is very easy with the code blocks at lines
- 576-578 and 588-590 (the destination buffer is usually quite small;
- for example, it is only 80 bytes long in X509_NAME_oneline()).
- Second, the code must branch to the err label:
- - the "goto err"s at lines 574-575 and 586-587 are unreachable, because
- snprintf() cannot possibly return -1 here;
- - the "goto err" at lines 525-526 is:
- . very easy to reach in LibreSSL <= 2.0.4;
- . impossible to reach in LibreSSL >= 2.0.5, because of the "MSB must
- be clear in the last octet" sanity check that was added to
- c2i_ASN1_OBJECT():
- 286 /*
- 287 * Sanity check OID encoding:
- 288 * - need at least one content octet
- 289 * - MSB must be clear in the last octet
- 290 * - can't have leading 0x80 in subidentifiers, see: X.690 8.19.2
- 291 */
- 292 if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL ||
- 293 p[len - 1] & 0x80) {
- 294 ASN1err(ASN1_F_C2I_ASN1_OBJECT, ASN1_R_INVALID_OBJECT_ENCODING);
- 295 return (NULL);
- 296 }
- - the remaining "goto err"s are triggered by error conditions in various
- BIGNUM functions:
- . either because of a very large BIGNUM (approximately 64 megabytes,
- which is impossible in the context of an SSL handshake, where X.509
- certificates are limited to 100 kilobytes);
- . or because of an out-of-memory condition (which can be reached
- through the memory leak described above).
- This off-by-one buffer overflow allows remote attackers to cause a
- denial of service (crash) or possibly execute arbitrary code. However,
- when triggered through X509_NAME_oneline() (and therefore d2i_X509()),
- this buffer overflow is stack-based and probably not exploitable on
- OpenBSD x86, where it appears to always smash the stack canary.
- ========================================================================
- Acknowledgments
- ========================================================================
- We would like to thank the LibreSSL team for their great work and their
- incredibly quick response, and Red Hat Product Security for promptly
- assigning CVE-IDs to these issues.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement