Contents

Web challenge

The challenge

The challenge gives us an URL which has a page with a text input and a submit button. The inserted command is sent via POST:

1
comando=ls

We tried different commands and we always received the same message: Acción no autorizada. After some tries, we figured out the command input did not like alpha-numeric characters, and only when we added symbols, we did not get that error message. Moreover, we could trigger some PHP errors that leaked the function used for sanitizing the input, which was preg_match. With this premise, we could think that the page would have something like this:

1
2
3
4
5
if (!preg_match('\[a-z0-9]/si')) {
  eval($_POST['comando']);
} else {
  echo 'Acción no autorizada';
}
  • a-z: Any letter from a to z.
  • 0-9: Any number from 0 to 9.
  • s: Single line.
  • i: Case insensitive.

Additional info:

When the s is not present, I read [1] a writeup on how to bypass this type of filter just by using multilines since preg_match will only take the first line. Example from the writeup [1]:

1
2
3
if (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
    echo 'Hacking attempt detected<br/><br/>';
}

While this input will be detected:

1
{ "cmd": "ls" }

The following one will bypass it:

1
2
3
{
  "cmd": "ls"
}

End additional info

PHPFuck

I remembered something I read long ago which was used to write PHP code with only symbols, it was called PHPFuck.

The concept behind PHPFuck is to use operations with implicit string conversions and XOR operations on characters. Using this, you can get to represent any letter and symbol to write PHP code. Lets work on the basics:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
php > echo [].[];
ArrayArray

php > echo []^[];
0

php > echo []^[[]];
1

php > var_dump([][[]]);
NULL

Knowing the above, we can build the character p as a result of the operation 'A' ^ '1':

1
2
3
([].[])[([]^[])] // A

([]^[[]]).[][[]] // 1

so:

1
2
php > echo ([].[])[([]^[])] ^ ([]^[[]]).[][[]];
p

Recommended reading: https://ctf-wiki.github.io/ctf-wiki/web/php/php/

Solution - Preg match code execution

We used the same concept of PHPFuck for crafting a payload to evade the input command filter.

And we got the flag!

References