CheckMarx - File Manipulation Vulnerability - php - php

my code essentially takes a file uploaded to the server using a front end, by referring to the the $_FILES variable in php, and moves it to a new file on the server . Following snippet summarizes the code,
$acutal_file = $_FILES['file_uploaded']['tmp_name'];
move_uploaded_file($actual_file, $target_file);
Here, I get the target_file variable from the database.
So, when I perform the code scan it creates a high vulnerability for this snippet with error type "File Manipulation", highlights the $_FILES variable above and gives the message "The input obtained in the file is used to determine the location of the file to be written into, potentially allowing an attacker to alter or corrupt the contents of that file, or create a new file altogether."
Does anyone know how to avoid the error ?
Thanks in advance.

I suggest you to read and apply all the rules defined in OWASP Cheat Sheet about File upload. this is the best rules to have

Some ways to mitigate Path Transversal and file manipulation are:
Validating the user’s input. Accept only valid values (whitelist).
Remove “..\” and “../” from any input that’s used in a file context.
Use indexes instead of actual portions of file names while using language files. (i.e – value 5 from the user submission = Indian, rather than expecting the user to return “Indian”).
Implement strict code access policies to restrict where files can be saved to.
Ensure the user cannot supply any part of the path to the file read or written to.
This information was found at https://www.checkmarx.com/knowledge/knowledgebase/path-traversal. If you are already using Checkmarx software, it may give you a lot of false positives, but don't always assume that. I hope this helped. If you have any other questions let me know.

Related

Do I need to filter the $_FILES['file'] before dealing with it? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
To protect the websites we're programming from attacks such as SQL-Injection or XSS we need to filter users' inputs before storing or displaying it.
In PHP, we use htmlspecialchars and addslashes functions to the inputs to prevent XSS and SQL-Injection attacks. So, what about the files ?
I used to protect web-apps by checking the files type and it's extension to know if those were in the whitelist or not. But I don't use htmlspecialchars and addslashes functions because I didn't see someone using this approach.
For example, if I want to get the file name I use $_FILES['file']['tmp_name'] then I store it directly to the database.
Is this wrong or it cannot be injected with codes, commands ... etc.
Do I need to filter the $_FILES['file'] before dealing with it?
Short answer: NO. It's a bunch of string values, nothing more.
Long Answer:
I used to protect web-apps by checking the files type and it's extension to know if those were in the whitelist or not.
This is a good approach, if applied and carried out correctly.
the $_FILES array is simply a carrier. It can't itself be abused, but you have to trust what it carries - ie trusting the file that is being passed to/by the server.
While I write this answer; below; it seems the OP is confused about what they're actually protecting against and why:
The OP states as "best practise" (which it is absolutely not):
If you want to use $_FILES['file']['tmp_name'] to be stored into your database or to display in your UI, you should use addslashes or PDO prepare statement to be protected against SQL-Injection attacks.
This is a misunderstanding of how the $_FILES array is populated. The $_FILES['file']['tmp_name'] value is set by the server, not by the user or the client.
The user given values are:
$_FILES['file']['name']
$_FILES['file']['type']
$_FILES['file']['size']
These are the string values that would need to be vetted. As long as you do not trust these string values, you have nothing to worry about.
Storing files inside your database is not usually a good idea and has its own pitfalls, dhnwebpro has their own answer on this question, regarding database safety.
$_FILES['file']['tmp_name'] is the server location of the file in temporary storage space.
The PHP Manual clearly states:
Files will, by default be stored in the server's default temporary directory, unless another location has been given with the upload_tmp_dir directive in php.ini. The server's default directory can be changed by setting the environment variable TMPDIR in the environment in which PHP runs.
The file will be deleted from the temporary directory at the end of the request if it has not been moved away or renamed.
If you think that your $_FILES['file']['tmp_name'] value is being abused then this is a sign of server compromise and you've got a whole lorry load of trouble on your plate, well beyond a nefarious file upload.
So, how to vet the file that is being carried?
There are numerous types of file attacks and this topic is far beyond the scope that you are asking. For example; a genuine JPEG image can contain XSS scripting in the JPEG Metadata, but this XSS is triggered when the JPEG is loaded and viewed, but for all intents and purposes the JPEG file is not a "bad file" or is not a XSS file, to an outside observer who doesn't specifically check for this vulnerability.
So, do you block this file.jpg or do you block all Jpeg files? It's a tough call to make but in PHP there are some very good work arounds (which are also I believe out of scope for this question). In short; your question could do with some editing and clarity as to what exactly you're trying to protect against and how far you're willing to go to reach that level of protection.
I can give you a rough catch-all guide to preventing certain MIME file-types from being accepted onto your server. This looks and feels like what you want, something to stop sneaky MP4 videos being uploaded as document files (or vice versa).
1:
Ignore the filename ($_FILES['file']['name']). NEVER trust user data.
Edit: As pointed out by meagar, you may need to retain the original filename, in which case you should check it with a REGEX or similar to remove unwanted characters...
2:
Ignore the declared filetype ($_FILES['file']['type']). Any filename given MIME type (such as .pdf) should simply be ignored. NEVER trust user data.
3:
Use the PHP Finfo function set as a preliminary indicator. It is not perfect but will catch most things.
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
$mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']);
$whitelist = ['text/html','image/gif','application/vnd.ms-excel'];
finfo_close($finfo);
if(in_array($mimeType,$whitelist)){
// File type is acceptable.
}
4: Images:
If you are checking an uploaded image the best approach is to check the finfo filetype as per 3 and then have PHP load the image into a blank canvas and resave the image, thereby stripping out all the excess metadata and other potentially undesirable data that is not image-data.
Like this method: Remove exif data from jpg using php.
5:
It is also advisable always to give your uploaded files randomised names, never using the $_FILES['file']['name'] value.
6:
Depending on the sort of threat you're trying to avoid and/or neutralise, you can open the uploaded file and read the first few bytes of the file and compare it with confirmed bytes from whitelisted files of that type. This is quite nuanced and again beyond the scope of this answer, which is quite long enough.
There is a function is_uploaded_file to determine that the file is indeed an uploaded file and not some sort of file path manipulation on the user's part. As far as I know, there is no way that is_uploaded_file($_FILES['file']['tmp_name']) will return false. You should also check that the filesize($_FILES['file']['tmp_name']) is less than the size of the column you are inserting into.
As for "storing it directly to the database" you still need practice good SQL injection prevention on the file contents. Additionally, it is usually difficult to scale a solution that stores files in a database, but that is a separate issue that you have presumably considered already.
If you're using PDO or MySQLi you should be able to place the file in a prepared statement which should protect you from SQL injection attacks. I pasted a method from https://www.mysqltutorial.org/php-mysql-blob/ which has some good information on storing files in a MySQL database.
/**
* insert blob into the files table
* #param string $filePath
* #param string $mime mimetype
* #return bool
*/
public function insertBlob($filePath, $mime) {
$blob = fopen($filePath, 'rb');
$sql = "INSERT INTO files(mime,data) VALUES(:mime,:data)";
$stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':mime', $mime);
$stmt->bindParam(':data', $blob, PDO::PARAM_LOB);
return $stmt->execute();
}
Or you could store the file on the filesystem and just include a reference to the file for when you need to serve it up. This method is quicker, but doesn't have the convenience of keeping all your data in one place.
The details about the elements of the $_FILES array are kind of buried in the manual, but they can be found at the end of example 1 here:
https://www.php.net/manual/en/features.file-upload.post-method.php
The values on all elements of the $_FILES array should be regarded as user input. I would recommend ignoring those values. However, if you wish to write them in to a database and/or display them later in your UI, you definitely need to protect yourself from SQL injection and XSS attacks. So using prepared statements and htmlspecialchars wouldn't hurt, in that case.

How safe is file_get_contents() while retrieving a local file path, not user inputted

I have user inputted HTML content stored on files without extension, on system-named folders and not user named files.
> file_put_contents($DBStoredFolder.'/'.$DBStoredFilename, $UserInputHtml);
How safe is to retrieve the content and print it?
> $content = file_get_contents($DBStoredFolder.'/'.$DBStoredFilename);
> echo '<html><body>'.$content.'</body></html>';
Can a file without extension only accessed via file_get_contents on a fixed path and then echoed, run PHP code?
I know that the returning html needs to be secured when it runs on the browser but that is other thing.
There's no way to answer that question generally.
If you're completely in control of the filename (i.e., there's no possibility of user input interfering with the filename), then it's safe to open the file at that path.
If you're completely in control of the contents of the file (i.e., it couldn't possibly be a user-uploaded or user-edited file) then it's safe to display it.
If you're completely in control of the formatting in the file and can be sure that it's already HTML, then there's no need to escape or sanitize the contents before displaying.
Almost always, though, one or more of those assumptions isn't really valid. How you cope with the uncertainty depends entirely on the specifics of the situation. In general, sanitize the filename, sanitize the file contents, sanitize the display, sanitize everything.
Personally, I'd rather be overly cautious with a filename I do control than risk introducing user input without realizing it.

How to go about editing a php file to change values?

I would like to write a script to edit a css file or maybe even a slideshow for instance where a form will update the variables in my php document. I've been doing some reading and some say editing a php file directly is bad news due to security issues and to use xml.
I am not connecting to databases or anything like that. So my question is is this correct to write script to directly write/update a php file to changes its variables?
Thank you.
if you can correctly sanitize your input then it is a usable aproach. The worst that can happen is code injection. So do check for variable length and content very strictly. It is like eval(); only worse, as everyone else will run it to. If there are only variables to change you might consider using an .ini file for configuration. And Use the data in that from your PHP script
In general you should not run PHP scripts as a user with permissions to write to its own executable code; it means any file write vulnerability immediately escalates to a code execution vulnerability.
Writing dynamic data into a PHP file is risky. You would need to know how to serialise/escape any value to a PHP literal exactly; any error could result in code execution. Watertight code generation is in general a tricky thing.
There is almost certainly a better way to approach whatever it is you are doing. Putting data in a static store such as a config file or database, and reading the data at run-time, would seem to be the place to start.

How to check if uploaded file (or text via text box) contains PHP code?

I am unable to find a proper answer to this on stackoverflow. But perhaps it is just me being silly.
I have a user form where the user can upload a text file. We are doing the sensible things like saving outside htdocs and renaming the file - but how can I check if the uploaded file contains some, potentially harmful, PHP snippets? Also there is a text box which is saved as a text file and we'd like to check if the user submitted php code in that too.
Is it as silly as checking for "<?php" ? Can this be re-written in some form of byte form which would render this check useless.
Note that the file may contain valid "<" and ">" characters as part of the input - and I do not want to escape these because then my data crunching application will not work on this sanitized form.
There shouldn't be any need for you to do this: you just have to take care the input is never used in a context where PHP code could be executed.
If you're receiving form data, make sure you're not eval()ing the content at some point. Other than that, you should be okay.
If you're receiving files, make sure you're storing them in a location where they can't be executed by the PHP interpreter. See e.g. Prevent execution of uploaded php files? also make sure you are never include()ing user-uploaded files - if they're files you need to display at some point, use file_get_contents() (and don't forget sanitizing them for HTML output).
Replace the point with underscore between file name and the extension to be sure.

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.

Categories