websec.fr level05

Starting from the source, we see that every word that meets a valid word regex is passed through to a correct function:

$q = substr ($_REQUEST['q'], 0, 256);  # Our spellchecker is a bit slow, do not DoS it please.
$blacklist = implode (["'", '"', '(', ')', ' ', '`']);

$corrected = preg_replace ("/([^$blacklist]{2,})/ie", 'correct ("\\1")', $q);

The final regex after array implosion is /([^'"() ]/ie (there's a grave accent in there but Ghost refuses to let me escape it), so we can't use any of those characters in our final payload.

What's important to note is the use of preg_replace with the e modifier. From the PHP manual:

Warning: This feature was DEPRECATED in PHP 5.5.0, and REMOVED as of PHP 7.0.0.

If this deprecated modifier is set, preg_replace() does normal substitution of backreferences in the replacement string, evaluates it as PHP code, and uses the result for replacing the search string. Single quotes, double quotes, backslashes () and NULL chars will be escaped by backslashes in substituted backreferences.

Hence, we have a vector for code execution!

# We use /**/ to act as an space to separate the require statement
# A literal newline will also work here too
${require/**/$_GET['require_file']} $flag # $_GET['require_file'] => flag.php
Show Comments

Get the latest posts delivered right to your inbox.