1

I'm curious if there is a way to make user input safe for grep commands. I have a search box that should allow an end user to search a directory recursively for files containing a string.

I could accomplish this solely with PHP but grep should be faster and is therefore preferable so long as it can be made safe.

I will not know the contents of the search string but it will likely have a limit of n characters.

FamousAv8er
  • 299
  • 1
  • 8
  • 1
    The type of attack that you describe is known as a `command line injection attack`. You mention that the user input comes from a search box. Is the search box part of a web application interface? If so, then whatever you are using for server-side scripting (e.g. php) should have a function for sanitizing the user input to mitigate CLI attacks. If you're using PHP, see https://www.php.net/manual/en/function.escapeshellcmd.php – mti2935 Sep 24 '20 at 16:15

3 Answers3

1

You can prevent command injection which should be done by giving the regex to grep via stdin rather than relying on escapeshellarg() as it has some tricky edge cases like argument injection. You will still be vulnerable to regular expression abuse such as denial of service and can also disclose content of unintended files. Try running grep '' /etc/passwd.

Most search functions work by analysing files/content and building a data store which can be queried. Using grep is a dirty work around and has some.big problems.

wireghoul
  • 5,745
  • 2
  • 17
  • 26
0

To prevent command injection in PHP, there are some utility functions that help sanitize user data. @mti2935 already mentioned escapeshellcmd, but that allows for multiple arbitrary arguments to be inserted by the user. If you just want to limit it to grep's pattern argument, use escapeshellarg to prevent the user from escaping that single argument.

multithr3at3d
  • 12,355
  • 3
  • 29
  • 42
0

You first need to distinguish between running grep through a shell and running grep directly (via the exec system call).

If you run grep directly (e.g. via exec syscall) there's no way to escape the parameter since grep does not expand arguments. You can use the PHP proc_open() function to do this. This would be my first choice.

If you run grep via a shell (sh, bash, csh, tcsh, etc), it's incredibly difficult to ensure the parameter cannot be escaped and introduce various security vulnerabilities. This is what the PHP exec() function does.

For example, if you enclose the parameter with double quotes ("something"), the shell will still expand $var, `cmd`, etc. That is before mentioning that a double quote will terminate the field and allow the attacker to run any command.

If you enclose the parameter with single quote ('something'), there aren't many special characters that can escape the parameter (except a single quote), but in csh/tcsh, for example, you can still access the history (with !) even inside single quotes.

If you can limit the grep to a limited character set (e.g. a-z,A-Z,0-9), you could sanitize the input to ensure it contains nothing else.

Another problem to consider is that if the input starts with a dash (-), grep will see it as a flag regardless of how you execute it.

Ideally you would both sanitize the input and use proc_open() to ensure there's no shell expansion. I think that would be reasonably safe.

eyalk
  • 21
  • 2