function checksig($filename, $timestamp, $sig, $secretkey)This task is exploited based on the PHP operator and expected Behavior of PHP equal to operator.
{
$realsig = substr(md5($filename.$timestamp.$secretkey),0,16);
if ($sig == $realsig)
{
$filename = './'.str_replace('/','',$filename);
readfile($filename);
die(0);
}
echo "Invalid Signature!";
}
$secretkey = "XXXXXXXXXXXXXXXXXXXXXXXXX";//This is not real $secretkey, ignore it !!!
echo "
Web100
Dare to read flag.php???
Click me
";
if (isset($_GET['filename'])&&isset($_GET['sig'])&&isset($_GET['timestamp']))
{
checksig($_GET['filename'],$_GET['timestamp'],$_GET['sig'], $secretkey);
die(0);
}
echo "Something's missing!!";
echo "";
?>
take a look at function checksig. In this function, there is a comparison
if ($sig == $realsig)
$sig is a signature that we send to server and $realsig is the calculated signature. Server will compare 2 values to decide whether or not the signature is correct.
Since the coder use the operator == to compare 2 strings, we can exploit it via the way php performs the type juggling. When using this operator (==), the comparison will be performed based on the active types of the operands. If the operands are strings or nulls, they are compared as strings, if either is a Boolean, they are converted to Boolean values and compared, and otherwise they are converted to numbers and compared. [Advanced PHP programming - George Schlossnagle]
In other words, this loose comparison will use context to understand what type the data is (type juggling) before doing comparison. > "If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically. These rules also apply to the switch statement. The type conversion does not take place when the comparison is === or !== as this involves comparing the type as well as the value." > [http://php.net/manual/en/language.operators.comparison.php]
let's take an example "0e1" == "0". This operand will return True even the two strings are different.
in this case, php will guess them as the numbers not the string (type juggling), the left side, "0e1", php considers it as a scientific notation, and treats it as 0*10^1 = 0, then the right side also will be treated as 0 (number). from now, php will compare these 2 numbers and return the true result.
Of course, if we reverse the order of the above operand as "0" =="0e1", the result is still the same.
Then, we just pass the filename argument as "flag.php", sig=0 and the value of timestamp will be varied until we get the flag (when the real calculated signature contains "0exxxxxxxxxxxxxx" (14 of x(s) must be the number) at the beginning.