Introduction

Creating my own Boot2Root VM has been something that has interested me ever since I first started getting in to stuff like HackTheBox and TryHackMe. Often times, I'd be doing machines on those platforms and thinking up solutions that were interesting, but didn't turn out to be the intended path. Whenever this happened, I'd always note to myself in my head - "Huh, that would be cool. Maybe I could make that one day".

Well, I finally got around to taking the plunge and creating my own box! Watcher is up on TryHackMe, where you can boot up your own VM instance and try it out today.

This article will go through some of the thought processes I had while planning and creating the box, how the actual development of the box went, and some issues I encountered that I now know to avoid in the future. Hopefully this article can be useful if you've thought about getting in to making machines but haven't yet got around to trying it out.

WARNING: There will be spoilers for the box below, don't read if you haven't completed it yet but intend to!

Fun for the whole family!

Planning

So from the start I had a few things in mind that I wanted to plan around:

Architecture

If I'm honest, I knew straight from the beginning that I wanted this to be a Linux box. Windows is fine and all (I used it almost exclusively up until I started uni), but when it comes to pentesting & CTF, Linux is just so clean to work with, as well as having so many interesting and thoughtful exploitation paths.

A Box for Beginners

After talking to people in the USW cyber society chat over the past few months, a prominent theme became clear - the interest was there for learning Boot2Root-style machines, but often the barrier of entry was just too great, or the required information too fractured.

With this box, I wanted to give a good place for beginner CTF players to start off in. It can be a difficult stage near the beginning; you're full of excitement and enthusiasm, but the quantity of information to take in can be overwhelming. Past the stage of "Okay, I've booted up this VM, what next?", but not quite at the stage of fully learning how to enumerate, being comfortable with common services, knowing the usual attack vectors, etc.

I wanted to make this box a bit more "hand-holdy" in that respect, giving a solid direction to follow (done through the use of hints and avoiding rabbit holes), while also giving it the same feeling of excitement and the "eureka!" moments that you get from a HTB-style machine that gives you room to experiment and learn.

Difficulty Tuning

While the intention of the machine was to be a good starting point for beginners, I didn't want it to be something you could blow through in 5 minutes. I think to really learn and remember techniques from these boxes, you DO need to struggle for a bit; it's the payoff of finally getting that nc listener connection or that root shell to pop that really makes the information stick in your head.

To do this, I decided instead of just having one service/privilege escalation path, I would implement multiple - but each one would be relatively simple on its own, and would have hints and resources to help nudge you in the right direction.

Boxes are always at their best for me when you know what to do, but don't know how to pull of the technique correctly quite yet; the machine "Intense" from HTB is a great example of this, always providing the source code but leaving it up to the user to find the specific vulnerabilities and learn how to exploit them.

We 💕 Linux

Development

Initial Setup

I decided to base the machine on an Ubuntu VM; Ubuntu is a good baseline OS to use, with the ability to easily install it & quickly configure needed software.

