5

I know I can use the php.ini open_basedir directive to limit the directory trees where files can be opened by PHP.

But in a directory structure such as this:

├── application
│   ├── index.php
│   └── www
├── logs
└── uploads
    └── malicious.php.jpg

Is there any way to prevent malicious.php.jpg from being evaluated as PHP if it were specified in an include(), without preventing PHP from reading/writing uploads to/from that directory?

Edit: I should probably specify that I'm interested in a configuration- or permissions-based solution.

3

Depending on your setup, you may be able to use Mandatory Access Control to get something close to what you want. For example, consider a system running linux with apparmor. By using apparmor you can limit which scripts are allowed to access the uploads directory. This isn't a perfect solution since a couple scripts will still be able to "include" the files, but you can limit the number of scripts that can.

For Example, you could allow upload.php to access the uploads directory, but deny index.php access to that directory even though they are running as the same user.

I assume you can do similar things with other MAC systems like SELinux.

3

This cannot be done without modifying the default behaviour of the include() function family by editing PHP source code and compiling your own binaries. But, to be honest, this is a little bit pointless. In order for malicious.php.jpg to be included, you need a file inclusion vulnerability in your code, something like include($_GET['file']).

The next best thing is to have all of your includes done using global inclusion function that runs certain input validations. That function can control what directories can be accessed.

2
  • Indeed, I was looking for a configuration- or permissions-based approach, for additional protection against bad/exploited PHP code. Oct 31 '13 at 18:27
  • In addition, be 100% sure the PHP installation on every server you're using is fully up to date. Any version 5.3.4 and above makes it impossible to truncate a filename with a null byte.
    – Anorov
    Nov 1 '13 at 11:30
1

No, not really. The only way to do so is to limit the files that can be read by PHP at the OS level. Even if you manged to somehow restrict which paths could be read using include() or require(), you're still not preventing execution: the script could just as easily use normal fopen() functionality to read the file, and then just eval() it, with exactly the same effect.

But if the code has the freedom to do all that, then file inclusion is the least of your concerns. In fact, inclusion of malicious files shouldn't even be possible if you write your code correctly. At no point should you ever (no really, ever) include or execute a file if the name originated from user input. If you're doing that, I can categorically state that you're doing it wrong.

But if you want to limit the range of includable / executable / readable files, then chroot is where it's at. A bit fiddly to set up, but offers the required level of protection.

1
  • Strange to assume that I'd be writing all of the code on the server; and a chroot wouldn't change this scenario, unfortunately, because PHP still needs to be able to read/write the uploads directory. Nov 1 '13 at 14:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.