9

During source code examination for a client, I found this code. It gets unsanitized parameter from GET, sanitizes it and does shell_exec()

$arg = $_GET['arg'];

// sanitization, I suppose...
if(preg_match("/[#\&\\+\-%@=\\\:;,\.\'\"\^`~\_|\!\/\?\*$#<>()\[\]\{\}]/i", $arg, $match)) exit;

$code = shell_exec("/some/app $arg");

echo $code;

I know that you need to escapeshellarg() before piping to shell_exec(). I’m not here for that answer.

My question is, how can this code be exploited to run arbitrary commands by an attacker? How can an attacker bypass that particular preg_match?

Anders
  • 64,406
  • 24
  • 178
  • 215
John Doe
  • 93
  • 4
  • What app is `/some/app` really? Also, what OS/shell is `shell_exec` using? – Joseph Sible-Reinstate Monica Feb 25 '19 at 03:59
  • @JosephSible It’s a simple C app, gets input, connects to a server, retrieve some data and print to stdout. Tried overflowing it but didn’t work. OS is RHEL 5, don’t know what shell is used for that command. – John Doe Feb 25 '19 at 04:11

1 Answers1

7

At least, the newline is not escaped, so, you can bypass it via /index.php?arg=%0Als (it should list all files from the current directory).

Also, there is a possibility to get a Full Path Disclosure passing arg as an array (/index.php?arg[]=1).

Victor
  • 216
  • 1
  • 4
  • Wow. Newline was not what I expected. Thanks! Still, can’t get useful commands to pass through because all special characters are blocked. Do you have any ideas? – John Doe Feb 25 '19 at 10:02
  • If the attacker is determined (or bored) enough, there is a change that you could get past the `preg_match` by playing with the character encoding (UTF-8 vs ASCII, etc.). – Jacco Feb 25 '19 at 10:28
  • Have you tested this? I wouldn't expect it to work, and some casual investigation supported this - "By default, PCRE treats the subject string as consisting of a single "line" of characters (even if it actually contains several newlines)" – symcbean Feb 25 '19 at 12:50
  • 1
    @JohnDoe It all depends on the environment. As a universal tip: you can try to write your shell into log files and extract it via grep. Also, do not forget that you can bypass that filter using Base64 or hex strings. – Victor Feb 25 '19 at 13:09
  • @symcbean It should work, because the command is executed via shell and `%0A` acts like pressing `Enter`. For example, I tested this one on PHP 5.6.30-0+deb8u1: `php -r 'echo shell_exec("date>date.txt\n cat date.txt\n rm date.txt");'` (that is, it executes three different commands: write date to the file, show contents of the file, remove the file). – Victor Feb 25 '19 at 13:11
  • @Victor: "works like pressing enter" - no, it does not. Not in preg_match(). Try it. – symcbean Feb 25 '19 at 19:28
  • @symcbean Please note that in my example `$arg` is equal to `\nls` (in fact, `\n` is a newline and it does not contain a backslash). Since the newline is not listed in that regex character class, the `preg_match` misses it and `$arg` is executed as `shell_exec("/some/app $arg\nls")`. The newline divides `$arg` into two commands and shell executes each line separately (the same thing happens when you paste a multiline string into your terminal). By the way, make sure that you do not define the variable as `$arg = '%0Als';` or `$arg = '\nls';`, because the right way is `$arg = "\nls";`. – Victor Feb 25 '19 at 21:34
  • @Victor: try it. – symcbean Feb 25 '19 at 22:10
  • @symcbean Sure, I tested it and it works for me. Moreover, since it's an accepted answer and it has some votes, it should testify that the method works for other users. By the way, I published a snippet to run it online and prove that newline is not blocked by that regex http://sandbox.onlinephpfunctions.com/code/3de20fdc6170a4e267a5899f96369a20fcaa21fb – Victor Feb 25 '19 at 22:25
  • Passing a percent-encoded newline works. The problem is I can’t do anything functional because it stops at the sight of special characters. – John Doe Feb 25 '19 at 23:36
  • @JohnDoe I do not know what do you mean by functionality, but even with minimal effort you can get a complete copy of the site using the `tar` command. Also you can navigate through directories or rename them, read or remove files. I think that such things should convince your client that this is a dangerous vulnerability. – Victor Feb 26 '19 at 21:37