Wireshark mailing list archives

Re: Mu Dynamics, Inc. Security Advisories MU-201202-01 and MU-201202-02 for GnuTLS and Libtasn1


From: Gerald Combs <gerald () wireshark org>
Date: Wed, 21 Mar 2012 15:16:02 -0700

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

The GNUTLS libraries that we ship with the Windows installers come
from the OpenSUSE build system:

https://build.opensuse.org/package/show?package=mingw32-gnutls&project=windows%3Amingw%3Awin32

I submitted a request to update GNUTLS and Libtasn1 to the most recent
releases that we can ship...

https://bugzilla.novell.com/show_bug.cgi?id=753440

...and by "that we can ship" I mean that GNUTLS 3.0 changed its
license from LGPLv2.1+ / GPLv3+ to LGPLv3+ / GPLv3+. The compatibility
matrix at

http://www.gnu.org/licenses/gpl-faq.html#AllCompatibility

suggests that this would require changing Wireshark's license. A while
back someone suggested adding support for Mozilla's Network Security
Services library:

https://bugzilla.redhat.com/show_bug.cgi?id=348461

It might be a good time to revisit that.



On 3/20/12 7:14 PM, Security wrote:
Hello Open Source Distributors,

Any libgnutls and libtasn1 packages you may have in your
environments should be updated to the latest versions in order to
correct the below vulnerabilities we released today. Various
popular packages such as Wireshark / tshark use these packages and
could also be affected.

http://www.gnu.org/software/gnutls/security.html 
http://blog.mudynamics.com/2012/03/20/gnutls-and-libtasn1-vulns/

Regards, Matthew Hall Mu Dynamics Research Team Mu Dynamics, Inc.

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(&params->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 (&params->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?)\n", 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 (&params->read.cipher_state, preamble,
preamble_size); 584          if (ret < 0) 585            return
gnutls_assert_val(ret); 586 587          ret =
_gnutls_auth_cipher_add_auth (&params->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 '\017' <repeats 16 times>) at hmac-sha256.c:43 #3
0x0021a749 in wrap_nettle_hmac_update (_ctx=0x807f050,
text=0x8082b09, textsize=4294967280) at mac.c:231 #4  0x00158233 in
_gnutls_hmac (handle=0x807ef9c, text=0x8082b09, textlen=4294967280)
at ./gnutls_hash_int.h:73 #5  0x00158b35 in
_gnutls_auth_cipher_add_auth (handle=0x807ef78, text=0x8082b09,
textlen=-16) at gnutls_cipher_int.c:190 #6  0x001473de in
ciphertext_to_compressed (session=0x807d810, ciphertext=0xbfffe8a4,
compress_data=0x8083da4 "", compress_size=16384, type=22 '\026',
params=0x807ed48, sequence=0x807efcc) at gnutls_cipher.c:587 #7
0x00145cdc in _gnutls_decrypt (session=0x807d810, 
ciphertext=0x8082af9 "\252\257C/7\301\362\352h|d\275#\312\027\312",
'\017' <repeats 16 times>, ciphertext_size=32, data=0x8083da4 "",
max_data_size=16384, type=GNUTLS_HANDSHAKE, params=0x807ed48,
sequence=0x807efcc) at gnutls_cipher.c:159 ... (gdb)

The segmentation fault appears as follows in Valgrind Memcheck:

