Not every privilege escalation path involves a kernel exploit or a clever binary abuse chain. Sometimes the box just leaves its secrets lying around in a log file, and all you have to do is read them.
That was the case here — a plaintext SMTP password sitting in an application’s database dump, reused as the root password.
The Setup
I had landed a low-privilege shell on a box running Openfire, an XMPP/chat server written in Java. Openfire ships with its own embedded database and a set of log files under /var/log/openfire/ and /var/lib/openfire/embedded-db/. As always, the first move after getting a foothold was to run LinPEAS and see what it flagged.
Enumeration
LinPEAS came back with two interesting paths almost immediately:

Writable: /var/log/openfire/openfire.log
Writable: /var/lib/openfire/embedded-db/openfire.log
Writable log files are worth a look on their own — if a root-owned process reads from them insecurely, that’s a potential injection vector. But before chasing that angle, I wanted to see what was actually already sitting in Openfire’s data directory. Digging through /var/lib/openfire/embedded-db/, I found openfire.script — the plaintext script file the embedded H2 database uses to persist its schema and data on disk. Since H2’s script format stores INSERT statements as raw SQL, anything sensitive that Openfire ever wrote to its own config table would be sitting there in the clear.
I grepped it for anything password-related and got a hit:

INSERT INTO OFPROPERTY VALUES('mail.smtp.password','OpenFireAtEveryone',0,NULL)
mail.smtp.password — the credential Openfire uses to authenticate to an outbound SMTP relay — stored as cleartext in the property table, which then gets flushed straight to disk in the .script file. No hashing, no encryption, just a raw string sitting in a file any local user with read access to the app’s data directory could open.
Exploitation
The SMTP relay itself wasn’t reachable from outside the box, so the credential wasn’t useful for pivoting externally. But password reuse is one of the first things worth testing on any internal box, and admins reusing service-account passwords across accounts is depressingly common. So I tried the leaked SMTP password against the one account that mattered most:
su root
Password: OpenFireAtEveryone

openfire@openfire:/home/openfire$ su root
Password:
root@openfire:/home/openfire# id
uid=0(root) gid=0(root) groups=0(root)
The same string protecting an outbound mail relay was also the root password on the box. One su command later, game over.
Why This Works
This chain works because of two separate but related failures stacked on top of each other:
- Openfire stores service credentials in plaintext. The embedded H2 database writes its property table straight to a
.scriptfile on disk with no encryption at rest. Any property configured through the admin console — including SMTP credentials, LDAP bind passwords, and similar — ends up recoverable by anyone who can read that file. - Password reuse across trust boundaries. The SMTP password had nothing to do with root, architecturally. But whoever configured this box picked the same password for both, collapsing two separate credential domains into one guessable secret.
Neither failure is exotic. They’re both extremely common in real environments, which is exactly why this kind of low-tech loot-the-config-files approach is worth doing on every engagement before reaching for anything more advanced.
Root Cause
The root cause here isn’t a vulnerability in Openfire itself — storing SMTP credentials in an app-local config store is normal. The actual failures are operational:
- The embedded database file was readable by a low-privilege local account, exposing every property Openfire had ever persisted, including credentials.
- The SMTP password and the root password were the same string.
Fix:
# Restrict read access to Openfire's data directory to the openfire user only
chmod 750 /var/lib/openfire/embedded-db
chown -R openfire:openfire /var/lib/openfire/embedded-db
# Rotate the exposed SMTP credential and the root password separately
passwd root
# then update mail.smtp.password via the Openfire admin console with a unique value
More broadly: never reuse a service-account password as a system or root password. They should come from entirely separate rotation policies so that leaking one never leaks the other.
Key Takeaways
- Always check application data/config directories for plaintext credentials before assuming you need a binary exploit —
grep -ri passwordacross a writable or world-readable app directory is cheap and often pays off - Embedded databases like H2 that persist as flat
.scriptfiles are a common source of plaintext secrets — treat any app using one as a credential-hunting target - Password reuse between service accounts and privileged system accounts is one of the most common real-world escalation paths, precisely because it requires no exploit at all
- Writable log files (as LinPEAS flagged here) are worth remembering even when they aren’t the path you end up taking — they’re a separate potential injection vector worth revisiting
Questions? Hit me up on X.