This is a tutorial covering some basic methods of triggering path disclosure – while FPD alone is not necessarily a security risk, it can be used in combination with other bugs to create a real issue. This is part 1 of a two-part series. Within this part I’ll be explaining some generic methods that can be used to determine the full path, as well as why knowing the full path can sometimes be important. In the second part, I’m going to be focusing more on triggering stack traces which reveal information far more than the path alone. Additionally, in Part 2 I will be including more methods of triggering FPD that I haven’t listed in the first part of this guide.
Full path disclosure is a software bug that results in the full path to the webroot directory of the server being exposed. While this alone is not a vulnerability, it can be useful for an attacker as it can allow them to exploit other unrelated (or semi-related) vulnerabilities with ease. For vulnerabilities such as Local File Inclusion and SQL Injection. We will explain the importance of Full Path Disclosure in regards to these vulnerabilities and others, but first we will be covering various methods of triggering Full Path Disclosure.
There’s a good chance you may have already seen path disclosure errors without doing anything to trigger them. They look something like this:
Fatal error: require() [function.require]: Failed opening required 'example.php' (include_path='.:/usr/local/php5/lib/php') in /home/custom/path/to/my/website/index.php on line 17
Although Full Path Disclosure tends to be most common within PHP, it is found within a multitude of languages. It can be circumvented within PHP by adding the following line to your scripts:
Although Full Path Disclosure tends to be most common within PHP, it is found within a multitude of languages. It can be circumvented within PHP by adding the following line to your scripts:
Or, alternatively (and more effectively), you can modify your php.ini file to disable error reporting site-wide.
Sometimes, Path Disclosure will result in more than just the path alone being disclosed. For example, the path could contain the username of the site operator, meaning an attacker would then have an SSH username to attempt to bruteforce or gain access to by other means. Sometimes attempts at Path Disclosure result in an entire stack trace being displayed and can reveal version information for various kinds of software, among other things. Sometimes the techniques listed here won’t even result in path disclosure taking place but can still leak sensitive info regardless! Below is an example of this. Using a generic method to trigger a Path Disclosure in MyBB Forums does not reveal the path, but instead it reveals other useful information such as the specific version of PHP running, alongside info pertaining to the Operating System:
The example above is just one demonstration as to how information other than the full path can be disclosed, via methods either identical to those used within FPD, or methods that are very similar. This guide will be focusing solely on FPD, but in Part 2 you can expect a much bigger focus on triggering stack traces, in addition to learning which information in those outputted stack traces could prove useful. Some stack traces can even leak mysql credentials, among other things!
Methods of triggering FPD:
- Arrray Insertion:
By inserting an array directly after the name of the parameter, you can sometimes trigger FPD (within PHP specifically), like so:
Although a blank array will work fine, it doesn’t matter if you have numbers or text between the braces:
If successful, then it should cause the page to spit out an error message containing the full path to the file you tested. If nothing happens, then you can assume it was unsuccessful or that error reporting has been disabled.
Pro tip: Sometimes (stupidly), developers will strip “” from a URL in order to prevent FPD, as opposed to just disabling error reporting within production environments to mitigate this issue entirely. This can sometimes be circumvented just by adding data into the array e.g. [lolol] or by doubling up on the array e.g. [lol[lol]lol] (assuming they’re stripping the array and text between it – [lol] would be stripped from the middle, leaving the end result as [lol] – similar mess-ups to that of unsafe string replacement.
Pro tip #2: sometimes it will seem like this isn’t working, whereas a simple urlencoding of the array can mean the difference between no output whatsoever, and Full Path Disclosure taking place. Example:
There are various ways of manipulating session cookies in order to trigger path disclosure errors – the most common method of this is by nulling your session cookie (making it blank) then reloading the page. In order to do that, simply type the following into your address bar:
Replace ‘cookieNAME’ with the names of cookies relevant to the site where you’re attempting to trigger Path Disclosure. PHPSESSID is a common cookie name so we will be using that for the purpose of these examples:
Once you’ve typed that into your address bar and hit enter, you must refresh afterwards. If you don’t then there’s no chance you’ll see the FPD. This applies to all of the cookie-based methods listed here. If your attempt was successful, you should see something like this:
Warning: session_start() [function.session-start]: The session id contains illegal characters, valid characters are a-z, A-Z, 0-9 and '-,' in /home/example/public_html/includes/functions.php on line 2
In PHP, the maximum acceptable size by default for a session cookie is 128 bytes, so it may be possible to trigger FPD by setting the length of your session cookie to 129 or more bytes, like so:
Another option is to set the value of your session cookie to a reserved character such as a dot or a comma
- Unexpected/Invalid data types being supplied:
Although in many cases this will just result in a “type mismatch” error (No, kids, that isn’t SQL Injection – just pointing this out because we see so many people reporting a simple type mismatch as SQLi), sometimes if you’re lucky (by ‘lucky’ we mean if error reporting is enabled and the page is configured in a certain manner) then this can result in Full Path Disclosure or even a full stack trace being outputted. For example, if there is a script that is expecting an integer as input from the user, and instead the user inputs a floating decimal or a string, this can result in Path Disclosure.
For example, lets assume calc.php takes two integers as inputs and performs addition or subtraction on them:
It may be possible to trigger Full Path Disclosure by inputting a non-expected data-type, such as a float:
or a string:
Of course this can work in reverse – for example if the page is expecting a string and you input a float or integer.
- Navigating to pages that don’t exist:
Sometimes simply navigating to a page that does not exist is enough to trigger a path disclosure. There are a few different ways in which this is generally done. The first (and most reliable) would be if there was a parameter to include a page on a site, for example if you had something like this:
Changing the ?page= parameter to something that clearly won’t exist is sometimes enough to trigger FPD:
Pro tip: if you get FPD as a result of this method, look into it a lot more. An FPD outputted as a result of the above method is very often an indicator of a more serious issue such as Local File Inclusion.
The second (and far less reliable method) of achieving FPD through a non-existent page is simply trying to navigate to the page like so:
despite the chances of that last method being slim, It’s still worth checking for if all else fails, as I’ve still had many successes with it in the past, regardless of it not working in most cases.
- Supplying invalid data-types as param values:
Assume you have a URL like follows:
In addition to the aforementioned technique of mixing up data types to trigger FPD (inputting strings/floats where integers are expected, and so on), it is also sometimes possible to disclose the path by inputting “data types” into parameters that clearly could not be a real data type of any sort, here are some examples:
Depending on the server configuration, this may be absolutely useless, or it could result in the FPD that you are looking for.
- Finding paths via phpinfo output:
Some websites will have their PHP Information publicly viewable (Why? Because many devs are incredibly stupid. More often than not they have it running on a testing server while developing their site then they forget to remove it while pushing to production, but there’s also been many cases observed where they leave it there because its ‘useful’ and apparently poses no security risks whatsoever.) – not only will this reveal the path, but also a trove of other information, such as details about their php.ini configuration, the uname output of the backend server, installed add-ons, and more.
Below are some common paths we have observed leading to
<?php echo phpinfo(); ?> being outputted.
Remember to also try for other PHP-related exntensions, e.g. php3, php4, and so on:
As for the following one, we’ve never quite understood why people do this, but, we’ve seen people label it as phpinfo.txt then set the content-type to PHP or modify it via a htaccess rewrite. I guess maybe they’re smoking crack or something:
Below, you can find a few more examples of common paths to phpinfo:
If you’re still having trouble finding their phpinfo, then Google can often yield useful results. This can in fact be very useful even in instances where they’ve removed phpinfo pages (yet such pages may still be available via google’s cache or through the likes of archive.org or other similar sites).
Don’t underestimate the power of Google dorking. Even if a developer has suddenly decided to put in more effort than that of a chimpanzee and finally disabled error-reporting site-wide, there may have still been a time when error reporting was enabled, and Google may still have a cache of some of those pages. It’s always worth searching for strings associated with FPD in order to see if Google has any of these pages cache. Just because a developer has disabled error reporting doesn’t mean that the path to their webroot directory has changed (it most likely hasnt!). Just remember to use
site:target-site.com so you’re not getting a bunch of useless noise.
Some examples of what you could dork for (without using the site: operator these are pointless – also use double quotes or the intext: operator to ensure that it’s matching the exact string and not just containing some words that the FPD error message also happens to contain). Here’s an example for any dummies out there:
site:target-site.com intext:the string you want to search
site:target-site.com "the string you want to search"
As for examples of specific strings to search, here are a few:
"supplied argument is not a valid MySQL result resource"
"The session id contains illegal characters"
"failed to open dir: No such file or directory"
"failed to open stream: No such file or directory in"
"Fatal error:" "include_path="
Remember too to utilize Google’s wildcards (the * character – for more information read our Google Dorks page) into your searches, this is due to the fact that while parts of the error message will remain the same, function names may differ. Here are some examples:
"Warning: *(*) [function.*]:"
"Fatal error: * in * on line *"
"Warning: * [function.*]: failed to open stream: No such file or directory in * on line *"
Warning:(): * supplied argument * in /* on line *
… and so on. You should get the point. If the developers have finally disabled error reporting, then some targeted Google dorking could potentially show a cached page displaying the path info.
- Division by Zero:
As anyone who didn’t flunk junior-school math, you should know that dividing something by zero is not possible. Shoddily written scripts on the other hand, are not aware of this basic fact and will in some cases attempting to divide by zero anyway. This can lead to Full Path Disclosure alongside a whole host of other problems. Let’s use the calculator script detailed above as an example for how this could be done. Here is what the original example of calc.php looked like as a URL. Note the GET parameters:
A user could manipulate these parameters like so:
WARNING: be VERY careful while testing this in the wild or during a penetration test against a client. Although it can result in path disclosure, it can occasionally result in a multitude of unexpected results which could cause serious damage to the server. Cases have been observed where this has resulted in application-level DoS, making the server inaccessible for all users. Testing this during a bug bounty and causing damage in this manner could get you banned, or even worse, arrested.
- Utilizing other vulnerabilities to get the full path:
This is by far the most convenient way of achieving FPD, because, most importantly, the nature of vulnerabilities in which allow you to reveal the full path, are also the exact nature of vulnerabilities that a full path is required in order to efficiently exploit. So, if you manage to identify both at once, then it’s a win/win situation and makes the exploitation process far easier. The two specific class of vulnerability that allow this to happen are SQL Injection and Local File Inclusion (or Local File Disclosure). In the final section of this page, an explanation as to why sometimes needing to know the full path is necessary for these vulnerabilities, alongside an explanation of other cases in which knowing the full path can be beneficial to a hacker.
For Local File Inclusion you can sometimes directly get the full path outputted via common files that you would be attempting to include while exploiting a vulnerability of this nature anyway, for example:
Since the passwd file contains a list of user accounts on the server alongside with their installed path, you can sometimes get the full path by simply looking for the web user in the passwd file and checking the associated path. /proc/self/environ is another file that can be included that can expose the full path, simply look for the values assigned to DOCUMENT_ROOT or SCRIPT_FILENAME – assuming you have an SQL Injection flaw and you have the ability to read local files via load_file() then the same result can potentially be achieved here by reading the same files. If this is possible, then it is hugely beneficial and by far the most efficient way of getting the full path (since its directly through the vulnerabilities that may require full path disclosure in order to be exploited to their fullest extent).
If you have an SQL Injection flaw but are lacking the ability to use features such as load_file(); in order to read local files, then you still may be able to utilize the SQLi to get the path information anyway. Sometimes error-based SQLi will just output it for you alongside the SQL error message, but if not, then try changing the ID (assuming it’s an integer) of the vuln parameter to a null value. For example, if you had a file news.php which performed an SQL query to determine which news article to load based on the numerical value provided (e.g. ?id=1 loads the first article, ?id=2 loads the second article, and so on), then do the following:
Generally this will only work if the page already happens to be vulnerable to SQL Injection, but in very rare cases it can lead to FPD without an SQLi being present. If there is an SQLi present another thing you can do is attempt to make it spit out an error through division by zero, as mentioned above (but via SQLi this time):
Why is knowing the full path necessary?
There are a variety of reasons as to why it may be necessary to know the full path, the most important being that they can be a requirement (when chained with other vulnerabilities which I will list below) to access a server. In addition to that, the information disclosed from a full path can tell you a lot more than just the path to the webroot directory. It can disclose names of user accounts on the server, whether it’s a shared server, which provider it’s with (assuming the attacker has prior knowledge of how directories are configured on various hosting providers), which operating system is running (in some cases, by determining the path to the httpd you can determine the distribution in use), among other bits of information (for example if it’s a shared server, and you see ‘user151’ in the path, then you know there are more than 150 user accounts on the server).
- SQL Injections:
Within SQL Injection attacks, if you have read privs via load_file(); or write privs through into outfile or dumpfile then knowing the path is necessary. For the former it may be necessary in order to read configuration files (such as the CMS config which could contain admin login credentials), whereas with the latter it is necessary to know where to write your shell to in order to gain access to the server. Without knowing the path, you won’t know where to write your shell to or how to locate it. Luckily, as mentioned earlier, if you have the ability to write files (via the likes of into outfile) then you should also have the ability to perform local file reads via load_file(); meaning you should be able to get the full path using the methods described above. If this isn’t a possibility, then other methods described above can be attempted to leak the full path.
- File inclusion or disclosure vulnerabilities:
The same logic applies for LFI/LFD vulnerabilities. This is especially important for Local File Disclosure moreso than it is for Local File Inclusion – this is because with LFI, the contents of any file you load is treated as an executable, meaning access can generally be gained through means of escalating to RCE by log poisoning or other methods. With Local File Disclosure, this isn’t a possibility so you can only gain access through information disclosure as a result of leaked files – meaning one of the most common ways to gain access to the server would be to read config files in the webroot directory (which of course you would need the full path to). For LFI on the other hand, access can generally be gained without needing the full path, but this can sometimes be very complex to the point of bordering near-impossible, so having the path and therefore the ability to potentially read configuration files offers the attacker a huge advantage, saving a lot of time and effort.
- Malicious Symbolic Linking:
Sometimes a hacker may come across a site on a shared server where they are unable to find a vulnerability other than FPD. The fact the server is shared, combined with the fact they have the specific path to that user’s webspace on the server, is practically invaluable. Let’s assume there are hundreds of sites running on this shared server. If the hacker is competent at all, then it’s almost a certainty that they will be able to identify and exploit another site running on the same server. From there, they can create a Symbolic Link to the webspace of the site that they were originally attempting to compromise. Without having the full path to that site, this would not be possible (or would be drastically harder as privilege escalation would more than likely be a requirement)
- SSH Bruteforce:
Last, but not least, path disclosure also discloses user account names (which generally match SSH usernames) – this allows an attacker to be able to perform bruteforce attacks not only on the ‘root’ user but also on other user accounts. From that point onwards, the attacker can attempt to escalate privileges either horizontally or vertically in order to gain root access to the server for a full compromise.
Well, that’s all for now! Part 2 will be coming in the next few weeks, and itt’l cover several other generic FPD methods, along with methods to trigger stack traces in several popular web applications.