==29586== Invalid read of size 1 ==29586==    at 0x40274B9: memcpy
(mc_replace_strmem.c:497) ==29586==    by 0x42BC5A6:
nettle_sha256_update (sha256.c:92) ==29586==    by 0x42B636C:
nettle_hmac_sha256_update (hmac-sha256.c:43) ==29586==    by
0x411C748: wrap_nettle_hmac_update (mac.c:231) ==29586==    by
0x405A232: _gnutls_hmac (gnutls_hash_int.h:73) ==29586==    by
0x405AB34: _gnutls_auth_cipher_add_auth (gnutls_cipher_int.c:190) 
==29586==    by 0x40493DD: ciphertext_to_compressed
(gnutls_cipher.c:587) ==29586==    by 0x4047CDB: _gnutls_decrypt
(gnutls_cipher.c:159) ... ==29586==  Address 0x4464411 is 0 bytes
after a block of size 89 alloc'd ==29586==    at 0x4024F12: calloc
(vg_replace_malloc.c:467) ==29586==    by 0x4049AE4: _mbuffer_alloc
(gnutls_mbuffers.c:288) ==29586==    by 0x4049C49:
_mbuffer_linearize (gnutls_mbuffers.c:349) ==29586==    by
0x40462FB: _gnutls_recv_in_buffers (gnutls_record.c:996) ==29586==
by 0x404D01C: _gnutls_handshake_io_recv_int
(gnutls_buffers.c:1174) ==29586==    by 0x4050383:
_gnutls_recv_handshake (gnutls_handshake.c:1260) ... ==29586==
Invalid read of size 1 ... ==29586==  Address 0x4464412 is 1 bytes
after a block of size 89 alloc'd ... ==29586== Process terminating
with default action of signal 11 (SIGSEGV) ==29586==  Access not
within mapped region at address 0x4779000 ==29586==    at
0x42BC946: _nettle_sha256_compress (sha256-compress.c:111) 
==29586==    by 0x42BC61A: nettle_sha256_update (sha256.c:92) 
==29586==    by 0x42B636C: nettle_hmac_sha256_update
(hmac-sha256.c:43) ==29586==    by 0x411C748:
wrap_nettle_hmac_update (mac.c:231) ==29586==    by 0x405A232:
_gnutls_hmac (gnutls_hash_int.h:73) ==29586==    by 0x405AB34:
_gnutls_auth_cipher_add_auth (gnutls_cipher_int.c:190) ==29586==
by 0x40493DD: ciphertext_to_compressed (gnutls_cipher.c:587) ... 
Segmentation fault

Details for ASN.1 length decoding vulnerability in Libtasn1
[MU-201202-02]:

Various functions using the ASN.1 length decoding logic in Libtasn1
were incorrectly assuming that the return value from
asn1_get_length_der is always less than the length of the enclosing
ASN.1 structure, which is only true for valid structures and not
for intentionally corrupt or otherwise buggy structures.

Here is an example of unsafe asn1_get_length_der usage from 
lib/minitasn1/decoding.c, in the asn1_der_decoding function:

0812    asn1_retCode 0813    asn1_der_decoding (ASN1_TYPE *
element, const void *ider, int len, 0814                       char
*errorDescription) 0815    { ... 1033                case
TYPE_ENUMERATED: 1034                  len2 = 1035
asn1_get_length_der (der + counter, len - counter, &len3); 1036
if (len2 < 0) 1037                    return ASN1_DER_ERROR; 1038
if (len2 + len3 > len - counter) 1039                    return
ASN1_DER_ERROR; 1040                  _asn1_set_value (p, der +
counter, len3 + len2); 1041                  counter += len3 +
len2; 1042                  move = RIGHT; 1043
break;

The above call to asn1_get_length_der was returning an impossibly
large value of 2GB when the Mu analyzer generated corrupt lengths
fields for versions, serial numbers, public key info, and signature
structures in X.509 client certificates, but this could happen in
any use of Libtasn1 that is relying upon asn1_get_length_der, not
just SSL, TLS, or GnuTLS.

The asn1_der_decoding function failed to check for cases when 
asn1_get_length_der returned a length larger than the enclosing
structure's (void* ider) own length (int len).

When _asn1_set_value was called anyway, it contained a memcpy
operation which assumed the arguments are valid, which tried copy
2GB of memory, leading to a heap corruption vulnerability.

Simon Josefsson, Libtasn1 maintainer, described the patch as
follows: "the real bug was not in asn1_get_length_der() even if
that is the function we patch[ed]. The callers of that function
that did not check that the return values are sane were buggy.
However, instead of fixing all callers, ... we went for the simpler
solution to let the function return an error for a situation that
is unlikely to occur without malicious interaction or data 
corruption."

The asn1_der_decoding function shown above is now safe, because 
asn1_get_length_der was updated to "[return] -4 when the decoded
length value plus @len would exceed @der_len," so asn1_der_decoding
returns ASN1_DER_ERROR before it can call _asn1_set_value to
trigger the segmentation fault.

Abbreviated GDB Backtrace after the segmentation fault:

(gdb) bt #0  __memcpy_ia32 () at
../sysdeps/i386/i686/multiarch/../memcpy.S:75 #1  0x00000001 in ??
() #2  0x0020eadc in _asn1_set_value (node=0x807ff50,
value=0x807ed5c, len=2147483652) at parser_aux.c:228 #3  0x0020a646
in asn1_der_decoding (element=0x8078000, ider=0x807ed4e, len=687,
errorDescription=0x0) at decoding.c:1036 #4  0x001bc7da in
gnutls_x509_crt_import (cert=0x8078000, data=0xbfffeae8, 
format=GNUTLS_X509_FMT_DER) at x509.c:226 #5  0x00176d16 in
gnutls_pcert_import_x509_raw (pcert=0x807d610, cert=0xbfffeae8,
format=GNUTLS_X509_FMT_DER, flags=0) at gnutls_pcert.c:201 ... 
(gdb)

