Using $_GET in system() function - security question - php

So let's say we have a following code:
<?php
$str = addslashes($_GET['str']);
$cmd = 'sometool "'.$str.'"';
system($cmd);
?>
Is it secure? Can I escape from double quotes somehow? The operating system in linux.
Purely theoretical consideration. I don't use it in my code ;)

It's not secure. You can still pass some arguments that will be malicious, i.e. execute other files in system.
$var = '$(sh file.sh)';
$str = addslashes($var);
$cmd = 'sometool "'.$str.'"';
system($cmd);
You should use escapeshellarg method for escaping shell arguments.
$str = escapeshellarg($_GET['str']);
$cmd = 'sometool ' . $str;
system($cmd);
Note that you have to use the argument $str as it is and that it will be a single argument. You must not surround it with quotes ' or double quotes "

Definitively not secure as is,
Like any user's input, you'll have to not only escape quotes, but also verify the conformity of the data being submitted and have to be strict on that.
For e.g.: if the "sometool" command is waiting for a path, you've to ensure that the user input is a valid path. If the path has to be in a restricted location, you've to check that restriction.
Assuming that your "str" has to be a valid string, you can begin with the filter input function.
https://www.php.net/manual/en/function.filter-input.php
Make sure to use the appropriate filters (for quotes, encoding, etc.) : https://www.php.net/manual/en/filter.filters.php.
It will not be possible to by-pass the escaping here.
This somehow ensure the conformity of the data, but still, you've to be sure that the command "sometool" itself will not be affected by any valid string characters or syntax, that's what makes it still unsecure to use.

Related

PHP SSH Lib, echoing to a file

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.

Safe way to process passage with quote and double quote in PHP?

Suppose I am importing a passage by file_get_contents() or getting user input, there may be single quotes or double quotes or both. What is the safe way to cast the said content into a variable and do manipulation afterward?
It depends on what you are about to do with the input later on:
Output as HTML:
$input = htmlspecialchars($input);
Use it in a shell command:
$input = escapeshellarg($input);
Use it in a database query
If you use prepared statements you are fine. If not (why?), use:
$input = mysqli_real_escape_string($mysqli, $string);
// or
$input = PDO::quote($input);
// other database extension may introduce their own quoting functions
Use it in a regular expression:
$input = preg_quote($input);
Extension or correction of this list is appreciated.... :)

php, proc_open how pass multiple arguments

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.

Apostrophe issue

I have built a search engine using php and mysql.
Problem:
When I submit a word with an apostrophe in it and return the value to the text field using $_GET the apostrophe has been replaced with a backslash and all characters after the apostrophe are missing.
Example:
Submitted Words: Just can't get enough
Returned Value (Using $_GET): Just can\
Also the url comes up like this:search=just+can%27t+get+enough
As you can see the ' has been replaced with a \ and get enough is missing.
Question:
Does anybody know what causes this to happen and what is the solution to fix this problem?
The code:
http://tinypaste.com/11d62
If you're running PHP version less than 5.3.0, the slash might be added by the Magic Quotes which you can turn off in the .ini file.
From your description of "value to the text field" I speculate you have some output code like this:
Redisplay
<input value='<?=$_GET['search']?>'>
In that case the contained single quote will terminate the html attribute. And anything behind the single quote is simply garbage to the browser. In this case applying htmlspecialchars to the output helps.
(The backslash is likely due to magic_quotes or mysql_*_escape before outputting the text. I doubt the question describes a database error here.)
Update: It seems it's indeed an output problem here:
echo "<a href='searchmusic.php?search=$search&s=$next'>Next</a>";
Regardless of if you use single or double quotes you would need:
echo "<a href='searchmusic.php?search="
. htmlspecialchars(stripslashes($search))
. "&s=$next'>Next</a>";
(Notice that using stripslashes is a workaround here. You should preserve the original search text, or disable the magic_quotes rather.)
Okay I forgot something crucial. htmlspecialchars needs the ENT_QUOTES parameter - always, and in your case particularly:
// prepare for later output:
$search = $_GET['search'];
$html_search = htmlspecialchars(stripslashes($search), ENT_QUOTES);
And then use that whereever you wanted to display $search before:
echo "<a href='searchmusic.php?search=$html_search&s=$next'>Next</a>";
Single quotes are important in PHP and MySQL.
A single quote is a delimeter for a string in PHP, for example:
$str = 'my string';
If you want to include a literal quote inside a string you must tell PHP that the quote is not the end of the string. It is escaped with the backslash, for example:
$str = 'my string with a quote \' inside it';
See PHP Strings for more on this.
MySQL operates in a similar way. An example query might be:
$username = 'andyb';
$quert = "SELECT * FROM users WHERE user_name = '$username'";
The single quote delimits the string parameter. If the $username included a single quote, this would cause the query to end prematurely. Correctly escaping parameters is an important concept to be familiar with as it is one attack vector for breaking into a database - see SQL Injection for more information.
One way to handle this escaping is with mysql_real_escape_string().

Securing a string before exec()ing it

I have a PHP app which takes a user-inputted $imageurl and does the following:
exec('convert "'.$url.'" -thumbnail 80x500 "images/out.jpg"');
Now obviously I have to take some precautions with this to stop users from executing arbitrary code. For example, if the user sets $url to";rm -rf *;" is no good at all.
So for starters I have to filter out " so that no matter what they type in, they can't escape from their input being a parameter to convert. But should I filter out ; as well? I've seen urls with semicolons in them... and while the semicolon is really the danger here, filtering out " would still keep me safe right? But can urls have " in them? And are there any other characters I should watch for?
Maybe instead of filtering characters out I should try to escape them. So should I try to escape every character interpreted specially by the shell? Or just escape " as everything else is sort of "pre-escaped" given that it's inside double-quotes?
Sorry for my rambling confusion, I'm just new at this and want to stay safe!
Thanks,
Mala
Well, if you want to make sure the URL is a URL, use filter_var
filter_var($url, FILTER_VALIDATE_URL);
This will not prevent people from supplying a URL like example.com/foo?;rm -rf though, which is still a valid URL. I'm not sure if this would cause rm to execute, but you could also check the URL with parse_url() and omit the query part.
Generally, it is a good idea to have a look at these as well:
escapeshellarg() — Escape a string to be used as a shell argument
escapeshellcmd() — Escape shell metacharacters
Also see the PHP Manual on securing user input.
You can use the escapeshellarg function.
Use Regular Expressions to ensure that $url only contains valid filename characters, e.g. "(\w\.\-/){1,256}". Plus, I imagine you are renaming the file the user uploads to be a random filename, or at least a whitelisted filename (i.e. using the same regex). sha1.ext or md5.ext are easy formats to use.

Categories