For the fourth challenge in the Random tier, users are presented with a PHP script. This particular script weighs in around 1500 lines and presents a user with text-based maze-like game where they must appropriately choose the correct path the receive the answer.

Figure Maze provided to users

Looking at the underlying code, we see a large blob of obfuscated PHP code, followed by the HTML that generates the data above. The code looks to consist primarily of what looks to be junk code, along with a few lines of unique code scattered within that actually perform tasks.

Figure PHP code within Merlin’s Maze

Making a copy of this file and removing this junk code provides us with the following:

<?php

$b99=idal(array(238,239,235,238,164));
$l8d4345=idal(array(168,172,177,173,174,165,164));
$z83=idal(array(160,179,179,160,184,158,167,168,173,181,164,179));
$tf082308=idal(array(164,183,160,173,233,166,187,168,175,167,173,160,181,164,233));
$h2bbd60=idal(array(232,232,250));
$z61=idal(array(164,183,160,173));
$nfa8b0b=idal(array(178,180,163,178,181,179));
$x1418=idal(array(229));
$e7r27=idal(array(177,179,164,166,158,179,164,177,173,160,162,164));
$kx3=idal(array(166,164,181,158,165,164,167,168,175,164,165,158,167,180,175,162,181,168,174,175,178));
$l84=$kx3();
$d7f=idal(array(177,160,162,170));
$tc2e980=idal(array(166,187,168,175,167,173,160,181,164));
$mzoha=null;
$l84=$z83($l84[idal(array(180,178,164,179))], idal(array(177,248,247,240,247,246,163)));
$p6a = array();
foreach($l84 as $f){$p6a[] = $nfa8b0b($f,5);};
$ke03 = $d7f(idal(array(137,235)),$l8d4345($mzoha,$p6a));
$r80 = idal(array(170,164,241,242));
$e7r27($b99, $tf082308.$x1418.$r80.$h2bbd60, $mzoha);
function p96167b($zwaxa){global $nfa8b0b; return ($nfa8b0b($zwaxa,0,5)== idal(array(163,245,164,163,165)));}
function idal($zwaxa){global $mzoha; $qoazis34 = $mzoha;for($i=0; $i < count($zwaxa); $i++)$qoazis34.=chr($zwaxa[$i]) ^ chr(193);return $qoazis34;}

?>

After de-obfuscating the code above, we can get a better understanding of what is going on. Comments have been added and the code has been better formatted to show what everything is doing.

<?php

// Decoded: '/.*/e'
$b99=idal(array(238,239,235,238,164));

// Decoded: 'implode'
$l8d4345=idal(array(168,172,177,173,174,165,164));

// Decoded: 'array_filter'
$z83=idal(array(160,179,179,160,184,158,167,168,173,181,164,179));

// Decoded: 'eval(gzinflate('
$tf082308=idal(array(164,183,160,173,233,166,187,168,175,167,173,160,181,164,233));

// Decoded: '));'
$h2bbd60=idal(array(232,232,250));

// Decoded: 'eval'
$z61=idal(array(164,183,160,173));

// Decoded: 'substr'
$nfa8b0b=idal(array(178,180,163,178,181,179));

// Decoded: '$'
$x1418=idal(array(229));

// Decoded: 'preg_replace'
$e7r27=idal(array(177,179,164,166,158,179,164,177,173,160,162,164));

// Decoded: get_defined_functions
$kx3=idal(array(166,164,181,158,165,164,167,168,175,164,165,158,167,180,175,162,181,168,174,175,178));

// $l84 holds an array of all of the functions within the script. 
$l84=$kx3();

// Decoded: 'pack'
$d7f=idal(array(177,160,162,170));

// Decoded: 'gzinflate'
$tc2e980=idal(array(166,187,168,175,167,173,160,181,164));

$mzoha=null;

// Decoded: 'user'
// Decoded: 'p96167b'
// This line performs an array_filter against all of the user functions within
// the script. It passes these function names to the the p96167b() function.
$l84=$z83($l84[idal(array(180,178,164,179))], idal(array(177,248,247,240,247,246,163)));

