Introduction

Suppose we have the following code:

int main(int argc, char ** argv) {
    char * fn = "/tmp/permitted";
    char buffer[128];
    FILE *fp;

    if(!access(fn, W_OK)){
        scanf("%100s", buffer );
        fp = fopen(fn, "w");
        fwrite("\n", sizeof(char), 1, fp);
        fwrite(buffer, sizeof(char), strlen(buffer), fp);
        fclose(fp);
    } else {
        printf("No permission \n");
    }
}

Normal usage of the file:

If this is compiled as a root user and a non-root user can access the compiled file, then we can exploit the race-condition vulnerability.

The exploit

  1. We first need two terminals opened to exploit the race condition because we need to create the symbolic link while running the race executable. We open both terminals as the hacker.

  2. In terminal 1 we run the compiled file race

  3. In terminal 2 we run:

    # First is the file to gain control, second is the file location
    ln -sf "/questions/race/test" "/tmp/permitted"


  4. In terminal 1 we simply input what we want to write to the file. We confirm that the write to the file test has succeeded.

  • With this exploit we can replace /questions/race/test with basically any file that we want to modify, even in files like "/etc/passwd". So to end up with root shell we basically create a superuser in passwd and shadow root-only files, overwritten every other users with our own password, all done as the root from our real user, hacker.
    For example "hacker:x:0:0::/home/hacker:/bin/bash" with hacker old password. Thus the exploit has succeeded, we have modified and written the root-only files as a non-root user by race condition vulnerability.

Why this is a problem:

As the hacker user, we should not be able to modify a root-only permission file in any way. But as a workaround, suppose we have an executable which is owned by root, and have the ability to execute an executable file that has the race condition vulnerbility, we can exploit by creating a symbolic link to a root-only permission file and ultimately creating new users and even gain the root privilege by adding the super user.
In our case the race executable is owned by root and executable by hacker to modify a hacker owned file, /tmp/permitted. However this executable's source file has a race condition vulnerbility between access and fopen. We can create a symbolic link of two files /tmp/permitted and /etc/passwd2 (by ln -sf and symlink() function) during the window, so that these two files will be handled in the race.c and because of the symbolic link created, the race condition vulnerability can now be exploited by the program checks for access (/tmp/permitted) which hacker has access and then it waits for an input, if we successfully catch this window while waiting for input, we can create a symbolic link from our file to any root owned files and thus can modify any files (race condition happens between access() and fopen()).

The fix:

int main(int argc, char ** argv) {
    char * fn = "/tmp/permitted";
    char buffer[128];
    FILE *fp;

    uid_t user = getuid();  // Get real user UID
    // uid_t root = geteuid(); // Get the root's UID
    seteuid(user); // Disabled real user UID

    if(!access(fn, W_OK)){
        scanf("%100s", buffer );
        fp = fopen(fn, "w");
        fwrite("\n", sizeof(char), 1, fp);
        fwrite(buffer, sizeof(char), strlen(buffer), fp);
        fclose(fp);
    } else {
        printf("No permission \n");
    }
}

The fix result:


How the fix resolves the issue:

  • We have accessed the real user UID and disabled real user UID so the user will not be priviledged when running the executable. Thus the race condition vulnerability has been resolved.