I haven't found this question on here yet, and I have done some quick Google research on this but I couldn't really find a clear or good answer to this question.
Is it possible to inject a piece of php code in an input field. that would actually work.
//for instance.
//Ill fill in '"test()"' in the field.
<input type="text" name="input" value="'"test()"'">
$injection = $_POST/*(or $_GET)*/['input']; // coming from the input
public function test(){
echo "injection successful";
}
So is this possible?
It is possible, but not like that. If you do what you do in your script, then the code would just be assigned as-is (as a string) to the variable $injection.
You can however execute it like this:
$injection = $_POST/*(or $_GET)*/['input'];
eval($injection);
There are other ways as well, but all have the same issue: you must actually evaluate the string as code to execute it. eval is the most obvious solution for that.
But be very careful when you implement this! If you open such a form for the outside world, everybody can execute any script, including ones that might destroy your server or steal your passwords.
The snippet you posted is harmless, but depending on what you do with user-supplied data, it can be used in an code-injection attack. The linked wiki has some examples, here's a couple of them:
$posted = $_POST['user_input'];
eval($posted);//<--- NEVER DO THIS
However, after 10 years, I've never ever even gotten close to the point where I had to even worry about dreaming of having to maybe go down this route.
Another, slightly less unlikely possible vulnerability is impropper escaping when passing user-data to exec:
$cmdArgument = $_POST['flag'];
exec('ls '.$cmdArgument, $return, $status);
Could leave you vulnerable if I passed this as a "flag" value:
-lta && /usr/bin/env php -r 'echo __DIR__;'
And use that input to start messing around with your file-system.
To protect agains this, use the escapeshellarg and escapeshellcmd functions to sanitize the input.
More common, equally dangerous, but easier to overlook, would be this:
$requested = $_GET['page'];
require $requested.'.php';
Instead, if you want to require scripts like this, a safer, and just as easy approach is this:
switch ($_GET['page'])
{
case 'admin':
require 'admin.php';
break;
case 'user':
require 'user.php';
break;
default:
require 'error.php';
break;
}
The PHP exec command can execute code posted to the server. Otherwise PHP code written in a text box will not be interpereted as PHP but just as a normal string.
Related
I am keeping record of every request made to my website. I am very aware of the security measurements that need to be taken before executing any MySQL query that contains data coming from query strings. I clean it as much as possible from injections and so far all tests have been successful using:
htmlspecialchars, strip_tags, mysqli_real_escape_string.
But on the logs of pages visited I find query strings of failed hack attempts that contain a lot of php code:
?1=%40ini_set%28"display_errors"%2C"0"%29%3B%40set_time_limit%280%29%3B%40set_magic_quotes_runtime%280%29%3Becho%20%27->%7C%27%3Bfile_put_contents%28%24_SERVER%5B%27DOCUMENT_ROOT%27%5D.%27/webconfig.txt.php%27%2Cbase64_decode%28%27PD9waHAgZXZhb
In the previous example we can see:
display_errors, set_time_limit, set_magic_quotes_runtime, file_put_contents
Another example:
/?s=/index/%5Cthink%5Capp/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=ctlpy.php&vars[1][]=<?php #assert($_REQUEST["ysy"]);?>ysydjsjxbei37$
This one is worst, there is even some <?php and $_REQUEST["ysy"] stuff in there. Although I am able to sanitize it, strip tags and encode < or > when I decode the string I can see the type of requests that are being sent.
Is there any way to detect a string that contains php code like:
filter_var($var, FILTER_SANITIZE_PHP);
FYI: This is not a real function, I am trying to give an idea of what I am looking for.
or some sort of function:
function findCode($var){
return ($var contains PHP) ? true : false
}
Again, not real
No need to sanitize, that has been taken care of, just to detect PHP code in a string. I need this because I want to detect them and save them in other logs.
NOTE: NEVER EXECUTE OR EVAL CODE COMING FROM QUERY STRINGS
After reading lots of comments #KIKO Software came up with an ingenious idea by using PHP tokenizer, but it ended up being extremely difficult because the string that is to be analyzed needed to have almost prefect syntax or it would fail.
So the best solution that I came up with is a simple function that tries to find commonly used PHP statements, In my case, especially on query strings with code injection. Another advantage of this solution is that we can modify and add to the list as many PHP statements as we want. Keep in mind that making the list bigger will considerably slow down your script. this functions uses strpos instead of preg_match (regex ) as its proven to perform faster.
This will not find 100% PHP code inside a string, but you can customize it to find as much as is required, never include terms that could be used in regular English, like 'echo' or 'if'
function findInStr($string, $findarray){
$found=false;
for($i=0;$i<sizeof($findarray);$i++){
$res=strpos($string,$findarray[$i]);
if($res !== false){
$found=true;
break;
}
}
return $found;
}
Simply use:
$search_line=array(
'file_put_contents',
'<?=',
'<?php',
'?>',
'eval(',
'$_REQUEST',
'$_POST',
'$_GET',
'$_SESSION',
'$_SERVER',
'exec(',
'shell_exec(',
'invokefunction',
'call_user_func_array',
'display_errors',
'ini_set',
'set_time_limit',
'set_magic_quotes_runtime',
'DOCUMENT_ROOT',
'include(',
'include_once(',
'require(',
'require_once(',
'base64_decode',
'file_get_contents',
'sizeof',
'array('
);
if(findInStr("this has some <?php echo 'PHP CODE' ?>",$search_line)){
echo "PHP found";
}
I know that eval is the function in PHP to execute PHP code from an input. Now I want to make a W3Schools like editor. What can I do to protect eval code that I get from POST variable.
$code = eval($_POST["phpusercode"]);
echo $code;
What I want to do is when a user will make a function like this
I want to give user the ability to write his own PHP code on my site without making my website vulnerable to some sort of hacking.
eval evaluates code, so, as #sectus says in comments, execute the code
For example:
eval ("echo 'Hello user'"); //This will execute echo 'Hello user'
So, in your case i think you don't want to execute your user code, so please carify your question and update it.
IMPORTANT:
Use of eval is highly discouraged
NEVER EVER use eval with params by POST/GET without sanitize them
Useful links:
When eval is evil
Avoid SQL injection
I would like to know which of the following solutions is more secure.
if(!ctype_alpha($_GET['a'])){
//another string can be put here if necessary
die('No Hacking!');
}
or
if(!ctype_alpha($_GET['a'])){
//Changed for security in depth, in-case I accidently use $_GET['a'] elsewhere. Designed to simulate header('Location: ./?a=default_value');
$_GET['a'] = 'default_value';
}
something similar to the following happens later in the script:
//make_safe is defined elsewhere, it is security in depth (redundancy) to remove slashes if they get past ctype_alpha using some unknown bug
$var = make_safe($_GET['a']);
require_once("./data/include/$var.php");
In a book I am currently reading, it says that it is best to stop all input not following my rules, instead of correcting. Therefore, my question boils down to does replacing the $_GET['a'] with a default parameter count as stopping the input, or must die() be used?
Die('fu') is a dirty thing.
I prefer your way of sanitizing inputs with default values if needed.
By the way, that's what does major companies (check at google, search something, go to page 2, now change start parameter in the url to something not numeric, you'll be back to page 1).
Plus, when hacking stuff, you'll try to have the application acting in a singular way.
If yours acts always the same, it's very frustrating for hackers, they'll hopefully feel bored quite quickly.
I have a lot of user inputs from $_GET and $_POST... At the moment I always write mysql_real_escape_string($_GET['var'])..
I would like to know whether you could make a function that secures, escapes and cleans the $_GET/$_POST arrays right away, so you won't have to deal with it each time you are working with user inputs and such.
I was thinking of an function, e.g cleanMe($input), and inside it, it should do mysql_real_escape_string, htmlspecialchars, strip_tags, stripslashes (I think that would be all to make it clean & secure) and then return the $input.
So is this possible? Making a function that works for all $_GET and $_POST, so you would do only this:
$_GET = cleanMe($_GET);
$_POST = cleanMe($_POST);
So in your code later, when you work with e.g $_GET['blabla'] or $_POST['haha'] , they are secured, stripped and so on?
Tried myself a little:
function cleanMe($input) {
$input = mysql_real_escape_string($input);
$input = htmlspecialchars($input, ENT_IGNORE, 'utf-8');
$input = strip_tags($input);
$input = stripslashes($input);
return $input;
}
The idea of a generic sanitation function is a broken concept.
There is one right sanitation method for every purpose. Running them all indiscriminately on a string will often break it - escaping a piece of HTML code for a SQL query will break it for use in a web page, and vice versa. Sanitation should be applied right before using the data:
before running a database query. The right sanitation method depends on the library you use; they are listed in How can I prevent SQL injection in PHP?
htmlspecialchars() for safe HTML output
preg_quote() for use in a regular expression
escapeshellarg() / escapeshellcmd() for use in an external command
etc. etc.
Using a "one size fits all" sanitation function is like using five kinds of highly toxic insecticide on a plant that can by definition only contain one kind of bug - only to find out that your plants are infested by a sixth kind, on which none of the insecticides work.
Always use that one right method, ideally straight before passing the data to the function. Never mix methods unless you need to.
There is no point in simply passing the input through all these functions. All these functions have different meanings. Data doesn't get "cleaner" by calling more escape-functions.
If you want to store user input in MySQL you need to use only mysql_real_escape_string. It is then fully escaped to store safely in the database.
EDIT
Also note the problems that arise with using the other functions. If the client sends for instance a username to the server, and the username contains an ampersand (&), you don;t want to have called htmlentities before storing it in the database because then the username in the database will contain &.
You're looking for filter_input_array().
However, I suggest only using that for business-style validation/sanitisation and not SQL input filtering.
For protection against SQL injection, use parametrised queries with mysqli or PDO.
The problem is, something clean or secure for one use, won't be for another : cleaning for part of a path, for part of a mysql query, for html output (as html, or in javascript or in an input's value), for xml may require different things which contradicts.
But, some global things can be done.
Try to use filter_input to get your user's input. And use prepared statements for your SQL queries.
Although, instead of a do-it-all function, you can create some class which manages your inputs. Something like that :
class inputManager{
static function toHTML($field){
$data = filter_input(INPUT_GET, $field, FILTER_SANITIZE_SPECIAL_CHARS);
return $data;
}
static function toSQL($field, $dbType = 'mysql'){
$data = filter_input(INPUT_GET, $field);
if($dbType == 'mysql'){
return mysql_real_escape_string($data);
}
}
}
With this kind of things, if you see any $_POST, $GET, $_REQUEST or $_COOKIE in your code, you know you have to change it. And if one day you have to change how you filter your inputs, just change the class you've made.
May I suggest to install "mod_security" if you're using apache and have full access to server?!
It did solve most of my problems. However don't rely in just one or two solutions, always write secure code ;)
UPDATE
Found this PHP IDS (http://php-ids.org/); seems nice :)
I use this:
function safeClean($n)
{
$n = trim($n);
if(get_magic_quotes_gpc())
{
$n = stripslashes($n);
}
$n = mysql_escape_string($n);
$n = htmlentities($n);
return $n;
}
To prevent any type of MySQL injection or anything like that. Whenever I use it to wrap around $_POST like this:
$username = safeClean($_POST['user']);
$password = md5(safeClean($_POST['password']));
$vpassword = md5(safeClean($_POST['verify']));
$email = safeClean($_POST['email']);
It doesn't even work, but I have attached functions.php and the directory is correct but doesn't work at all because it just shows a blank page... If I remove the safeClean() from each $_POST it works.
How come this isn't working at all?
In my opinion, this sort of general sanitization approach isn't the best way to think about things. For one thing, parameterized queries (probably most convenient using PDO) are a much better way to approach the SQL safety issue. But in general...
I know the developer impulse is to try and reduce the number of things you have to think about. So, naturally, you want to see if you can come up with an all-purpose sanitization function you can just hand all inputs over to and not have to worry any more. Inputs are one arena, though, where if you really want security, you need to think specifically about what each incoming piece of data is supposed to be and where it's going to end up. If you go on auto-pilot here, you will introduce a security issue at some point.
Try using mysql_real_escape_string() rather than mysql_escape_string().
Almost everything in your code is wrong.
get_magic_quotes_gpc is misplaced, htmlentities is misplaced and even term "sanitization" is misused.
As a matter of fact, you shouldn't sanitize anything for the database. But just follow syntax rules.
Take a look at the very similar question, I've explained SQL matters pretty well: In PHP when submitting strings to the database should I take care of illegal characters using htmlspecialchars() or use a regular expression?
And as of the blank page, you have to learn primer of debugging. You have to turn error reporting on to see error messages instead of blank page. To start with it you can refer to this article:
Link to start: http://www.ibm.com/developerworks/library/os-debug/
you can start from adding these lines at the top of your cript
ini_set('display_errors',1);
error_reporting(E_ALL);
and this code to the query execution:
$result = mysql_query($query);
if (!$result) trigger_error(mysql_error());