// At this point, $l84 contains all of the function names in the script that 
// start with a string of 'b4ebd'. The remaining data from these function names
// is appended to an array.
$p6a = array();
foreach($l84 as $f){
	$p6a[] = $nfa8b0b($f,5);
};

// Decoded: 'H*'
// This line unhexes the data contained within the $p6a variable. 
$ke03 = $d7f(idal(array(137,235)), $l8d4345($mzoha,$p6a));

// Decoded: ke03
$r80 = idal(array(170,164,241,242));

// This line does a number of things. It translates to the following:
// preg_replace('/.*/e', eval(gzinflate($ke03));, $mzoha );
// Simply put, it will gzinflate and evaluate the data. 
$e7r27($b99, $tf082308.$x1418.$r80.$h2bbd60, $mzoha);

// This function looks at the provided string and performs a 'substr' against
// the first 5 bytes. It proceeds to compare it against a string of 'b4ebd' 
// to see if it's a match.
function p96167b($zwaxa){
	global $nfa8b0b; 
	// Decoded: 'b4ebd'
	return ($nfa8b0b($zwaxa,0,5) == idal(array(163,245,164,163,165)));
}

// This function is responsible for XORing the provided array of 
// bytes against 193.
function idal($zwaxa){
	global $mzoha; 
	$qoazis34 = $mzoha;
	for($i=0; $i < count($zwaxa); $i++)
		$qoazis34.=chr($zwaxa[$i]) ^ chr(193);
	return $qoazis34;
}

?>

Using this information, we can decode the provided PHP using the following Python code:

import sys, re, binascii, zlib, base64

def gzinflate(compressed_data):
	return zlib.decompress(compressed_data, -15)

php_file = "MerlinsMaze.php"
php_fh = open(php_file, 'rb')
php_data = php_fh.read()
php_fh.close()

all_data = ""
found_function_names = re.findall("function b4ebd(\w+)", php_data)
all_data = "".join(found_function_names)

print gzinflate(binascii.unhexlify(all_data))

This leaves us with the following decoded PHP code:


