I can't decide whether I'm being overly paranoid here, but if I'm running a PHP script from a commandline and that script echo's out user defined content, do I need to escape it?
For example, would this be potentially dangerous or would the text literally just echo out as plain text?
$test = 'shutdown -h now';
echo $test;
If I do need to escape, is it the escapeshellarg() function I want?
The shell interpretes commands from stdin but you are writing to stdout. So everything is fine
However, to prevent you from accidently copy pasting them into a terminal it is never a bad idea to escape them
I do not fully agree with the other answers.
It is right that you write to stdout, so the input won't be interpreted as commands, but some special control sequences can invoke some shell-related behaviour. See here, for example.
These cannot call other programs or commands, but they can annoy the user (he has to type reset for resseting the shell).
It should not be dangerous. User can't invoke any command this way. Of course if you are not using exec() or similar function in between. Please note that passing any argument to phpcli from command line is dangerous. Because this argument may contain "`", that executes the command in shell to get a result.
Related
I'm trying to create a PHP script that creates a file on a remote linux server through ssh, and echos the file contents into it.
However, I cannot figure out how to correctly and safely encode/escape the file contents, so that the contents don't get interpreted as commands.
I'm using phpseclib from here.
I've tried something like
echo $ssh->exec('sudo echo "' . escapeshellarg($newConfig) . '" > /etc/nginx/nginx.conf') . "\n";
but without success.
Thanks,
Steve
What about escapeshellcmd? Quoting the description of that vs escapeshellarg:
escapeshellarg() adds single quotes around a string and quotes/escapes
any existing single quotes allowing you to pass a string directly to a
shell function and having it be treated as a single safe argument.
...and...
escapeshellcmd() escapes any characters in a string that might be used
to trick a shell command into executing arbitrary commands. This
function should be used to make sure that any data coming from user
input is escaped before this data is passed to the exec() or system()
functions, or to the backtick operator.
Following characters are preceded by a backslash: #&;`|*?~<>^()[]{}$\,
\x0A and \xFF. ' and " are escaped only if they are not paired. In
Windows, all these characters plus % are replaced by a space instead.
I was going about this all wrong, I should have used Net_SFTP instead of NET_SSH for this sort of thing.
I'm learning PHP and writing it and executing in the browser is cumbersome.
So I write it as a script and execute it on the terminal, such as
me#machine $ php script.php
However, it seems to me, all statements are printed to the same line, if not explicitly a newline character is also printed.
<?php
echo "Hello World.\n";
?>
If I omit \n, I end up with
me#machine $ php hello_world.php
Hello World. > me#machine $
which kind of is lame.
Do I really, like really really (as in "totally really"), need to type \n for every statement I like to test?
You've got a choice:
Include a \n on the end, and have a line feed.
Leave out the \n and don't have a line feed.
It's up to you. No, you don't need to have it there, but if you want to output text to the command line, you probably do want it.
I guess there's one other alternative. Since PHP outputs content that is outside of the <?php .. ?> tags as plain text, you could just put a blank line at the end of your code after the final ?>. That will cause PHP to output a new line at the end without you needing to write \n.
But to be honest, putting the \n in your string is better coding practice. (And frankly, \n isn't exactly the worst thing in the world to having in your code. if you can't cope with the horrors of seeing \n in your code, then you're going to have a hard time reading most program code anyway... just wait to you learn Regex!!!)
No. You might write your own writeLn() function and maybe use PHP_EOL instead of \n, depending on what the script is for. (New-line string differ across systems, and PHP_EOL is your server's version of new-line, so it makes your script portable at least in regard of the running environment.)
Yes, you need to use \n to print a new line.
PHP will only print that which you tell it to print. So, if you want a new line then you need to print a new line.
Depending on your requirements.
\n is representing a new line break.
So if you are testing a single command with a single echo, from command line you might beable to go without the newline break.
If you have multiple echos, all the output will be jumbled into one long text.
function NewLine ($Text)
{
$Text = $Text."\n";
return $Text;
}
echo NewLine('This Text Will Have A New Line Appended To The End');
I am writing php code which will work under *nix systems. I need to call a python script with 5 arguments inside php code. Some of arguments
are user input so there could be any characters. I cannot figure out how pass arguments to a script. How would I separate arguments?. For example in this question you separate by end of line character, but in my arguments could be anything written by users. How to pass such arguments? any ideas?
EDIT:
I have idea of putting escape character in each quotes symbols ' or " before
passing arguments, on the other end I will get rid of escape character. Does json encoding do it?
The function you want is escapeshellcmd():
$arg1 = escapeshellarg($input1);
$arg2 = "foo";
$arg3 = escapeshellarg($input3);
$arg4 = "bar";
$arg5 = escapeshellarg("a string containing spaces and other *special* characters");
$proc = proc_open("python_prog $arg1 $arg2 $arg3 $arg4 $arg5", ...);
In the other thread, the program didn't take any arguments, the newlines were being used to separate items on standard input.
You're basically executing a command on the command prompt; you might want to familiarize yourself with a command prompt first.
Parameters are separated by spaces. So if your inputs have spaces in them, you have to put quotes around these inputs (I suggest single quotes; using a double quote will lead to environment variables being expanded, among other things).
So basically, you have to escape all the single quotes, line breaks, and carriage returns in your inputs, surround each of them with single quotes and append them to the command.
Warning: Security-wise, this whole thing is very problematic. If your escape mechanism is not bullet-proof, anyone would be able to execute a command on your server.
An alternate answer would be to write the inputs into a temporary file, and read from this file in your python script. If you have control over this script, I would strongly suggest you to do that.
I've been having trouble running a command using PHP's exec() function on Windows. Per a comment on PHP's site on exec():
In Windows, exec() issues an internal call to "cmd /c your_command".
My command looks like:
"path\to\program.exe" -flag1 attribute1 -flag2 attribute2 -flag3 "attribute3 attribute4"
Under regular execution of this command in my local command prompt, without the /c flag, the command runs fine. However, with the introduction of the /c flag, command prompt tells me that "The system cannot find the path specified."
I think the command prompt is interpreting the double-quoted argument as a path to another file, but that's the furthest I've gotten with this problem.
Does anybody have any ideas on how to get past this? Thanks!
I also encountered this issue, and the cause of it is, indeed, the internal use of "cmd /c" as described in your own answer.
I have done some investigation, and have found that this was resolved in PHP 5.3, which is why some commenters were unable to reproduce it.
It was fixed in the following commit:
https://github.com/php/php-src/commit/19322fc782af429938da8d3b421c0807cf1b848a#diff-15f2d3ef68f383a87cce668765721041R221
For anyone who still needs to support PHP 5.2, it is fairly easy to replicate the fix in your own code. Instead of:
$cmd = "...any shell command, maybe with multiple quotes...";
exec($cmd);
use
function safe_exec($cmd, &$output = null, &$result_code = null) {
if (strtoupper(substr(php_uname('s'), 0, 3)) == "WIN"
&& version_compare(PHP_VERSION, "5.3", "<"))
{
$cmd = '"' . $cmd . '"';
}
return exec($cmd, $output, $result_code);
}
$cmd = "...any shell command, maybe with multiple quotes...";
safe_exec($cmd);
This replicates the behaviour of PHP 5.3 and above, in the same way as in the above-linked commit.
Note that this applies to all shell commands, not just exec() as used in my example.
I've figured out the answer by myself...
After perusing cmd.exe's /? and trying to decipher that, I've noticed one important section:
If all of the following conditions are met, then quote characters on the command line are preserved:
No /S switch (Strip quotes)
Exactly two quote characters
No special characters between the two quote characters, where special is one of: & < >( ) # ^ |
There are one or more whitespace characters between the the two quote characters
The string between the two quote characters is the name of an executable file.
Otherwise, old behavior is to see if the first character is a quote character and if so, strip the leading character and remove the last quote character on the command line, preserving any text after the last quote character. To negate this behaviour use a double set of quotes "" at the start and end of the command line.
It seems as though if there more than one pair of quotes at any time, quotation marks will be stripped from the second pair of quotes and on.
A relevant question: How do I deal with quote characters when using cmd.exe but not completely relevant, since PHP will not allow you to modify its exec() command by putting an /S flag on its call (which would definitely be a lot easier).
I've managed to work around this problem by directly changing directories with chdir() to the folder where the .exe is located, then chdir()'ing back to my original working directory. It's an extremely hacky solution, given the case that I'm lucky that I only have one set of arguments using double quotes. If anybody were to have multiple arguments using double quotes, I wouldn't know how to solve that...
Just a guess (I am not familiar with PHP on windows): maybe escape the quotes as " becoming ""?
"path\to\program.exe" -flag1 attribute1 -flag2 attribute2 -flag3 ""attribute3 attribute4""
Whatever the solution is, make sure that when there's some form of user-input that gets passed to this command as arguments that you use escapeshellarg and/or escapeshellcmd.
I hope it will help
escapeshellarg() — Escape a string to be used as a shell argument
escapeshellcmd() — Escape shell metacharacters
Php has a method escapeshellcmd() that escapes any characters in a string that might be used to trick a shell command into executing arbitrary commands.
<?php
exec(find /music -type f -iname '*mp3'", $arrSongPaths);
echo $arrSongPaths[0] //prints It Won´t Be Long.mp3;
echo escapeshellcmd($arrSongPaths[0]) //prints It Wont Be Long.mp3;
?>
Is there a way to write a shell script that will recursively rename filenames (in particular *mp3) with special characters escaped?
I tried to do this in php
$escapedSongPath = escapeshellarg($arrSongPaths[0]);
exec("mv $arrSongPaths[0] $escapedSongPath");
but that didn't work. Anyways the last line of code is unsafe since you're executing a command with a potentially dangerous filename $arrSongPaths[0].
For the love of all things security related why aren't you using the php rename command - it doesn't suffer from any shell escape issues. replace the exec("mv ...") with:
rename($arrSongPaths[0], $escapedSongPath)
... and check for errors.
And instead of using exec(find...) use the recursive_glob tip from the glob php operation page.