Road to HackMex: Dia 1 - Contract
Table of Contents
Introducción
Primero que nada, buenos días. Ya tiene rato que no escribo por acá pero es que la escuela y en general la vida me ha estado agarrando a putazos jajaj. Han estado pasando muchas cosillas estos meses, aunque estoy agradecido de que en su mayoría han sido buenas mayoría de q 51 a 49 pero ajá. Pero pues equis, aquí andamos de regreso comenzando con una serie de posts que espero dure un rato y nos mantenga entretenidos.
HackMex
Como se puede inferir por algunos posts de este blog, formo parte de la agrupación de ciberseguridad de la Facultad de Ingeniería de la UNAM. PumaHat Cibersecurity Team pumahot para los compas. Y como tal, existen ciertas veces en las que participamos como grupo en las competencias de ciberseguridad nacionales, principalmente CTFs. En estos momentos, nos estamos preparando para competir en HackMex.
HackMex es una competencia organizada por varias asociaciones, empresas e incluso organismos de gobierno (de hecho el IPN anda por ahí), en la cual compiten estudiantes de nivel medio superior, superio y posgrado.
También compiten sectores del gobierno, asociaciones civiles y empresas privadas; obviamente cada quien en su categoría porque si, soy un cabrón con la percepción de la realidad bien alterada, pero hasta yo sé q no le puedo cantar un cibertiro a algun wey de empresa
Y pues va a empezar a finales de agosto, pero desde ahora vamos a comenzar a entrenar para poder rifarnos una buena posición. Como parte de este entrenamiento, nos vamos a rifar una máquina diaria, y yo voy a estar subiendo los writeups de las q logre headshotear y que ya se puedan subir por aquí. Empezando desde hoy.
Writeup Contract EchoCTF
Enumeracion
Descripción de la máquina
Binding agreements with clarity and precision, ensuring mutual commitments are honored and upheld seamlessly.
Escaneo de puertos
Inmediatamente vemos servicio http en el puerto 80, un nginx que está hosteando un servicio llamado PhotoShow Tambien vemos un servicio ssh
80/tcp open http nginx 1.18.0
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)

Enumeracion de servicios
Corro un dirsearch en el servicio web, el cual en un principio pensé que me estaba dando un login escondido, pero luego me di cuenta de que existe en la página principal JAJAJA
Entonces dirsearch en realidad no nos revela nada útil
Y buscamos vulnerabilidades en las versiones de los servicios
No encontré otra más que esta.
PhotoShow 3.0 - Remote Code Execution - PHP webapps Exploit
Esta requiere una cuenta admin, podriamos bruteforcear la ventana de login que encontramos hace rato para ver si encontramos las credenciales
Si queremos seguir esta ruta, tenemos las siguientes politicas de nombres y contraseñas:
Login : letters and numbers only
Password : minimum 6 characters

Pero como podemos ver no tenemos una forma de enumerar los posibles usuarios de manera correcta, pues el mensaje que nos da si fallamos contraseña en usuario existente e inexistente es el mismo, entonces si queremos irnos por esta ruta, estamos a ciegas.
Por fuerza de hábito, probemos con credenciales comúnes:
admin:admin
admin:password
Fue la segunda lol
Pues ya teniendo credenciales de admin, podemos correr el exploit.
Explotacion
Preparar el payload
Antes de correr el exploit debemos realizar algunas modificaciones ligeras para que funcione correctamente.

Aquí debemos de modificar el comando a correr para levantar el revshell, pues hacerlo con sockets nos causa problemas. (mata la máquina jaja)
Usaremos en su lugar netcat. Y además, le meteremos un ampersand al final para no matar shells de otros (perdón)

Ejecución
Ponemos a la escucha nuestro netcat y corremos el script. We are in.

Por fuerza del hábito, upgradeamos nuestra shell y cobramos inmediatamente la primera bandera con:
cat /etc/passwd
Y para verificar nuestras capacidades adentro, podríamos correr linnpeas y ver qué encontramos, pero no guardé screenshot de esta fase así que creanme que encontraremos que /usr/bin/agreement tiene permisos en sudo -l, lo que como sabemos significa que podemos correrlo como root.
Y agreement es un script en JS que corre lo siguiente:
#!/usr/bin/env node
var args = process.argv.slice(2);
(async () => {
const lib = await import('@agreejs/shared');
const { exec } = await import('child_process');
var components = JSON.parse(args[0]);
try {
lib.mergeInternalComponents(components);
} catch (e) { }
var user = {};
if (user.authenticated === true) {
exec(user.cmd);
}
})();
Podemos observar que acepta un argumento por linea de comandos, el cual es esperado como objeto JSON
Luego lo parsea y convierte en components
Define un objeto user y verifica si user.authenticated es true. Si es así, ejecuta user.cmd
A primer vistazo, podríamos pensar en que si nosotros estamos dando components y el script verifica parámetros de user, entonces no podemos hacer nada. Pero en realidad mediante components podemos y cambiaremos los parámetros de user; haciendo lo que se conoce como Prototype Pollution
Privilege Escalation
Prototype Pollution
En JS todos los objetos heredan parámetros de su prototipo, el cual suele ser Object.prototype. Al crear un objeto, JavaScript primero verifica si le estamos dando valor a una propiedad de forma explícita, y si no, entonces busca valores en sus prototipos. En este caso, nada nos restringe de modificar el prototipo de component, el cual asumimos Object.prototype, y asumimos que será el mismo para user, y hacer algo como:
{"__proto__": {"authenticated": true, "cmd": "/bin/sh"}}
Si nuestras asunciones son correctas, desde el prototipo en común entre components y user podremos definir los parámetros que el segundo usará.
Antes de seguir, si te interesa este tema y te quedas confundido con la explicación, puedes documentarte más sobre este tema aquí
No tenemos garantizado que el comando imprima su salida, entonces vámonos recio a usar este espacio para levantar otra revshell como root. Corriendo:
sudo agreement '{"__proto__": {"authenticated": true, "cmd": "CMD para abrir una revshell"}}'
Podríamos probar con ese payload para ver qué ocurre, evidentemente teniendo otro puerto listo para escuchar en nuestro netcat.
Y efectivamente, con este payload we're in, ahora como roots

Y una vez dentro, cobramos las banderas faltantes las cuales serán:
- Una en /etc/shadow
- Una en /proc/1/environ
- El nombre del único archivo en /root
Headshot