Is php fileinfo sufficient to prevent upload of malicious files? - php

I have searched around a bit, and have not really found a professional type response to how to have secure fileupload capability. So I wanted to get the opinion of some of the experts on this site. I am currently allowing upload of mp3s and images, and while I am pretty confident in preventing xss and injection attacks on my site, I am not really familiar with fileupload security. I basically just use php fileinfo and check an array of accepted filetypes against the filetype. For images, there is the getimagesize function and some additional checks. As far as storing them, I just have a folder within my directory, because I want the users to be able to use the files. If anyone could give me some tips I would really appreciate it.

I usually invoke ClamAV when accepting files that can be shared. With PHP, this is rather easily accomplished with php-clamav.
One of the last things you want to do is spread malware around the globe :)
If you can, do this in the background after a file is uploaded, but before making it public. A quirk with this class is that it can load the entire ClamAV virus definition database into memory, which will almost certainly stink if PHP is running under Apache conventionally (think on the order of +120 MB of memory per instance).
Using something like beanstalkd to scan uploads then update your DB to make them public is a very good way to work around this.
I mentioned this only because the other answers had not, in no way did I intend this to be a complete solution. See the other answers posted here, this is a step you should be finishing with. Always, always, always sanitize your input, make sure it's of the expected type, etc (did I mention that you should read the other answers too?)

"malicious" files are not the only way to hurt your server (and if your site is down, it hurts your users).
For example, a possibility to hurt a server would be to upload a lot of very small files :
it would not use all the space on the disk,
but could use all available inodes...
...And when there is no free inode left, it's not possible to create any file anymore ; which, obviously, is bad.
After that, there is also the problems like :
copyright
content that is not OK to you or your users (nudity ? )
For that, there's not much you an do with technical solutions -- but an "alert the moderator" feature is oftne helpful ;-)

No, because this could easily be spoofed. There's an article that describes how a server could be attacked by uploading a 1x1 "jpg file" and how to prevent it. Good read.

The first thing to do would be to disable execution of any server side code (e.g. PHP) in that directory via server configuration. Setting up a whitelist for MIME types (or file extensions, since your server uses those to figure out the mime type in the first place) and only allowing media files (not HTML or anything) will protect you from XSS injections. Those combined with a file type check should be quite sufficient - the only thing I can think of that might get through those are things that exploit image/audio decoders, and for spotting those you'd need something close to a virus scanner.

To start with the "file-type" ($_FILES['userfile']['type']) is completely meaningless. This is a variable in the HTTP post request that can be ANY VALUE the attacker wants. Remove this check ASAP.
getimagesize() Is an excellent way to verify that an image is real. Sounds files can be a bit more tricky, you could call file /tmp/temp_uploaded_file on the commandline.
By far the most important part of an uploaded file is the file's extension. If the file is a .php, then you just got hacked. It gets worse, Apache can be configured to ignore the first file extension if it doesn't recognize it, and then use the next extension, so this file would be executed a normal .php file: backdoor.php.junk. By default this should be disabled, but it was enabled by default a few years ago.
You MUST MUST MUST use a file extension White List. So you want to force using files like: jpg,jpeg,gif,png,mp3 and reject it otherwise.

if exiv2 can't remove the metadata its probably malicious or corrupted in some way atleast. following required exiv2 be installed on your unix system. Unfortunately, this might be dangerous if the file contains malicious shell code. not sure how sturdy exiv2 is against shell exploits, so use with caution. i haven't used it, but i've thought about using it.
function isFileMalicious($file)
{
try{
$out = [];
#exec('exiv2 rm '.escapeshellarg($file).' 2>&1',$out);
if(!empty($out)){
return false;
}
}
catch(exception $e)
{
return false;
}
return true;
}

Related

PHP file changes its extension to ".suspeced"

