Home / vulnerabilities MU Security Advisory 201202-01 / 201202-02
Posted on 21 March 2012
Source : packetstormsecurity.org Link
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Mu Dynamics, Inc. Security Advisories MU-201202-01 and MU-201202-02 for GnuTLS and Libtasn1
TLS record handling vulnerability in GnuTLS [MU-201202-01]
ASN.1 length decoding vulnerability in Libtasn1 [MU-201202-02]
20 March 2012
http://blog.mudynamics.com/2012/03/20/gnutls-and-libtasn1-vulns/
http://labs.mudynamics.com/advisories.html
Affected Products/Versions:
* libgnutls up to 3.0.16.
* libtasn1 up to 2.11.
Product Overview:
GnuTLS is an open source implementation of SSL, TLS and DTLS, with APIs for
encrypted network communications, along with X.509, PKCS #12, OpenPGP, and
other security data types.
Analysis:
Details for TLS record handling vulnerability in GnuTLS [MU-201202-01]:
The block cipher decryption logic in GnuTLS assumed that a record containing
any data which was a multiple of the block size was valid for further
decryption processing, leading to a heap corruption vulnerability.
The bug can be reproduced in GnuTLS 3.0.14 by creating a corrupt
GenericBlockCipher struct with a valid IV, while everything else is stripped
off the end, while the handshake message length retains its original value:
struct {
opaque IV[SecurityParameters.record_iv_length];
// corrupt: below items not sent
/*
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
};
*/
} GenericBlockCipher;
This will cause a segmentation fault, when the ciphertext_to_compressed
function tries to give decrypted data to _gnutls_auth_cipher_add_auth for HMAC
verification, even though the data length is invalid, and it should have
returned GNUTLS_E_DECRYPTION_FAILED or GNUTLS_E_UNEXPECTED_PACKET_LENGTH
instead, before _gnutls_auth_cipher_add_auth was called.
Since the error was not returned soon enough, all of the various operations
ciphertext_to_compressed performs: i.e. setting the IV, removing the padding,
setting the "true" data length with the padding stripped, checking the padding
size and padding payload and verifying HMAC could all reference undefined,
unallocated, or uninitialized memory.
There could be similar ways to reproduce this for AEAD ciphers due to the
various flows through this code, but we did not attempt to do this, and see it
as a topic for further investigation.
Below we trace the execution of the ciphertext_to_compressed function from
lib/gnutls_cipher.c. The unsafe operations and missed opportunities to return
before the heap corruption happens are marked with "***** ... *****" :
433 static int
434 ciphertext_to_compressed (gnutls_session_t session,
435 gnutls_datum_t *ciphertext,
436 uint8_t * compress_data,
437 int compress_size,
438 uint8_t type, record_parameters_st * params,
439 uint64* sequence)
440 {
...
511 case CIPHER_BLOCK:
512 if (ciphertext->size < MAX(blocksize, tag_size) || (ciphertext->size % blocksize != 0)) ***** UNSAFE *****
513 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
514
515 /* ignore the IV in TLS 1.1+
516 */
517 if (explicit_iv)
518 {
519 _gnutls_auth_cipher_setiv(¶ms->read.cipher_state,
520 ciphertext->data, blocksize);
521
522 ciphertext->size -= blocksize;
523 ciphertext->data += blocksize;
524
525 if (ciphertext->size == 0) ***** UNSAFE *****
526 {
527 gnutls_assert ();
528 return GNUTLS_E_DECRYPTION_FAILED;
529 }
530 }
...
537 if ((ret =
538 _gnutls_cipher_decrypt (¶ms->read.cipher_state.cipher,
539 ciphertext->data, ciphertext->size)) < 0)
540 return gnutls_assert_val(ret);
541
542 pad = ciphertext->data[ciphertext->size - 1] + 1; /* pad */
543
544 if ((int) pad > (int) ciphertext->size - tag_size)
545 {
546 gnutls_assert ();
547 _gnutls_record_log
548 ("REC[%p]: Short record length %d > %d - %d (under attack?)
",
549 session, pad, ciphertext->size, tag_size); ***** Message Appears During The Attack *****
550 /* We do not fail here. We check below for the
551 * the pad_failed. If zero means success.
552 */
553 pad_failed = GNUTLS_E_DECRYPTION_FAILED; ***** Execution Continues Anyway *****
554 pad %= blocksize;
555 }
556
557 length = ciphertext->size - tag_size - pad;
558
559 /* Check the padding bytes (TLS 1.x) */
...
577 /* Pass the type, version, length and compressed through
578 * MAC.
579 */
580 preamble_size =
581 make_preamble (UINT64DATA(*sequence), type,
582 length, ver, preamble);
583 ret = _gnutls_auth_cipher_add_auth (¶ms->read.cipher_state, preamble, preamble_size);
584 if (ret < 0)
585 return gnutls_assert_val(ret);
586
587 ret = _gnutls_auth_cipher_add_auth (¶ms->read.cipher_state, ciphertext->data, length); ***** UNSAFE, crashes here *****
588 if (ret < 0)
589 return gnutls_assert_val(ret); ***** Crashes Before Error Is Returned *****
...
The segmentation fault appears as follows in GDB:
Program received signal SIGSEGV, Segmentation fault.
0x003b9946 in _nettle_sha256_compress (state=0x807f128,
input=0x808f000 <Address 0x808f000 out of bounds>, k=0x3cdb60)
at sha256-compress.c:111
111 sha256-compress.c: No such file or directory.
in sha256-compress.c
(gdb) bt
#0 0x003b9946 in _nettle_sha256_compress (state=0x807f128,
input=0x808f000 <Address 0x808f000 out of bounds>, k=0x3cdb60)
at sha256-compress.c:111
#1 0x003b961b in nettle_sha256_update (ctx=0x807f128, length=4294916861,
data=0x808effc "") at sha256.c:92
#2 0x003b336d in nettle_hmac_sha256_update (ctx=0x807f050, length=4294967280,
data=0x8082b09 '