Using PHP’s data:// stream and File Inclusion to execute code

This is a reasonably old remote code execution trick that I was actually unaware of until recently, illness when I stumbled across it by accident. I have been heavily researching various ways to go from a file inclusion bug to a remote code execution bug, and this one really got me interested.

As we previously mentioned in the I expect:// a shell post, medical you can use certain PHP streams to execute code via a file inclusion vulnerability. This one does not require any PHP extensions to be installed, unlike the expect:// trick, and relies solely on allow_url_include to be enabled, which sadly is becoming a rarity these days.

How this works is simple. PHP has a data:// stream, which can decode and accept data. If you insert some PHP code into this stream and include() it, the code will be executed. Rather simple, and rather effective too. I will cover php://input in a follow up post, and then post my findings on abusing FindFirstFile.

Essentially, instead of including /etc/passwd or a remote file, you simply include the following. data://text/plain;base64,PAYLOAD_GOES_HERE
Where the payload is base64 encoded PHP code to be executed. I choose to base64 encode the payload to avoid some problems I ran into with whitespace and longer payloads.

Now, obviously this would be no fun without a simple proof of concept tool to demonstrate the vulnerability. The following tool is under serious redevelopment at the moment, so it only spawns a bind shell at the moment. Next version will offer several payloads (I am working on a generic payload library for this kind of thing).

Data:// shell to bindshell :)

You can download the current version of the tool here: PHP data include exploit

I will update that code later, might do a video once there is something worth watching.

I expect:// a shell!

This blog post covers a fascinating method of leveraging Local File Inclusion to gain Remote Code Execution on a vulnerable host. It has several downfalls, but overall is one of the more interesting methods I have found, and I have not found any references to it anywhere that I looked online.

PHP has many “wrappers” to parse certain types of things. For example, the php://input or php://filter wrappers, which have been used in the past for both code execution and information disclosure – notably the PHP-CGI Arguement Injection exploit, which uses the php://input wrapper to inject code after making modifications to PHP.ini directives.

One of the more entertaining ones I stumbled across is how PHP handles the expect:// “wrapper”. For those who do not know, “expect” is a program/scripting language of sorts that one can use to interact with other interactive programs. Some of you may be familiar with pexpect from Python, which is used to interact with SSH sessions for automation. It is a rather powerful utility, and is often used by sysadmins to automate procedures which would normally require human interaction.

As it happens, amongst PHP’s many wrappers, there is an “expect://” wrapper. I stumbled across it by accident while looking up the correct way to use php://filter to read files via LFI (I will document that method later, it deserves a post of its own). I knew expect looked familiar, so when I looked more into it, I found examples of people using it in PHP scripts to automate things like ssh-ing to remote boxes, etc.

After a while it dawned on me that something interesting might just happen if I passed expect://ls to an include() call in a PHP script, so I decided to see what would happen.

I used the following vulnerable (to LFI) PHP script, and called test.php?hax=expect://ls

<?php
$code = $_GET[‘hax’];
include($code);
?>

It provided me with a directory listing of my webroot.

expecting shell

remote code execution

After a few minutes of thinking “oh, this is interesting”, I decided to see if I could knock up an interactive shell in Python to automate the whole procedure.

First off, I decided to see could I get it all to work out using Pythons “requests” module…

Seeing as it worked, now it was time to write a “shell”.

Gotshell?

got shell :)

Yes, I now had a somewhat interactive “shell” on the vulnerable host (localhost…). I considered releasing the proof of concept right there, however further messing about was warranted first, obviously. I needed to see how far I could “push” this vuln, and how cool I could possibly make the PoC tool before releasing it to the wild, where someone would doubtlessly give me much abuse about my python :P

So, without further ado, here is the video demo of it. It now checks if the host is vuln (very rudimentary check), and offers the “inline shell” or a reverse shell :) Download links at bottom :)

// Err, the video is on its way, I did not have time to clean it up sadly. I will edit this post in a day or so with the finished video, I promise :)

download link