I have two php files on server that keep changing their extension over night. For example, file.php changes to file.php.suspected
What these two files have in common is mail() function. For example,
$mail_success = mail($_POST["email_to"], stripslashes($_POST["email_subject"]), stripslashes($_POST["email_body"]), $_app["email_headers"]);
There is nothing else that these files have in common. So, something on the server goes through the files over night and apparently dislikes these files with mail() function, changing their extension or rather adding .suspected extension to .php extension.
After a couple minutes of googling, it looks like a PHP file changing filetypes is the sign of a hacked server. Here is a post on the CPanel forums, where a guy has a similar issue and the other commenters decide that his server had been hacked.
I personally can't give you any advice to secure your site, but perhaps you should head over to SysAdmin or another community and look into making your server more secure.
I'm about 3 years late, but...
I found a piece of WordPress malware that does exactly what you describe.
It's something of a cleaner - it has 56 different functions to decide is a given ".php" file name constitutes code that needs to be rendered inoperable.
One of those indicators is a substring of what you say the two renamed files have in common:
function ryypkex($content)
{
if (strpos($content, " = mail(\$_POST[") !== FALSE) {
return TRUE;
}
If a given filename's contents match a condition, that filename gets its ".php" suffix changed to ".php.suspect".
The two instances of this cleaner that my honey pot caught use the "RC" action of the WSO web shell to immediately execute the cleaner. No on-disk cleaner code will exist. The implication is that you probably need to look for a WSO web shell somewhere in your web apps' code.

Virus file systems.php on my server?

I found a file systems.php on my webserver that neither I - as user - placed there, nor my webserver provider has placed in there. I viewed the file, it only contains one preg_replace() statement with an extremly long $replacement part, which seems to be somehow encoded.
preg_replace("/.*/e","\x28\x65\...\x29\x29\x3B",".");
If I interpret this statement correctly, it would mean that basically everything shall be replaced be the $replacement part (which might be encrypted/encoded virus injection stuff).
I have uploaded the whole code as pastebin here. Someone has an idea in what way the code is encrypted/how it can be decrypted in order to assess the grade of compromisation of my server?
Update
This might be the attack vector:
So after some digging, we found that this script was planted using a vulnerability in the Uploadify jQuery library. The library's existence was discovered by the attacker through google. source
Unhexxing the shellcode shows it's executing eval(gzinflate(base64_decode(huge string));
I changed this eval to an echo and the full output is on pastebin here:
http://pastebin.com/t1iZ5LQ8
I haven't looked much further into this but it certainly seems dodgy. Just thought I'd do some of the legwork for anyone interested in looking at it further
EDIT
Little bit more detailed look, it appears to allow an attacker to upload files to your server, and take a dump of any databases on the box
It's look like a Shellcode, which can be disastrous for your server, shellcode executed by the CPU can give access to a shell or shuch of things.
For more informations about shellcodes here's a good article :
http://www.vividmachines.com/shellcode/shellcode.html
This upload may hide a possible exploit on your server which grant access to upload or write data into, try to check your logs to identify the problem.

Can input written to a file be maliciously tampered?

Uber simple example to illustrate the point:
$message = $_POST['message'];
$fp = fopen("log.txt", "a");
fwrite($fp, $message);
fclose($fp);
Should I be sanitizing user input for the $_POST['message'] variable?
I understand prepared statements (for database sanitization) and htmlentities (if I were outputting the POST message back to the screen at some time) but in this case, the input is simply sitting in a log file that will be read by a small PHP script (via fopen())
Is the answer dependent on how it will be read? For example if I do open the log file via fopen() it should be htmlentities, and if I plan to download the log file and read it with Excel (for filtering purposes), there is nothing to be done?
Your code is basically innocent. The only "obvious" attack would be to repeatedly upload data to your server, eventually exhausting your disk space.
"sanitizing" is something that's situational. It's not something you can just sprinkle on code to make it better, like you can with salt on food. Perhaps you'll sanitize the $_POST data to prevent SQL injection attacks, but then use the data in an HTML context - now you're vulnerable to XSS attacks. Perhaps it's an image upload, and you do basic MIME-type determination to make sure it IS an image. That's all fine and dandy, but then someone uploads kiddy porn, which will pass the "is it an image" test, and now you've got a much bigger problem.
Since you're accepting user data and writing it out to a file, there is nothing that can be done with this code (except the disk space problem) to abuse your system. You cannot embed some data sequence into the data that'd cause PHP, or the underlying OS, to suddenly stop writing that data out to disk and start executing it. It doesn't matter WHAT kind if data is being uploaded, because it's never being used in a context where it could be used to affect the script's execution. You're simply sucking in some data from the webserver, and spitting it out to disk. You're not allowing the user to influence which file is written to (unless your users have shell-level access to the server and could, say, create a symlink called 'log.txt' pointing at some OTHER more critical file).
The real problem comes AFTERWARD... what do you do with this file after it's been written? If your later code does something silly like
include('log.txt');
then now you DO have a problem - you've now taken this "innocent" data sitting in a file on the disk and turned it into potentially executable code. All it takes is a simple <?php exec('rm -rf /') ?> anywhere in that file to trash your server.
As well, consider something like the inherently idiotic "security" measure that was PHP's magic_quotes. The PHP developers (WRONGLY and STUPIDLY) assumed that ANY data submitted from the outside world would only EVER be used in an SQL context, and did SQL escaping on ALL data, regardless of its ultimate purpose. And to make it worse, they simply assumed that all databases use backslashes for their escape sequence. That's all fine and dandy if you never use anything but MySQL, but what if you're on, say, SQL Server? Now you have to translate the PHP-provided Miles O\'Brien to Miles O''Brien, essentially having to UNDO what PHP did for you automatically.
TL;DR: Don't use shotgun 'sanitization' methods, they're almost always useless/pointless and just involve more work before AND after. Just use context-specific methods at the time you're using the data.
You should sanitize user input, but how is entirely dependent on what the input is for. "Sanitizing" refers to the idea of making sure input is safe or sane for a particular use. The term cannot be more specific until you settle on use cases.
You don't need to worry about the PHP reading/writing functions like fopen(). Be concerned with steps that actually parse or analyze the input. Some possible examples:
If a file will be displayed in a basic log reader, you might need to make sure that each input is limited to a certain length and doesn't contain line breaks or your chosen field delimiter, and the beginning of each line is a valid time stamp.
If a file will be displayed in a web browser, you might need to make sure inputs do not include scripts or links to other resources (like an IMG tag).
Excel files would have similar concerns regarding line length, time stamps, and delimiters. You don't have to worry about someone including executable code as long as Excel will be parsing the file as text. (Also, modern Excel versions give you warnings about included macros before running them.)
The general rule is to validate input and sanitize output.
If it is possible to validate your input in any way, then you should. If not, then you should sanitize it when output to make sure it is safe for the context it is used.
e.g. if you know that each message should be less than 100 characters regardless of how it is used, the script that reads the POST data could validate and reject any request whose POST data contains input that is 100 characters or over.
Validation is an "all or nothing" approach that rejects anything that doesn't follow certain rules regardless of output context, whereas sanitisation is the process of "making something safe" depending on the context. I think it's important to make that distinction.
In your case the sample code you provided does not output (except for the puposes of processing by another script). It is more of a storage operation than an output operation in that the message could be written to a database just as easily as the file system. The main attack surface that would need locking down in this case appears to be file permissions and making sure that nothing can read or write to the file other than the scripts you intend to do this and under the correct context. For example, I realise your example was simplified, but in that specific case you should make sure that the file is written to a location above your web root, or to a location that has folder permissions set appropriately. Otherwise, you may have inadvertantly given access for anyone on the web to read http://www.example.com/log.txt and if they can write to it too it may be possible to leverage some sort of XSS attack if they can trick a browser into reading the file as HTML. Old versions of Internet Explorer try and detect the MIME type rather than rely on the server header value of text/plain (see here also). These vulnerabilities may be slightly off topic though, and I just mention them to be thorough and as an example of making sure the files themselves are locked down appropriately.
Back to your question: In your case your validation should take place by the script that processes log.txt. This should validate the file. Note that it is validating the file here, not the raw message. The file should be validated using its own rules to make sure the data is as expected. If the script directly outputs anything, this is where the sanitisation should take place to match the context of the output. So to summarise the process of validation and sanitisation for your application would be:
Create log: Web browser ---POST---> get_message.php ---> validate that message is valid ---fwrite()--> log.txt
Process log: log.txt ---fopen()---> process.php ---> validate that file is valid ---> anything output? then sanitise at this stage.
The above assumes that the correct authorisation is made before processing takes place by the scripts (i.e. that the current user has permissions in your application to logmessages or process logs.)
I would sanitize it. When it comes to logs, just make sure you put it into reserved space - for instance, if the log is one record per line, strip the new lines and other stuff from user's input so he cannot fool you.
Take a look at Attack Named Log Injection
Also be very careful when it comes to displaying the log file. Make sure no output can harm your reader.
You append to a file in the current directory - this seems to be downloadable via browser, so you're creating a security hole. Place the file outside of the document root (best), or protect it via .htaccess.
You should sanitize all user input. Always. What this means depends on how you use this data. You seem to write to a text logfile, so you would want to let only printable and whitespace-class chars through. Sanitize defensively: do NOT specify bad charcodes and let everything else through, but define a list/classes of "good" chars and just let these good chars through.
Depending on your use case, you may want to flock() the log file, to prevent multiple parallel requests from mixing up in your file:
$logtext = sanitizeLog($_POST[Message']);
$fd = fopen( "/path/to/log.txt", "a");
if(flock($fd, LOCK_EX)) {
fseek($fd, 0, SEEK_END);
fwrite($fd, $logtext);
flock($fd, LOCK_UN);
}
fclose($fd);
I've omitted checks for fopen() results...
Regarding PHP's fwrite() function, there's no need to sanitize: fwrite() just writes that to a file that it gets passed along.
Regarding the log-file, you might wish to sanitize. Here is why:
Suppose an attacker post a multiple line value as message. If your log was before the post
line 1
line 2
then it is after the post
line 1
line 2
line 3
remainder of line 3
very remainder of line 3
because attacker posted this:
line 3\nremainder of line 3\nvery remainder of line 3
Note: One time posted vs. 3 lines added.
That said: How posted data needs to be sanitized, fully depends on your application.

Simplify PHP files - PHP compression

I know JavaScript or CSS for expample can be "compressed", "simplified" in order to be loaded faster. After simplifying they are difficult to be read by humans... and this is exactly what I need.
Is there anyway to make it automatically? Rename all variables to short random strings and make it all hypercompressed. I don't think it is a fool thing because I have seen this lot of times in javascript. The idea is to conserve the original source and upload the minified one.
There is no need for doing this. The Server reads the file, and the file never gets transferred to the user.
Therefore, compression is useless because there is no bandwidth saved.
CSS & JavaScript does however get transfered to the user, and therefore they can see it. A user can never see PHP unless you've done something wrong on your server. But then you need to worry about totally different things than compression.
If you want to compress it, this is basically useless, since you have it on the server and only the output gets transferred to the client.
If you want to make the code more difficult to read for other human beings, you're looking for something which is called an obfuscator.
There are a few php obfuscator engines out there, p.e.
http://www.codeeclipse.com/
http://www.truebug.com/
http://www.raizlabs.com/softwarephpobfuscator/

PHP: read html file for offline reading

I am using file_get_contents() function to read a URL eg:
$html = file_get_contents('www.mydomain.com');
Now how do I modify above code or what should I do to read pages offline once saved in my db. The problem is that saved pages have images and css pointing to fetched url which means internet should be on to read them.
How can I make it have images as well as CSS also saved. I had asked similar question before regarding mht/mhtml format.
Is that what you're looking for?
http://www.phpclasses.org/package/1766-PHP-Build-MHT-MIME-archives-from-lists-of-files.html
http://www.wynia.org/wordpress/2006/12/making-mht-single-page-archive-files-with-php
Please note that MHT is MS-specific format so above example uses Windows libraries.
One way to do this that is potentially dangerous (you'll have to sanitize inputs, if any), but will certainly work if your server is a well-equipped Linux server, is to invoke the wget program with the right arguments using PHP's system function, like so:
system("wget --recursive --no-clobber --page-requisites \
--html-extension --convert-links --no-parent $url");
Once the files are downloaded, you can put them in the database, though I have to ask: what benefits does a database have over a file system for the purpose of storing files? Of course, I don't know your particular circumstances; I'm just raising the question in case you're making things more complicated than they need to be.

Categories