Problem Description
We created this web interface to run commands on our servers, but since we haven't figured out how to secure it yet we only let you run 'ls'
http://challenges.fbctf.com:8085
(This problem does not require any brute force or scanning.
We will ban your team if we detect brute force or scanning).
Application Overview
The webpage has a single form that accepts a command in a JSON format
{ "cmd": "command to execute" }
As described by the problem we should be able to execute ls
with:
{ "cmd": "ls" }
Problem
However when trying ls ..
the command is rejected by the server
As it turns out the request is filtered by this insane looking regex:
} elseif (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/>';
}
As you can see, pretty much all characters except lowercase alphabet and space are not allowed.
Bypassing preg_match
One of the most common ways to bypass pregmatch is to use multiline inputs, because pregmatch only tries to match the first line. Lucky for us JSON can be formatted to be multiline, for example:
{
"cmd": "ls /home/rceservice"
}
Since there were no checks to filter out multiline inputs, we can send this exact input to the server and recieve a welcoming response:
Looks like there is a flag file. However, running this payload yields an empty response.
{
"cmd": "cat /home/rceservice/flag"
}
"Escaping" the jail
As it turns out, the application's PATH variable was changed by:
putenv('PATH=/home/rceservice/jail');
This means that our current PATH contained the ls binary, which let us execute it, but not cat. We can bypass this by using the absolute path to cat which is /bin/cat
. The payload then becomes:
{
"cmd": "/bin/cat /home/rceservice/flag"
}
Flag: fb{pr3g_M@tcH_m@K3s_m3_w@Nt_t0_cry!!1!!1!}
Final Notes
As it turns out, the multi-line JSON exploit wasn't the intended solution by the Facebook team. The intended solution involves exploiting the backtrack and recursion limit of pcre. If this limit is reached, preg_match may return the wrong matching result.