Forwardslash — HackTheBox

y4th0ts
11 min readJul 4, 2020

Summary

Forwardslash is a hard-rated Linux machine created by InfoSecJack & chivato. Initial foothold is gained by finding the backup website from enumerating vhosts. User access is gained by abusing an LFI vulnerability and using PHP filters to view files that are not viewed normally with simple LFI. User credentials are found on one of the PHP config files that leads to ssh access. Lateral movement to a different user is performed by abusing a SUID binary owned by the other user which will access a file with an md5 sum as filename. This was used to view a backup config file that has the other user’s credentials. Finally, root privilege is obtained by decrypting a ciphertext that contains the key to an encrypted LUKS image and abusing sudo privileges for opening the LUKS image and mounting it to grab root’s private key for ssh access.

Reconnaissance

Nmap scan result shows only port 22(ssh) and 80(http) open.

Visiting the http port redirects to forwardslash.htb so I added it to my hosts file in order to access it.

It shows a defaced page by ‘The Backslash Gang’. Looking at the source code does not give us any useful information So I ran a directory bruteforce.

The scan results show a file ‘note.txt’. Let’s check it out.

The note contains some important information that we can use later on. We have ‘pain’ and ‘chiv’ as possible users and a backup site is also mentioned on the note.

Since there was no backup directory on the directory bruteforce results, I went and scanned for vhosts and it came out on the results.

I added it to my hosts file and visited the page.

I ran a directory bruteforce on the subdomain and poked around it while it runs. The page displays a login panel. I tried using some common credentials like admin:password and admin:admin and so on but nothing worked. Source code does not give us anything useful as well.

I went to the signup page and created my own account.

Upon logging in, we get directed to a dashboard. I poked around the other pages and sources and the only interesting thing I found is the ‘profilepicture.php’ page.

The directory bruteforce results gave me 3 things that I could not access from the dashboard. The ‘api.php’, ‘config.php’, and ‘/dev’ directory. Going the php pages gives me blank pages while going to the /dev directory gives me a forbidden error.

Initial Foothold

Local File Inclusion (LFI)

I went and played around with the profilepicture.php page. Looking at the source, It performs a post request to profilepicture.php but the form field and the submit button are disabled.

These can be enabled by going to ‘inspect element’ and removing the disabled parameter on the html code.

I tried testing for possible SQL injection but I was only redirected to the original profilepicture.php page with the disabled field and button.

I tried testing for local file inclusion(LFI) and lucky enough to make it work.

I intercepted the post request in burpsuite in order to make fuzzing easier and have a more readable output. The passwd file confirms the existence of ‘chiv’ and ‘pain’ user.

I tried accessing the config.php and api.php that gives me blank pages but I was only able to view the config.php file. Temporary mysql credentials were exposed but will not be useful right now so I took note of them.

Accessing the api.php gives a ‘Permission Denied: Not that way ;)’ message. I also tried accessing /dev and it gives me the same message.

While researching on local file inclusion, I came around payloadallthethings’ github page which gave me a trick to view restricted PHP files by using phpfilter. I tried it on the /etc/passwd file to see if it works.

Request
Response

I decoded it on my terminal and it works like a charm.

Gaining user access

I went and tried to view dev/index.php to see if it will work this time.

Copied the base64 string at the bottom of the response and decoded it on the terminal. The page shows a connection to FTP by chiv with his user and password.

I tried the credentials on ssh and I got user access. Unfortunately, user.txt flag is not on his home directory. So we will need to move laterally to Pain in order to grab it.

I poked around using common enumeration commands but found nothing of interest so I downloaded linpeas.sh to the target machine to gather new information.

mysql is running locally on port 3306.

Some more interesting files to look at. Most especially the suid binary /usr/bin/backup owned by pain.

I attempted to login to mysql using the credentials that I have available to me but was unsuccessful.

I went to the /var/backups directory and check the contents of files that I can access and found another note.txt file. It states that this is the backup of the old config which is the ‘config.php.bak’ I presume and is telling chiv not to touch it.

Viewing the contents of ‘config.php.bak’ gives me ‘Permission Denied’ error as well as accessing the recovery directory.