$alalalala = ".backup.bin";
$oilk = "5c59295d2d2461565";
if(!(file_exists($alalalala))) {
	$jqqqqq = fopen($alalalala, 'w+');
	fwrite($jqqqqq, "");
	fclose($jqqqqq);
}
$ukl = "";
if(filesize($alalalala) > 0)
{
	$jqqqqq = fopen($alalalala, 'r+');
	$khfmal = fread($jqqqqq, filesize($alalalala));
	$ghhhggv = split(", ", $khfmal);
	fclose($jqqqqq);
}
else{ $ghhhggv = array();}
$oilk = $oilk+"529206651412d2a5d";
$ukl.="16727839782a2524105a4";
if(isset($_GET['path'])){
	$p = $_GET['path'];
	$to_write = "";
	$ghhhggv[] = $p;
	$jqqqqq = fopen($alalalala, 'w');
	fwrite($jqqqqq, implode(", ", $ghhhggv));
	fclose($jqqqqq);
}
$ukl.="51550125a203";
function l(){
	global $alalalala;
	$jqqqqq = fopen($alalalala, 'w+');
	fwrite($jqqqqq, "");
	fclose($jqqqqq);
	$c = rand(0, 10);
	if($c<1){
		return "A super fluffly dog mauls you to death.";
	}elseif($c<2){
		return "You have been defeated by David Bowie's juggling.";
	}elseif($c<3){
		return "The maze drives you to madness and you spiral into a world of chaos.";
	}elseif($c<4){
		return "Jennifer Connelly's teenage angst defeats you.";
	}elseif($c<5){
		return "You die of dysentery.";
	}elseif($c<6){
		return "You don't really die. You just kind of lie there and give up.";
	}elseif($c<7){
		return "A white owl flies overhead. Oh, also, you lose.";
	}elseif($c<8){
		return "A weird goblin shows up and scares you away.";
	}else{
		return "Jim Henson returns from the dead and possesses you.";
	}
}
function c2($okal){
	$f=0;
	if($okal[20]!='f'){$f=4;}
	if(strtolower(substr("F12AB867ACDBE57",8,2))!=chr(97).$okal[22]){$f=1;}
	if($okal[25]!='p'){$f=3;}
	if($okal[22]==$okal[28]){$f=8;}
	return $f;
}
$ukl.="b20665a5";
$ukl.="56220565a455";
$k = array();
foreach ($ghhhggv as $a){
	switch(trim($a)){
		case("Up"):
			$k[] = "A";
			break;
		case("Down"):
			$k[] = "0";
			break;
		case("Back"):
			$k[] = "B";
			break;
		case("Forward"):
			$k[] = "8";
			break;
		case("Left"):
			$k[] = "7";
			break;
		case("Right"):
			$k[] = "F";
			break;
		case("246 Degrees"):
			$k[] = "3";
			break;
		case("94 Degrees"):
			$k[] = "C";
			break;
		case("Skip"):
			$k[] = "E";
			break;
		case("Stroll"):
			$k[] = "1";
			break;
		case("Jump"):
			$k[] = "D";
			break;
		case("Run"):
			$k[] = "9";
			break;
		case("North"):
			$k[] = "2";
			break;
		case("South"):
			$k[] = "5";
			break;
		case("East"):
			$k[] = "6";
			break;
		case("West"):
			$k[] = "4";
			break;
		default:
			print "DANGER ".$a;
	}
}
$ukl.="55f5023352d295d456c14";
function x_oiflksf($goijas, $oijasf) {
	$goijas = implode("", $goijas);
	$o_joijasd = '';
	for($i=0; $i<strlen($oijasf);)
	{
		for($j=0;($j<strlen($goijas) && $i<strlen($oijasf));$j++,$i++)
		{
		 	$o_joijasd .= $oijasf{$i} ^ $goijas{$j};
		}
	}  
 return $o_joijasd;
}
$ukl.="022f325f1f16";
function lkj080jo($oilk, $ukl){
	return x_oiflksf($oilk, $ukl);
}
$ukl.="4544424724353666";
$ukl.="544127";
function bxmsadfj($a, $b){
	$a.="2b37174a";
	$u = pack('H*', $a);
	return x_oiflksf($b, $u);
}
function get_key(){return gnfjk();}
$ukl.="634a58585c425a2f";
function uan($kfj){
	$y = sizeof($kfj);
	if($y > 20){
		$lxkf = implode("",$kfj);
		if(strrev(substr($lxkf,10,4))!="2156"){return 0;}
		if($lxkf[5]!=$lxkf[6]){return 0;}
		preg_match_all('/.{1}(.+)/', $lxkf, $o);
		if($o[1][0][1]!="6"){return 0;}
		if(ord($kfj[0])+ord($kfj[18])!=140){return 0;}
	}
	if((100/5/2) == 10){return 1;}
	if($kfj[3]=='1'){return 0;}
	return 0;
}
$ukl.="2437665a58345b2f3524541d1";
function gnfjk(){return l();}
$ukl.="67154535b61362c325d13";
function lkj($l){
	$zl = sizeof($l);
	if($zl>12){
		if($l[3]!=substr("ABCDEFABCDEF",-5,1)){return true;}
		if($l[20*10/20-2]!=substr("759480376789",5,1)){return true;}
		if(substr(base64_encode("orb"),1,1)!=$l[9]){return true;}
	}
	if($zl>22){
		$qzlf = implode("",$l);
		preg_match_all('/.{19}(.).(.)/', $qzlf, $yy);
		if($yy[1][0]!="5"){return true;}
		if($yy[2][0]!="B"){return true;}
	}
	return false;
}
function hj($h){
	$z = sizeof($h);
	$f = 1;
	if($z > 28){
		if(chr(11*6)!=$h[21]){$f=0;}
		if(chr(49+1+1-(8*0))!=$h[1]){$f=0;}
		if(chr(ord($h[19])+1)!=$h[27]){$f=0;}
		if(substr(strrev(base64_encode("!1!Goblin King oh my!1!")),25,1)!=$h[26]){$f=0;}
	}
	if($z>25){
		if((ord("a")-40)!=ord($h[23])){$f=0;}
		if(substr("53812E7F82ABFE",5,2)!=($h[17].$h[24])){$f=0;}
	}
	return $f;
}
function c($k){
	global $ukl;
	$sz = sizeof($k);
	if($sz == 1){
		if($k[0] == "F"){   
			$k1 = "2365";
			$x = "AF05236525";
			$k1 = $k1+$x;
		} else { return l(); }
	}
	if($sz > 6){         
		$j = ord($k[5]);
		if($j != 67){ return l();}
	}
	if($sz > 5){
		if($k[4] != "4"){return get_key();}
	}
	if(uan($k)!=1){return gnfjk();}
	if(hj($k)!=1){return l();}
	if($sz>24){
		if('A'!=$k[16]){return get_key();}
	}
	if($sz > 8){
		$o = ord($k[7]);  
		$o = ($o + 17) / 2;
		$o = $o * 4;
		$o = chr($o - 56);
		if($o != 'l'){return l();}else{$key2 = "EB45C";}
	}
	if(lkj($k)){return gnfjk();}
	if(($sz+31) == 63){
		if(array_slice($k,29,3)!=array("B","A","D")){return get_key();}
		$jl = bxmsadfj($ukl, $k);
		$d = c2($jl);
		if($d > 5){ 
			$t1 = "You have naviga";
			$t2 = "Surprise! You've encountered ";
			$t1 .= "ted the ma";
			$tl = "The Goblin King. ";
			$t2 .= "the Gob";
			/* Hi. Congrats on getting this far. */
			$t1 .= "ze and de";
			$t2 .= "lin King!";
			/*
				Once upon a time, there was a beautiful young 
				girl whose stepmother 
				always made her stay home with the baby. And the baby was a spoiled 
				child, and wanted everything to himself, and 
				the young girl was 
				practically a slave. But what no one knew is that the king of the 
				goblins had fallen in love with the the 
				girl, and he had given her 
				certain powers. So one night, when the baby had be 
				particularly 
				cruel 
				to 
				her, she 
				called 
				on the goblins 
				for 
				help!
			*/
			$t1 .= "feated Dav";
			$t1 .= "id Bowie! <p>K";
			$tl .= "He shall return with this key: ";
			$t2 .= "You found the key: ";
			$t1 .= "ey: ".$jl."</p>";
			if(substr($t1,23,1)!=$jl[14]){return str_replace('.','!',str_replace(" ","_",$jl));}
			if($k[9]!=$k[1]){return $t2;}
			if($k[31]==$k[0]){return $tl;}
			if($k[15]==$k[16] and lcfirst($k[15])==$jl[15]){return $t1;}
			return l();
		}else{return l();}
	}elseif($sz>32){return l();}
	return "";
}
$khfmal = implode(", ", $ghhhggv);
$t = c($k);

At this point we’re able to trace what is happening when we enter various options within the script. Data is written to a ‘.backup.bin’ file to keep track of what previous data was inputted. After stepping through the code and seeing what checks have been included, we determine that the following order must be provided:

  1. Right

  2. 246 Degrees

  3. East

  4. Back

  5. West

  6. 94 Degrees

  7. 94 Degrees

  8. Up

  9. Down

  10. 246 Degrees

  11. East

  12. South

  13. Stroll

  14. North

  15. Left

  16. Up

  17. Up

  18. Skip

  19. Right

  20. South

  21. 246 Degrees

  22. Back

  23. 94 Degrees

  24. Run

  25. Left

  26. South

  27. Run

  28. East

  29. 246 Degrees

  30. Back

  31. Up

  32. Jump

Entering this into the program leaves us with the following:

Figure Maze after correct answer is inputted

This leave us with a key of ‘PAN{Life is a maze of complications. Also, puppets are sometimes involved. Deal with it.}’.