Skip to Content.
Sympa Menu

cacert-sysadm - URGENT OpenSSL flaw Fwd: [Discuss] [Full-disclosure] incorrect integer conversions in OpenSSL can result in memory corruption.

cacert-sysadm AT lists.cacert.org

Subject: CAcert System Admins discussion list

List archive

URGENT OpenSSL flaw Fwd: [Discuss] [Full-disclosure] incorrect integer conversions in OpenSSL can result in memory corruption.


Chronological Thread 
  • From: "Philipp Gühring" <pg AT futureware.at>
  • To: critical-admin AT cacert.org, wytze AT cacert.org, iang AT cacert.org, iang AT iang.org, cacert-sysadm AT lists.cacert.org
  • Subject: URGENT OpenSSL flaw Fwd: [Discuss] [Full-disclosure] incorrect integer conversions in OpenSSL can result in memory corruption.
  • Date: Thu, 19 Apr 2012 17:17:52 +0200

Hi,

I think CAcert is directly affected by this bug, and we should upgrade to
the OpenSSL 1.0.1a immediately. If we want to wait for Debian packages,
then we should turn off the webdb until Debian packages are available.

http://openssl.org/news/
http://openssl.org/news/secadv_20120419.txt

Best regards,
Philipp Gühring


-----Original Message-----
From: "L. Aaron Kaplan" 
<kaplan AT cert.at>
To: Gühring Philipp 
<pg AT futureware.at>,
 Subik Matthias
<matthias AT subik.at>,
 Grigg Ian 
<iang AT iang.org>
Date: Thu, 19 Apr 2012 16:51:43 +0200
Subject: Fwd: [Discuss] [Full-disclosure] incorrect integer conversions in
OpenSSL can result in memory corruption.



CACert.org?

--> please check this if it is a problem for you. I assume it is a
serious problem for you.


Begin forwarded message:

> From: "L. Aaron Kaplan" 
> <kaplan AT cert.at>
> Subject: [Discuss] [Full-disclosure] incorrect integer conversions in
OpenSSL can result in memory corruption.
> Date: April 19, 2012 4:44:05 PM GMT+02:00
> To: Discuss CERT 
> <discuss AT lists.cert.at>
> 
> Bitte um Beachtung und rasches patchen!
> Das wirkt sehr ungut. 
> 
> Wir schaetzen, dass hier primaer Services betroffen sind, die
Zertifikate entgegennehmen (oder sonstige Daten, die ASN1 encoded sein
koennen).
> Vermutlich ist ein normaler Webserver mit TLS/SSL (oder Mailserver)
nicht betroffen.
> Trotzdem raten wir zu raschem patchen!
> Hier handelt es sich um einen ganz klassischen Heap Overflow in der
Openssl library. 
> 
> 
> Mfg,
> L. Aaron Kaplan
> CERT.at
> 
> 
> Begin forwarded message:
> 
> Zusammenfassung:
>
>> """
>> asn1_d2i_read_bio in OpenSSL contains multiple integer errors that can
>> cause memory corruption when parsing encoded ASN.1 data. This error
can
>> be exploited on systems that parse untrusted data, such as X.509
>> certificates or RSA public keys.
>> """
>
> 
> Original
> 
>> -------- Original Message --------
>> Subject: [Full-disclosure] incorrect integer conversions in OpenSSL
can
>> result in memory corruption.
>> Date: Thu, 19 Apr 2012 12:35:22 +0200
>> From: Tavis Ormandy 
>> <taviso AT cmpxchg8b.com>
>> To: 
>> <full-disclosure AT lists.grok.org.uk>
>
>> Incorrect integer conversions in OpenSSL can result in memory
corruption.
>>
-------------------------------------------------------------------------
-
>
>> CVE-2012-2110
>
>> This advisory is intended for system administrators and developers
exposing
>> OpenSSL in production systems to untrusted data.
>
>> asn1_d2i_read_bio in OpenSSL contains multiple integer errors that can
cause
>> memory corruption when parsing encoded ASN.1 data. This error can be
>> exploited
>> on systems that parse untrusted data, such as X.509 certificates or
RSA
>> public
>> keys.
>
>> The following context structure from asn1.h is used to record the
>> current state
>> of the decoder:
>
>> typedef struct asn1_const_ctx_st
>> {
>>   const unsigned char *p;/* work char pointer */
>>   int eos;    /* end of sequence read for indefinite encoding */
>>   int error;  /* error code to use when returning an error */
>>   int inf;    /* constructed if 0x20, indefinite is 0x21 */
>>   int tag;    /* tag from last 'get object' */
>>   int xclass; /* class from last 'get object' */
>>   long slen;  /* length of last 'get object' */
>>   const unsigned char *max; /* largest value of p allowed */
>>   const unsigned char *q;/* temporary variable */
>>   const unsigned char **pp;/* variable */
>>   int line;   /* used in error processing */
>> } ASN1_const_CTX;
>
>> These members are populated via calls to ASN1_get_object and
asn1_get_length
>> which have the following prototypes
>
>> int ASN1_get_object(const unsigned char **pp,
>>                   long *plength,
>>                   int *ptag,
>>                   int *pclass,
>>                   long omax);
>
>> int asn1_get_length(const unsigned char **pp,
>>                   int *inf,
>>                   long *rl,
>>                   int max);
>
>> The lengths are always stored as signed longs, however,
asn1_d2i_read_bio
>> casts ASN1_const_CTX->slen to a signed int in multiple locations. This
>> truncation can result in numerous conversion problems.
>
>> The most visible example on x64 is this cast incorrectly interpreting
the
>> result of asn1_get_length.
>
>> 222             /* suck in c.slen bytes of data */
>> 223             want=(int)c.slen;
>
>> A simple way to demonstrate this is to prepare a DER certificate that
>> contains
>> a length with the 31st bit set, like so
>
>> $ dumpasn1 testcase.crt
>> 0 NDEF: [PRIVATE 3] {
>>  2 2147483648:   [1]
>>       ...
>>  }
>
>> Breakpoint 2, asn1_d2i_read_bio (in=0x9173a0, pb=0x7fffffffd8f0) at
>> a_d2i_fp.c:224
>> 224             if (want > (len-off))
>> (gdb) list
>> 219             }
>> 220         else
>> 221             {
>> 222             /* suck in c.slen bytes of data */
>> 223             want=(int)c.slen;
>> 224             if (want > (len-off))
>> 225                 {
>> 226                 want-=(len-off);
>> 227                 if (!BUF_MEM_grow_clean(b,len+want))
>> 228                     {
>> (gdb) p c.slen
>> $18 = 2147483648
>> (gdb) p want
>> $19 = -2147483648
>
>> This results in an inconsistent state, and will lead to memory
corruption.
>
>> --------------------
>> Affected Software
>> ------------------------
>
>> All versions of OpenSSL on all platforms up to and including version
>> 1.0.1 are
>> affected.
>
>> Some attack vectors require an I32LP64 architecture, others do not.
>
>> --------------------
>> Consequences
>> -----------------------
>
>> In order to explore the subtle problems caused by this, an unrelated
bug
>> in the
>> OpenSSL allocator wrappers must be discussed.
>
>> It is generally expected that the realloc standard library routine
>> should support
>> reducing the size of a buffer, as well as increasing it. As ISO C99
>> states "The
>> realloc function deallocates the old object pointed to by ptr and
returns a
>> pointer to a new object that has the size specified by size. The
contents
>> of the
>> new object shall be the same as that of the old object prior to
>> deallocation,
>> up to the lesser of the new and old sizes."
>
>> However, the wrapper routines from OpenSSL do not support shrinking a
>> buffer,
>> due to this code:
>
>> void *CRYPTO_realloc_clean(void *str, int old_len, int num, const char
>> *file, int line)
>> {
>>   /* ... */
>>   ret=malloc_ex_func(num,file,line);
>>   if(ret)
>>       {
>>       memcpy(ret,str,old_len);
>>       OPENSSL_cleanse(str,old_len);
>>       free_func(str);
>>       }
>>   /* ... */
>>   return ret;
>> }
>
>> The old data is always copied over, regardless of whether the new size
>> will be
>> enough. This allows us to turn this truncation into what is
effectively:
>
>>   memcpy(heap_buffer, <attacker controlled buffer>, <attacker
>> controlled size>);
>
>> We can reach this code by simply causing an integer to be sign
extended and
>> truncated multiple times. These two protoypes are relevant:
>
>> int BUF_MEM_grow_clean(BUF_MEM *str, size_t len);
>
>> void *CRYPTO_realloc_clean(void *str, int old_len, int num, const char
>> *file, int line);
>
>> BUF_MEM_grow_clean accepts a size_t, but the subroutine it uses to
>> handle the
>> allocation only accepts a 32bit signed integer. We can exploit this by
>> providing a large amount of data to OpenSSL, and causing the length
>> calculation
>> here to become negative:
>
>>           /* suck in c.slen bytes of data */
>>           want=(int)c.slen;
>>           if (want > (len-off))
>>               {
>>               want-=(len-off);
>>               if (!BUF_MEM_grow_clean(b,len+want))
>>                   {
>>                  
ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
>>                   goto err;
>>                   }
>
>> Because want is a signed int, the sign extension to size_t for
>> BUF_MEM_grow_clean means an unexpectedly size_t is produced. An
>> example is probably helpful:
>
>> (gdb) bt
>> #0  asn1_d2i_read_bio (in=0x9173a0, pb=0x7fffffffd8f0) at
a_d2i_fp.c:223
>> #1  0x0000000000524ce8 in ASN1_item_d2i_bio (it=0x62d740, in=0x9173a0,
>> x=0x0) at a_d2i_fp.c:112
>> #2  0x000000000054c132 in d2i_X509_bio (bp=0x9173a0, x509=0x0) at
>> x_all.c:150
>> #3  0x000000000043b7a7 in load_cert (err=0x8a1010, file=0x0, format=1,
>> pass=0x0, e=0x0, cert_descrip=0x5ebcc0 "Certificate") at apps.c:819
>> #4  0x0000000000422422 in x509_main (argc=0, argv=0x7fffffffe458) at
>> x509.c:662
>> #5  0x00000000004032d9 in do_cmd (prog=0x9123e0, argc=3,
>> argv=0x7fffffffe440) at openssl.c:489
>> #6  0x0000000000402ee6 in main (Argc=3, Argv=0x7fffffffe440) at
>> openssl.c:381
>> (gdb) list
>> 218                 want=HEADER_SIZE;
>> 219             }
>> 220         else
>> 221             {
>> 222             /* suck in c.slen bytes of data */
>> 223             want=(int)c.slen;
>> 224             if (want > (len-off))
>> 225                 {
>> 226                 want-=(len-off);
>> 227                 if (!BUF_MEM_grow_clean(b,len+want))
>> (gdb) pt len
>> type = int
>> (gdb) pt want
>> type = int
>> (gdb) p len
>> $28 = 1431655797
>> (gdb) p want
>> $29 = 2147483646
>> (gdb) p len+want
>> $30 = -715827853
>> (gdb) s
>> BUF_MEM_grow_clean (str=0x917440, len=18446744072993723763) at
buffer.c:133
>> (gdb) p/x len
>> $31 = 0xffffffffd5555573
>
>> Here len+want wraps to a negative value, which is sign extended to a
large
>> size_t for BUF_MEM_grow_clean. Now the call to CRYPTO_realloc_clean()
>> truncates
>> this back into a signed int:
>
>> CRYPTO_realloc_clean (str=0x7fff85be4010, old_len=1908874388,
>> num=477218632, file=0x626661 "buffer.c", line=149) at mem.c:369
>
>> Now old_len > num, which openssl does not handle, resulting in this:
>
>> ret = malloc_ex_func(num, file, line);
>
>> memcpy(ret, str, old_len);
>
>> Effectively a textbook heap overflow. It is likely this code is
>> reachable via
>> the majority of the d2i BIO interfaces and their wrappers, so most
>> applications
>> that handle untrusted data via OpenSSL should take action.
>
>> Note that even if you do not use d2i_* calls directly, many of the
>> higher level
>> APIs will use it indirectly for you. Producing DER data to demonstrate
this
>> is relatively easy for both x86 and x64 architectures.
>
>> -------------------
>> Solution
>> -----------------------
>
>> The OpenSSL project has provided an updated version to resolve this
issue.
>
>http://www.openssl.org/
>http://www.openssl.org/news/secadv_20120419.txt
>
>> -------------------
>> Credit
>> -----------------------
>
>> This bug was discovered by Tavis Ormandy, Google Security Team.
>
>> Additional thanks to Adam Langley also of Google for analysis and
>> designing a fix.
>
>> -- 
>> -------------------------------------
>> taviso AT cmpxchg8b.com
>>  | pgp encrypted mail preferred
>> -------------------------------------------------------
> 
> --
> Listen-Einstellungen:
> http://lists.cert.at/cgi-bin/mailman/listinfo/discuss

Attachment: signature.asc
Description: PGP signature




Archive powered by MHonArc 2.6.16.

Top of Page