troy@home:~$

CTF Writeup: tryhackme.com GamingServer


Introduction

In this post, I will do another tryhackme.com CTF writeup. This time, we will go over the steps taken to compromise a very poorly-configured gaming server. You can find the room here. The introduction to this room states:

Can you gain access to this gaming server built by amateurs with no experience of web development and take advantage of the deployment system?

Yes. Yes, I think we can. As always, we will first need to connect to the tryhackme.com network via VPN. If you have never done so before, you can find the relevant information and configuration file here.

Reconnaissance

After we’ve spun up the machine in the room, we can now access it. Let’s begin with a standard nmap scan. In my case, the machine is at IP address 10.10.8.222. First the nmap scan:

nmap -sC -sV 10.10.8.222

Now that we know we’ve confirmed there is a web server running, as denoted by Apache running on port 80, let’s quickly take a look at the site before we run our gobuster scan. Navigating to the server in our web browser yields the following site:

There is a bunch of lorem ipsum and most of the links are dead or route back to the main page. There doesn’t appear to be anything here all that interesting. Let’s take a quick look at the html:

At the end of the html is a comment stating:

“john, please add some actual content to the site! lorem ipsum is horrible to look at.”

That could potentially be a user name, so let’s tuck that away in our notes for now. Next, we will run a gobuster scan using the common.txt wordlist (which you can find here).

gobuster -u http://10.10.8.222 -w /usr/share/wordlists/gobuster/common.txt

The results of the scan indicate several directories that we have acess to, including /secret and /uploads, as well as a robots.txt file. Let’s see what’s in the hilariously-named /secret directory.

We see a directory listing with a file called secretKey, so let’s take a look at that:

Well, the description of this room said that this server was built by amateurs with no web development experience. Here they’ve placed a private RSA key in a public-facing directory.

Initial Access

We may be able to use this key along with the john username to gain access to the machine via ssh. Let’s give it a try now and see if it works. First, we pull down the key using curl. Note that the IP address of the server is different than before because I worked on this post over several different sessions.

curl -o id_rsa_gamingserver http://10.10.221.45/secret/secretKey

Once we have it, we can attempt to use it to log in to the machine using the john username:

ssh -i id_rsa_gamingserver john@10.10.221.45

We get a message that we don’t have the correct permissions set on the key file. Let’s change it so that it is readable only by the owner:

chmod 400 id_rsa_gamingserver

Then we try again:

It appears that the key is passphrase-protected. We will have to try and crack it. For that we can use john the ripper and ssh2john (not to be confused with the username in this case). First we will use ssh2john to convert it to a hash file for john the ripper to use, saving it to a file called gamingserver.hash:

./ssh2john.py ~/id_rsa_gamingserver > gamingserver.hash

Now that we have the hash file, we can plug it into john the ripper and try to crack it using the rockyou wordlist (available here). Note that in the image below, I’ve moved into the directory where I keep the compiled code for john the ripper:

./john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa_gamingserver.hash

This private key was protected with a very weak passphrase (redacted). Now that we have it, we can again try to log into the server with the private key, providing the passphrase when prompted:

ssh -i id_rsa_gamingserver john@10.10.221.45

It worked. We are now logged in to the server as john, as confirmed by the results of the whoami command. The user flag is right here in the user’s home directory:

Privilege Escalation

Now that we have that, we can move on to getting the root flag. To do that, we’ll obviously need to escalate our privileges to root. Let’s enumerate the machine using the LinEnum script (which you can find here) to identify any potential security misconfigurations. First, well need to get a copy of the script on to the server. Since we have an ssh key, let’s just use secure copy. Here I’ve already downloaded LinEnum.sh to my home directory on my attacking machine. We can use scp along with our ssh key to do this:

scp -i id_rsa_gamingserver ~/LinEnum.sh john@10.10.221.45:~

Now we go back to our shell on the gaming server and give ourselves execute privileges on the file using:

chmod +x LinEnum.sh

Then we can run the script. Because it creates a lot of output, I’m going to save it to a file named LinEnum.log instead of printing to standard output:

./LinEnum.sh > LinEnum.log

I’m not going to display the output of this script because it’s too big, but if you are following along, you’ll have your own copy to look at. I’ll be honest in that I had trouble finding anything exploitable when looking through the results. After a while however, I noticed this:

[00;33m[+] We're a member of the (lxd) group - could possibly misuse these rights! [00m
uid=1000(john) gid=1000(john) groups=1000(john),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lxd)

Under other circumstances, I probably would not have given this a second glance, but I remembered that this tryhackme room was tagged with “lxd”. So, we are most certainly expected to use this in some way. I’m not very familiar with lxd other than the fact that its some type of hybrid containerization/virtualization technology-ish thingamajig for Linux. But apparently the fact that john is in the lxd group gives us a privilege escalation technique. Researching this a bit further, I found this article, which not only explains lxd, but provides the steps for this particular privesc technique. I will be using the steps laid out by the author in this section, so all credit to him.

In order to pull off this exploit, we first need a running container on the server. In order to do that we’ll need something to run in that container. Here we will use alpine-builder to create an Alpine Linux image that can be used with lxd. Alpine is beneficial in this case due to its small size. First we clone the github repo and then build the image on our attacking machine:

git clone  https://github.com/saghul/lxd-alpine-builder.git

Next, cd into the newly-created directory and run the build-alpine script as root:

If all goes well, you should have a gzipped archive file in the directory called:

alpine-v3.13-x86_64-xxxxxxxx_xxxx.tar.gz

where the x’s will be the current date and time.

Now we will need to move the image over to the server. Again, we’ll use secure copy:

scp -i ~/id_rsa_gamingserver alpine-v3.13-x86_64-20210611_1538.tar.gz john@10.10.161.106:~ 

Next we go back to our shell on the gaming server and import the image into lxc:

Then we initialize, configure and start the container with the following four commands:

lxc init alpine ignite -c security.privileged=true
lxc config device add ignite mydevice disk source=/ path=/mnt/root recursive=true
lxc start ignite
lxc exec ignite /bin/sh

We are now root in the container. We can access the host machine’s files as root by navigating to its root directory at /mnt/root/root. The flag can be found in the usual spot.

That’s it. We’ve fully compromised the machine and obtained both the user and root flags, completing the room.

Lessons Learned

We were able to break into this machine fairly easily due to some comically-bad security configurations. In this scenario, the gaming server is said to be set up by people with no web development or server knowledge, so it doesn’t come as a surprise. What could the owners of the server have done in this case to mitigate these vulnerabilites?

  1. First of all, there was the html comment on index.html that contained someone’s name. Potential usernames of a system should never be made available publicly.

  2. There was an ssh private key in a public facing web directory called /secret. A private key should never be seen by anyone other than the owner, let alone be made public. The administrator should remove this directory and tell john to immediately stop using the key. Then John should then generate a new key using ssh-keygen on their machine and copy the resulting public key over to the server using ssh-copy-id.

  3. The ssh private key was protected with a passphrase, which is good. However in this case, the passphrase was particularly weak and easily brute-forced. John should have chosen a more robust passphrase with a mix of uppercase, lowercase, digits, and symbols.

  4. The fact the the john user was a member of the lxd group provided us with an exploit to elevate our privilege to root. Although there may be some cases in which a user would need to be a member of the lxd group, it was entirely unnecessary in this case because there were no containers running on the system and lxd was not in use. Therefore, there was no reason for john to be a member of the lxd group. The administrator should remove john from the lxd group using gpasswd -d john lxd.