SUID Binary exploitation

I did not find anything else useful at this point so I went and checked the suid binary owned by pain. Executing it gives me an error about an md5sum that does not exist or not accessible by me, then it exits. The md5sum differs every execution.

Running strace shows its system calls. It looks like it is setting uid and gid to 1002, then trying to access a file. If the file does not exist, it exits.

Running ltrace on the binary shows a little more information. Ltrace shows library calls made by the program or binary. Looking at the output, the binary accesses the localtime and does an md5sum of it?

The sprintf library function assigns output to a string instead of printing it. Notice that the hexadecimal value are taken using sprintf and put together into an md5sum that gets accessed as a filename. If the file exists, the file gets deleted at the end of the execution.

I created a one liner that will take the md5sum value from the error message. Then developed a script to try to exploit the suid binary.

The script contains the one liner that parses the md5sum from the error, directs it to a file called ‘filename.txt, then creates a file using the md5sum as the filename and re-executes /usr/bin/backup. After execution, the error is gone.

I tried putting something in the file and see what happens. I added a command that directs the output of /etc/passwd to the file being created. It displays the contents but I still don’t know how to use this as leverage.

I tried assigning a symlink to pain’s ssh private key but it gave me errors again. One reason is he may not have one.

I tried assigning a symlink to user.txt flag and it worked!

After experimenting more, I remembered about the backup config.php file and tried viewing that using the binary.

Bingo! I was able to view the contents and find new credentials.

I tried the credentials by switching user and I was able to switch to pain user! Grabbed the user flag which was confirmed to be the same one that I viewed using the suid binary.

Privilege Escalation

I went to the /var/backups and this time I am able to access the recovery directory. It contains an encrypted backup image file. Running file command on it shows that it’s a LUKS encrypted file. I ran linpeas.sh again to find new information.

Linpeas results discovered some commands that pain can run with sudo.

I tried opening the image file with the passwords that I have as the passphrase but it did not work.

Decrypting the Ciphertext

At this point I went and checked out the encryptorinator directory in pain’s home directory. The ciphertext contains gibberish data and the encrypter.py file has REDACTED values.

Since I have the ciphertext, I can try to bruteforce the key using a wordlist. I went and downloaded the encrypter.py and ciphertext to test it locally.

First, I created my own ciphertext so I can test if it will work.

I ran encrypter.py and directed it to a file called ‘cipher.test’.

Then I appended the key that I used to a file that originally contains the first 50 words from rockyou.txt.

Then I added these lines of codes to the original encrypter.py file. As stated on the comments, the script will import the ciphertext, then import the wordlist into a list of keys. And finally, run a decryption using every key in the list of keys. And if the string ‘long’ is found on the decrypted output, the program will print the key that was used and the decrypted message.

Running the program gives us this output. The first words of the message are not decrypted properly but the rest looks good.

I had this idea because most of the notes left around have ‘chiv’ and ‘pain’ in them and this encrypted message might also have it. This is the final script.

The final version of the script will try to decrypt using words from rockyou.txt as a key and if ‘chiv’, ‘pain’, ‘pass’, or ‘key’ is on the output, it will print the key that was used to decrypt the ciphertext, and the decrypted message. More over, it will write the matched key and message into a file.
As you can see, the words that I expected to appear are not on the message. Good thing I added ‘pass’ and ‘key’ to the script considering the first few words aren’t decrypted properly. Otherwise it would’ve taken me a long time to figure it out or might even fall into a rabbit hole.

Now that we have the key to the encrypted LUKS image, we can try to escalate to root. Looking at the commands we can run with sudo again, I opened the luks encrypted image using the passphrase from the decrypted message. After it gets opened, it should be found in /dev/mapper directory. Then we mount it while we are in ‘/’ directory since that’s where we can run the mount command with sudo. After it’s mounted, we can grab the private key located inside the /mnt share.

I used scp to grab the id_rsa file. Set the correct permissions to it, logged in to ssh as root, and finish off by grabbing the root.txt flag.

That is it for forwardslash! Thank you for reading and please feel free to provide any feedback or tips on any alternate approach that could have been done. Have a good day all!

--

--