Bash-4.3 crash BUG

Authors:Hector Marco & Ismael Ripoll
BUG:Incorrect error handling resulting in Bash crash
Dates:10 December 2013 - Discovered the bug
25 March 2014    - Public disclosure

Description

A bug in bash for versions prior to 4.3 has been found. The bug is caused by the internal printf bash command because an incorrect error handling resulting in a bash crash.

Impact

It is possible to force bash to try to print an incorrect region of memory which results in a crash with the corresponding core dump. A malicious user can prepare a bash script which when executed under some X Windows Systems environments causes an xterm process to terminate incorrectly which may in turn terminate the entire X11 session. User data may get lost.

Vulnerable packages

Bash package 4.3 is vulnerable, version from 3.0 (released on August 2004) to the current 4.3 (last git commit on 26 February) are also affected.

The bug

The bug appears because the function getint() does not print correctly the precision value when the value of it is not valid.
The getint() call to getintmax() which forward rewind the garglist to the next word. When back to getint() function, if the precision is not valid this function try to print the precision but incorrectly using the printf_erange() function. Instead of printing the value of the invalid precision, the pointer passed to printf_erange() is the next parameter. Since there are not more parameters passed to the bash, the printf_erange() prints from a wild pointer. The bug appears in builtins/printf.def file, at lines 1118 and 1123:
static intmax_t
getintmax ()
{
  intmax_t ret;
  ...
  garglist = garglist->next; // Point to the next (but there are not more)
  return (ret);
}

static int
getint ()
{
    intmax_t ret;

  ret = getintmax ();

  if (ret > INT_MAX)
    {
      printf_erange (garglist->word->word); // Wrong pointer
      ret = INT_MAX;
    }
  else if (ret < INT_MIN)
    {
      printf_erange (garglist->word->word); // Wrong pointer
      ret = INT_MIN;
    }

  return ((int)ret);
}

Exploit PoC

In order to check if your bash is affected by this bug you can execute the following:
$ printf "%.*x\n" 0x7f92514e5000

If your bash crashes then your are affected by this bug.
Another way to check if your bash is affected without causing a bash crash is passing a second argument to the internal printf bash. If the first error message showed is referring to Numerical error then your bash is affected by this bug.

$ printf "%.*x\n" 0x7f92514e5000 "Hello world" 
bash: printf: warning: Hello world: Numerical result out of range
bash: printf: Hello world: invalid number

As the second proof of concept shows, the internal printf shows "Hello world" instead of "0x7f92514e5000" as an numerical result out of range.

FIX

We have created a non official patch for bash 4.3:
diff --git builtins/printf.def builtins/printf.def
index 7f29126..a7b534b 100644
--- builtins/printf.def
+++ builtins/printf.def
@@ -1106,6 +1106,7 @@ static int
 getint ()
 {
   intmax_t ret;
+  WORD_DESC *cword = garglist->word->word;
 
   ret = getintmax ();
 
@@ -1114,12 +1115,12 @@ getint ()
 
   if (ret > INT_MAX)
     {
-      printf_erange (garglist->word->word);
+      printf_erange (cword);
       ret = INT_MAX;
     }
   else if (ret < INT_MIN)
     {
-      printf_erange (garglist->word->word);
+      printf_erange (cword);
       ret = INT_MIN;
     }
[ bash_4.3_printf_getint_bug.patch ]

Patching bash 4.3:
$ wget http://hmarco.org/bugs/patches/bash_4.3_printf_getint_bug.patch
$ cd bash.4.3
$ patch -p0 < ../bash_4.3_printf_getint_bug.patch


Hector Marco - http://hmarco.org