I downloaded an Ubuntu Server 20.04 image (you'll see how this bites me later), created a VM with it, and was ready to start developing.

Foothold - Corkplacemats Website

So the foothold idea was one I came up with while doing another box; combining an LFI vulnerability with FTP to upload malicious PHP code. This wasn't something I'd encountered before, but seemed like something that was basic enough to be a good beginner level challenge.

The first step to this was configuring the services needed on the box. After a quick apt install apache2 php libapache2-mod-php vsftpd I had the services I needed on the box, and then went to configuring them. For the apache server I just set up mod-rewrite to use .htaccess, and for ftp I created an ftp user in /home/user/ftpuser. I then configured vsftp.conf to only allow ftpuser to login, and created a directory for it to upload files in to.

The next step was the creation of the site. I used bootstrap to create a small site based around cork placemats (the name of our CTF team, long story). The site includes an LFI vuln in the post.php page, allowing for inclusion of system files in to the php code.

After this I set up robots.txt to reference the first flag, as well as a hidden secret_file_do_not_read.txt file, containing the php creds and upload path. I restricted the access to this second file with .htaccess, allowing the user to see that the file exists, but not what was in it.

The intention was that the user would find robots.txt first, obtaining the first flag and then having their curiosity piqued by the secret file. From there, they'd do some more digging and find the LFI vuln, using it to read the secret file and gain FTP credentials. Finally, they'd log in to FTP, grab the second flag, and realise they can upload PHP files. From there they would upload a php shell and include it using the LFI vuln, obtaining a reverse shell on the system as www-data.

Who doesn't love cork placemats?

User 1 - Toby

After getting a shell as www-data, I wanted to start off as easy as possible in terms of privesc to give the user a bit of encouragement at the start. I think doing something like this is a good idea, as I can remember first learning and getting stuck as soon as I got a foothold shell on the box; even a little nudge in the right direction can do a lot for morale.

To do this, I added a sudo rule to allow www-data to execute commands as Toby. Using some basic enumeration with sudo -l, the user should be able to see this and use a command such as sudo -u toby bash to get a shell as Toby.

Ride the privilege escalator!

User 2 - Mat

From here, I wanted a privesc that was a bit of a step up, but still very doable for a beginner. cron escalation seemed like a good fit, as this is one of the more common privescs found in beginner scenarios, as well as being included in most Linux privesc checkers (LinPEAS, LinEnum, etc).

I first added a note to Toby's home directory from Mat referencing cron jobs, then created a scripts directory and a cow.sh script inside it. From there, a cronjob was added to /etc/crontab, running the script as Mat every minute. With a bit of research, users should be able to see that the script is editable by Toby and executed by Mat, effectively giving us a root to execute commands as Mat. From there, many payloads could be used, such as adding an SSH key to Mat's home directory, or running a reverse shell.

Mooooooo

User 3 - Will

With the next privesc, I wanted to step the difficulty up a little bit, while remaining somewhat familiar. I decided to stay with the same theme as the previous step - editing a script that is run with elevated privileges - but with a bit more nuance.

For this, I decided to go with a python vulnerability - library hijacking. This requires a little bit of python knowledge, but it's not something that couldn't be learned with a little bit of research and intuition. As well as this, a slightly more complex sudo rule was implemented, requiring the user to chain together some techniques they'd used earlier in the box.

To do this, I set up a sudo rule that allowed the user to only run python3 with the will_script.py script set up in the scripts directory. This script used a library in the same directory - cmd.py - which takes in a number as an argument, and returns a command string. The original script then checks this command string against a whitelist, and runs the command if it passes.

The trick here is that will_script.py is only editable by the will user, while cmd.py is editable by mat. This means that even though we can't run cmd.py as will, because will_script.py imports it, we can inject our code in to will_script.py. The implementation of a whitelist was meant as a slight red herring; the intention was that users would try and find some way of trying to bypass the whitelist, not realising that they can just enter an os.system("/bin/bash") command at the top of cmd.py to obtain a shell as will.

Sssssneaky exploitsssss....

User 4 - root

For the final privilege escalation, I wanted something that would require a bit more enumeration than the others. Knowing what is normal and what isn't is a key part of privilege escalation, as well as being able to effectively parse output from privesc detection scripts.

To do this, I added will to the adm group, which is usually reserved for reading log files. As well as this, I created a backups folder in the /opt directory, changing its permissions so it's only able to be read by root and the adm group. Finally, a base64 encoded copy of the root account's private SSH key was added to the directory.

base64 encoding the key ensured that priv checkers wouldn't immediately light it up as an SSH key - instead some more thorough enumeration of the folder system would be required, realising that /opt/backups is not a default directory, and that the will acconut has the special permissions required to read it.

Once the key is decoded, the user can use ssh -i to log in as root. This requires a little bit of knowledge on how to use SSH, but again not anything that can't be learned with a bit of googling.

Now logged in as root, the user can pick up the final flag and revel in their triumph over the box!

Post-Development

With the development of the box done, I could start packaging it up and getting ready to upload.

TryHackMe allows for the upload of VM files, and will let users spawn individual instances of the VM; this is great as someone who doesn't have a whole lot of experience with distributing VMs, and makes the whole process a lot easier.

To upload to TryHackMe, the VM gets exported as an .ova file from VMware. This packages the VM in to one file, allowing for easy transportation and upload. Once you've got an .ova file, simply go to the "upload" section on TryHackMe and select the file - it'll get uploaded and then processed, after which you can assign it to a room and start deploying instances.

Issues

Of course, all of this didn't go right first try - there were a few small (and big) slip-ups along the way that took a few hours to work out.

Ubuntu Version

So after fully completing the VM and uploading the .ova file to TryHackMe, I noticed that only Ubuntu versions up to 18.04 were supported... Oops.

I ended up having to recreate the machine with an Ubuntu 18.04.5 image instead; thankfully the setup was almost identical so it was just a matter of retracing my steps.

This taught me the very important lesson of making sure your software is compatible with a platform before developing it!

Locked Out

While re-creating the VM, I made a pretty huge mistake - the privesc used from will to root wasn't working correctly, and I didn't notice this until after I'd removed the sudo group from will, preventing me from accessing root again

I thought for a moment that I'd have to recreate the whole VM for a second time. Thankfully, I'd inadvertently left will in the lxd group - if you haven't seen before, users in the lxd group can escalate to root by creating a container and mounting the host file system to it.

This allowed me to get back in to the root account and saved me from having to waste another hour recreating the machine!

Lessons learned: 1 - Don't remove sudo before testing the final privesc, and 2 - Always keep a VM snapshot of it being logged as the root user!

Oops..

Conclusion

Overall, this was a great experience and I expect that I'll make some more boxes in the future. After finishing the box, some of us from the USW cyber society joined voice chat together and had a race to see who could solve the box first (well done Mat!), and the amount of engagement and interest from the people that came along was great. Giving people the opporunity to learn something they didn't know before is always a great feeling, and I'd love to be able to do similar events again.

Thanks to Toby for testing the box, and thanks to Mat for answering my questions related to getting this kind of thing set up (and for introducting me to TryHackMe a year ago!).

And of course, thank you for reading!