I have this code :
$path = "/somedirectory/$user";
echo exec('du -s '.escapeshellarg($path));
This code is used to check how many space the user use in his directory. The $user value can be any alphanumeric value and ".-"
Is it safe to use it ?
escapeshellarg ensures that the value is interpreted as a single, plain shell argument without further shell expansion (e. g., no `…`, $(…), ${…}, etc.). That means that any value in $path is passed as is as a single argument to du.
However, as already mentioned, it does not prevent from passing arguments that may be malicious when interpreted by the executable.
This is safe in the sense that it won't run arbitrary commands, but depending on how $user gets set, .. could sneak in there, which would let whoever is looking at this to see the size of the / directory, which may or may not be of concern to you.
Safe if only your exec does not rely on any $user related commands.
For example, $user . "/du -s " is absolutely unsafe.
Related
I could not find the reason why my request fail for the following
My php code is:
if (isset($_COOKIE["user"])) {
echo '<p><h3><strong>Welcome '.$_COOKIE["param"].'</strong></h3></p>'; .....
When i request exec('ls -al') as param , the php code did not run the command.
On the response of the request it was like parameterized:
Welcome exec('ls -al')
What may the reason that failed this execution?
$_COOKIE["param"] is a string. You are echoing it. It is not supposed to run anything.
If you wanted to run a command in your PHP, you would have to use eval(). But as for running a command from a cookie value:
DON'T DO IT!
So you're saying that the value of $_COOKIE['param'] is exec('ls -al'), and you're expecting that to run when you echo it out?
That's not how it works. The value of that cookie will be the string value "exec('ls -al')", not the result of the executed code. If you think about it for a second, you'll understand why it would be a bad idea for a cookie to be able to auto-execute code.
It's not really a great idea to be running random commands through exec() anyway, especially if that input came from a user (which cookies do - the user can and will change them to try to attack you).
Instead, you should be using other input that your code can interpret as a signal to run certain code. For example, you could have the param value hold the string list files, and your code would see that value and run exec('ls -al') for you.
You still shouldn't be execing code to do this though, since it's very easy to accidentally run dangerous commands that way. Instead, you should use PHP's built-in functions as much as possible, and only after sanitizing your inputs and only running known values.
For your case, PHP has a bunch of functions that let you interact with the filesystem of your server. Use those to get a list of files on the system instead.
I'm writing a PHP library that will need to reach out to the system and access a command line program that doesn't have a PHP interface (or PHP library). As such, I was wondering what is the best (and the safest way) to access the system to retrieve output from a CLI program? I've taken a look at both system() and exec(), but still not sure which is the best to use in a situation like this.
The library will get a string of user-passed text, and transmit it to the command line, retrieving back another string of text. Obviously, with passing user-provided data to the CLI, I will be doing a verification to ensure that no executable data can be passed.
I would suggest shell_exec() together with escapeshellcmd() and escapeshellarg().
To clarify (I was on the go when I first posted this answer): The right way to secure a shell command is:
$exe = 'cat';
$args = array('/etc/passwd');
$args = array_map('escapeshellarg', $args);
$escaped = escapeshellcmd($exe . ' ' . implode(' ', $args));
Here's a legitimate demo (and a nefarious demo as well) of the above code.
The above is just a dummy example, of course. But the main idea is that you apply escapeshellarg() to each argument and then call escapeshellcmd() on the whole command string (including the path to the executable and the previously escaped arguments). This is critical in arbitrary commands.
Note: By secure, I mean making it impossible to perform shell injection attacks by escaping characters that have special meaning like >, <, &&, | and more (see the Wikipedia link) while at the same time properly quoting spaces and other characters that may also have special interpretations by the shell.
With that aside, if you're already white-listing all the commands allowed, you already have the best possible security and you don't need the above functions (althought it doesn't hurt to use them anyway).
Regarding the actual calling function, they all pretty much do the same thing with a few quirks. Personally, I prefer shell_exec() since its return value is more versatile (from this page):
exec(): returns the last line of output from the command and flushes nothing.
shell_exec(): returns the entire output from the command and flushes nothing.
system(): returns the last line of output from the command and tries to flush the output buffer after each line of the output as it goes.
passthru(): returns nothing and passes the resulting output without interference to the browser, especially useful when the output is in binary format.
Except from the system() exit return code, you can mimic the behavior of all the other functions with the return value of shell_exec(). However, the inverse it's either harder to do, or just not possible.
I hope this clears things up for you.
Ideally, you would use passthru() from a pre-defined list of possible inputs (so that if user input == 'operation_a' you can { passthru('operation_a'); } without worrying about sanitizing input). Otherwise, use passthru() with some serious sanitation of input. passthru() allows you to capture the output of the command and pass the whole lump back to the browser. This function is particularly useful if you are expecting binary output (like from image generation, &c.).
I have a script that calls a bash script that does some processing, but the script calls the bash script using user inputed data.
I am wondering if there is a way to make sure the person (it's a file upload) doesn't append like ;cd /;rm -rf * to the end of the file. Or anything else like that. Would a normal MYSQL Injection methods work? Is there a better alternative?
Being able to inject shell commands would be ... shell command injection, and neither file nor SQL injection. To secure against it, use escapeshellarg:
exec('bash bash-script ' . escapeshellarg($userInput));
Did you check escapeshellcmd() and escapeshellarg() or am I missing the point?
Securing this process is a two-way procedure:
ensuring the input meets some criteria (especially on maximum types)
ensuring the input cannot leak and change the process itself
Let's say I'm passing a number to a program...
$num = $_GET['num']; // get the input
$num = (int)$_GET['num']; // ensure it is an integer
$num = max($num, 0); // ensure it is at least 0
$num = min($num, 800); // ensure it is at most 800
$num = escapeshellarg($num); // this is overkill at this point, but you never know
exec('command '.$num);
As advised above, you can also have your own little language to do this but...
it may still be vulnerable
it may be overkill for a simple task
it is just an advanced version of the filter system
Finally, there's another alternative. There are functions that accept the command and parameters as separate arguments, such as popen() (you can push command arguments through pipes). But this depends on implementation.
How do I use a PHP5 variable inside a system() call
$dir = '/etc/somedir';
eg system("ls $dir")
I think I'm missing something
I am actually passing a variable from a post
e.g.
$username = $_POST[username];
to a system call
system("processData --user $username --pass $password");
this isn't working, so i trivialised down to a simple
example
You are doing it fine except that you are missing semi-colon (;)
system("ls $dir");
You can also do like:
system("ls" . $dir);
Note:
When allowing user-supplied data to be
passed to this function, use
escapeshellarg() or
escapeshellcmd() to ensure that
users cannot trick the system into
executing arbitrary commands.
it looks like you are not.. could you extend your example? are there any errors returned? what does the system() function return?
you should keep in mind that system() returns only the last line of the run command.
also, instead of 'ls' you can use a built-in php function like dir() or DirectoryIterator
I have a PHP script which calls another script in order to add IP addresses to a whitelist. I sometimes want to whitelist all addresses, in which case I have it call
exec("otherscript *.*.*.*", output, retval);
This worked fine, adding the string "*.*.*.*" to the whitelist until I happened to have another file in the directory of the php script that matched that pattern ("foo.1.tar.gz"), at which point the wildcards were expanded, and I ended up with the filename in my whitelist. Is there some way to disable globbing in php's exec? It isn't mentioned in the PHP docs as far as I can tell.
escapeshellarg will make sure your string is safe for using as a shell argument. Globbing is probably not mentioned in the manual because it's up to the shell, and also differs between different shells.
$address = escapeshellarg('*.*.*.*');
exec("otherscript $address", $output, $retval);
Quoting the parameter should help:
exec("otherscript '*.*.*.*'", output, retval);