Road to HackMex: Dia 1 - Contract

· 6min · IsaacNietoG

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)

Nmap Scan

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