Response / Solution:

TLS record handling vulnerability in GnuTLS [MU-201202-01] is fixed
in GnuTLS 3.0.15. For more details, see 
http://article.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/5912
.

ASN.1 length decoding vulnerability in Libtasn1 [MU-201202-02] is
fixed in Libtasn1 2.12 and GnuTLS 3.0.16. For more details, see 
http://lists.gnu.org/archive/html/help-libtasn1/2012-03/msg00000.html
and 
http://article.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/5932
.

History:

Mon, 27 Feb 2012 14:13:45 -0800: TLS Record handling issue
reported. Tue, 28 Feb 2012 10:29:46 +0100: TLS Record handling
patch created. Fri, 02 Mar 2012 18:42:05 +0000: GnuTLS 3.0.15
release announced. Fri, 02 Mar 2012 14:04:31 -0800: ASN.1 length
decoding issue reported. Wed, 14 Mar 2012 01:04:36 +0100: ASN.1
length decoding patch created. Mon, 19 Mar 2012 10:57:42 +0100:
Libtasn1 2.12 release announced. Tue, 20 Mar 2012 23:40:00 +0000:
Advisory released to the public.

See also:

http://article.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/5912


http://article.gmane.org/gmane.comp.encryption.gpg.gnutls.devel/5932
http://lists.gnu.org/archive/html/help-libtasn1/2012-03/msg00000.html


http://git.savannah.gnu.org/gitweb/?p=gnutls.git;a=commitdiff;h=b495740f2ff66550ca9395b3fda3ea32c3acb185
http://git.savannah.gnu.org/gitweb/?p=libtasn1.git;a=commitdiff;h=6e534bf4fb3144be51c928ed3efcf9c36055c9c7

 Credit:

These vulnerabilities were discovered by Matthew Hall
<mhall () mudynamics com>, Senior Network Protocol Software Engineer
at Mu Dynamics, via code inspection and protocol fuzzing using a Mu
4000 security analyzer.

http://blog.mudynamics.com/wp-content/uploads/2012/03/pgpkey.txt

Mu Dynamics is the leading provider of solutions ensuring the
performance and security of both applications and network
infrastructure. The company's innovative solutions enable customers
to confidently meet the challenges posed by today's rapidly
changing networks. This includes the ever-growing number of 
applications and devices on the network, and the swift transition
to mobile, virtual and cloud environments. Hundreds of service
providers, enterprises, application developers and network
equipment manufacturers count on its purpose-built solutions, like
Mu Studio and Blitz, to ensure their applications and networks are
scalable and secure. Mu Dynamics is headquartered in Sunnyvale,
California. 
___________________________________________________________________________


Sent via:    Wireshark-dev mailing list <wireshark-dev () wireshark org>
Archives:    http://www.wireshark.org/lists/wireshark-dev 
Unsubscribe: https://wireshark.org/mailman/options/wireshark-dev 
mailto:wireshark-dev-request () wireshark org?subject=unsubscribe

- -- 
Join us for Sharkfest ’12! · Wireshark® Developer and User Conference
Berkeley, CA, June 24-27 · sharkfest.wireshark.org
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk9qUyIACgkQpw8IXSHylJrJSwCgqZWz1v7gP7s/b/+j9nZaJ6nW
0psAmgPx/RJxdrYbNwJti4gN6YGmUf33
=ZtFw
-----END PGP SIGNATURE-----
___________________________________________________________________________
Sent via:    Wireshark-dev mailing list <wireshark-dev () wireshark org>
Archives:    http://www.wireshark.org/lists/wireshark-dev
Unsubscribe: https://wireshark.org/mailman/options/wireshark-dev
             mailto:wireshark-dev-request () wireshark org?subject=unsubscribe

Current thread: