FPD is one of approximately 17576 three-letter abbreviations used on the Internet, and one of the few where the letter F doesn't stand for, um, let's say friend. The meaning of the acronym that I'd like to talk about is important for web application security: FPD means Full Path Disclosure.
And the path means the path to the file, to the currently running script, not the path home from your favorite bar.
If you see something like this on your own website, then your website cannot withstand a Full Path Disclosure attack and will reveal the full path. And it certainly shouldn't. I can see your palm coming up to your face, and how you tell yourself that you know the path to your files, and how you shake your head in disbelief. But the information displayed is important not only for you, but also for the bad guys who want to attack your website in some way.
Besides the full path to the search.php
script, there are a few other important pieces of information that can be learned from the displayed error message:
strtolower()
expects a string as the first parameter (just in case you forgot)Just for the record, even the full path itself is important, because on some servers the paths don't match the domain names and the files are stored in directories with generated names (for example /www/sites/8/site13148/public_html
is the path to the files of adriadatabanka.com) and so it may happen that even you don't know where your files actually are. Full Path Disclosure will help you find them (which is probably why even half a year after reporting this vulnerability is not patched). And it will help not only you find them, but anyone who wants to find them, including potential bad guys.
Sometimes the information displayed can also show the versions of the tools used and the stack trace, i.e. a complete list of files and functions that were called before the error occurred (for example, Chris Shiflett, author of Essential PHP Security, on his Not Found page) or what database server and PHP extension is being used for access and how queries are sanitized, that's when you see the message similar to:
mysql_real_escape_string() expects parameter 1 to be string, array given
In short, a Full Path Disclosure attack can give away a lot of info that can be used to plan and execute other attacks with much larger and worse impact, such as SQLIA (SQL Injection Attack, that's when someone steals usernames and passwords from your database) or LFI (Local File Inclusion, that's when someone downloads a file that shouldn't be downloaded, such as a configuration file with database server access credentials). Maybe this attack could be better and more generally called FPIADHYB (Full Path, Information and Architecture Disclosure, Hell Yeah, Baby). I have learned to generalize and see the world in black and white when it comes to security, which is why I always say that a Full Path Disclosure attack is just as serious as the mentioned SQLIA or LFI.
Full Path Disclosure is a fairly common attack and is often successful (and sometimes affects the blacksmith and his mare) or a website that is written in some known framework), it is therefore good to know how such an attack can be carried out in order to be able to effectively defend against it. If you try to make an FPD attack on your own website (we don't attack other poeple's websites, we know?), you should know there's no limit to your imagination, the basic thing is to trigger some PHP error message, which by default also includes the full path to the file where the error occurred. Here are some basic tricks to help you experiment.
If you add an empty square brackets after the parameter name, PHP will change the input parameter type to array":https://www.php.net/faq.html#…. However, the script doesn't count on this trick and passes this variable to functions that work only with strings (for example strtolower()' or `preg_match()') and reports an error when an array is passed to them. For example `search.php?q[]=…
, the resulting error is captured in the opening image. In forms submitted by the POST method, then just use your browser's developer tools to change the name of the INPUT element by adding square brackets for example to name="search[]"
.
The session identifier has certain limitations regarding the allowed characters and the length of the id. An illegal character is, for example, a space, and an illegal number of characters is, for example, zero, i.e. an empty string. If we use an identifier with an illegal character or an illegal length, session_start()
will report an error. The session identifier can be changed, for example, directly in your browser (look for a cookie called PHPSESSID
or something similar), or you can change it using JavaScript by inserting the following code into the address bar of your browser when your website is loaded and then by reloading the page.
javascript:void(document.cookie="PHPSESSID=");
If the website passes the session identifier in the URL (which no modern website should do nowadays), then nothing is easier than changing the given parameter in the URL.
Try to directly call files in the browser that you only include or require into other files. You may see a message similar to this:
Fatal error: Call to undefined function login() in /stor1/vemex/html/form.php on line 7
Yes, even in this case your website just failed to withstand the FPD attack.
If the script requires any parameters, try calling it without these parameters. You might be surprised.
Check that all your publicly available scripts can read files, which are needed to execute them successfully.
If any of your scripts process HTML or XML, try sending it well-deformed data, or something that doesn't look like HTML or XML, it might not like it.
If there is a script on the site that redirects, try using some special tool (Firebug, Fiddler, curl) to look at its output when you try the tricks described above. It's possible that the script will give away the full path and other information, but then redirect somewhere else, so you won't see the expected error message in a conventional browser.
A lot of scripts like system check give away a lot too, and they may not even report any errors. This group also includes all those /info.php
, /phpinfo.php
, /pi.php
, etc. scripts, i.e. the output from the phpinfo()
function. That function is also dangerous because its output can be used to obtain session id even if the cookie with the id has the HttpOnly
attribute.
You can try as hard as you like, treat different states and variable types and generally do and write everything defensively, but dear PHP will always surprise you with something. So the only option is to turn off error messages using the display_errors
directive. Preferably in the server configuration, if you do it somewhere in the script, it may be too late. In the .htaccess
file you can do it like this:
php_flag display_errors off
So errors won't be displayed, but it's definitely good to know about them. We should therefore store them somewhere, preferably in a log. This is done with the log_errors
directive, in the .htaccess
file as follows:
php_flag log_errors on
The directive error_log
determines which log the error messages will be saved to. Try looking, for example, in the server error log.
Definitely never disable the error messages by disabling their generation, for example by using error_reporting(0);
, this will also disable their saving to the log file. Where there is no error message, there is nothing to save.
It should be noted that FPIADHYB is not just a PHP issue, but applies to basically all technologies that somehow print error messages containing useful information.
TL;DR: set display_errors = off
Come chat about FPIADHYB, SQLIA, LFI and BBQ at my PHP Application Security Training (next date: termín zatím nevypsán) or, if you are good at deviating from the original topic, even to any other training.
Disclaimer: I believe the sites linked above know about the issues, but they just don't care. Otherwise, I can't explain why they haven't been resolved even after several months of reporting. If they don't know about the problems, let them know, dear readers, and send them a link to this article. Thank you.
I wrote the text back in 2012 for Borek Bernard's DevBlog (in Czech), and in 2024 I just added links to pages that no longer exist, which were saved by the Internet Archive not long after the original publication, corrected typos and put them on my website in the original wording, translated to English.