Bash 4.3 setuid() BUG

Authors:Hector Marco & Ismael Ripoll
BUG:Lack of checking setuid() return code
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 not checking the return values of setuid() and getuid() calls. The process shall not continue its normal execution when any of these calls fail (returns an error) to drop privileges.

Impact

The bash shell contains the drop privileges code as a way to improve the security of the applications that use it. It is not advisable to execute bash with a modified effective uid or gid. This way, a careless privileged application or a root shell would not be able to damage the system.
The drop privileges error is not actually a security issue to the bash because bash is not installed with the bit setuid, but this code was added to help to protected the system.

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 2014) is also affected.

The bug

The bug appears because the return value of the setuid() call is not checked. When the setuid() fails, the application continue its normal execution (does not terminate) and the remaining code is executed with the original privileges. The bug appears in shell.c file, on lines 1229 and 1230:
void
disable_priv_mode ()
{
  setuid (current_user.uid);
  setgid (current_user.gid);
  current_user.euid = current_user.uid;
  current_user.egid = current_user.gid;
}

Exploit

The strategy to exploit this kind of bugs consists in creating as many processes as the target user is allowed to make (which is given by RLIMIT_NPROC), and then the next attempt to drop privileges will fail, letting the process alive and with the original privileges.

FIX

We have created a non official patch for bash-4.3:
diff --git shell.c shell.c
index bbc8a66..5bfd466 100644
--- shell.c
+++ shell.c
@@ -1226,8 +1226,12 @@ uidget ()
 void
 disable_priv_mode ()
 {
-  setuid (current_user.uid);
-  setgid (current_user.gid);
+   
+  if( (setgid (current_user.gid) !=0) ||  (setuid (current_user.uid) != 0) ){
+     report_error("Drop privileges failed!!\n");
+     exit(-1);
+  }
+  
   current_user.euid = current_user.uid;
   current_user.egid = current_user.gid;
 }
[ bash_4.3-fix-setuid.patch ]

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

Discussion

There has been some discussions whether this is a security issue or not. This is a bash security feature to help other applications with the setuid bit to prevents to execute bash with root privileges. If bash drop privileges fails then other applications, as for example the s3dvt setuid vulnerability, could obtain a root shell.
We think that this is a security issue because in some circumstances the bash security feature could be bypassed allowing the bash to be a valid target shell in an attack.


Hector Marco - http://hmarco.org