使用 Python 的 FTP 弱密码扫描器

PythonBeginner
立即练习

介绍

本项目从使用 Python 实现一个 FTP 弱密码扫描器开始,介绍 Python 渗透测试技术。该实验涉及理解 FTP 服务器原理、使用 ftplib 库以及其他相关知识。

  1. 理解 FTP 服务器:了解 FTP 服务器、其用途以及工作方式。
  2. 使用 FTPlib 库:利用 Python 中的 ftplib 库实现一个 FTP 匿名扫描器和一个暴力密码破解器。
  3. 使用 argparse 库:学习如何使用 Python 中的 argparse 库处理命令行参数。
  4. 在 Ubuntu 上设置 FTP 服务器:按照说明在本地设置一个 FTP 服务器用于测试。

本项目难度适中,适合对 Python 有基本了解的用户。这是一个巩固和强化 Python 基础知识并获得 Python 渗透测试技术实践经验的好机会。

👀 预览

python3 ftpScanner.py -H 127.0.0.1 -f pwd.txt
[-] 127.0.0.1 FTP匿名登录失败!
[+] 尝试:ftp:ftp
[+] 尝试:root:root
[+] 尝试:root:toor
[+] 尝试:admin:admin
[+] 尝试:geust:geust
[+] 尝试:admin:123456

[+] 127.0.0.1 FTP登录成功:admin:123456

[+] 主机:127.0.0.1 用户名:admin 密码:123456

[*]-------------------扫描结束!--------------------[*]

🎯 任务

在本项目中,你将学习:

  • 如何理解 FTP 服务器的工作原理
  • 如何使用 Python 中的 ftplib 库实现一个 FTP 匿名扫描器
  • 如何使用密码字典为 FTP 服务器实现一个暴力密码破解器
  • 如何使用 argparse 库处理命令行参数
  • 如何在 Ubuntu 上设置一个 FTP 服务器用于测试

🏆 成果

完成本项目后,你将能够:

  • 使用 Python 与 FTP 服务器进行交互
  • 实现对匿名登录和弱密码的扫描
  • 在 Python 中处理命令行参数
  • 在 Ubuntu 上设置一个 FTP 服务器

FTP 服务器

FTP 服务器(文件传输协议服务器)是一台遵循 FTP 协议在互联网上提供文件存储和访问服务的计算机。FTP 代表文件传输协议,它是一种专门为文件传输设计的协议。简单来说,支持 FTP 协议的服务器就是 FTP 服务器。

FTP 是一种仅基于 TCP 的服务,不支持 UDP。FTP 的独特之处在于它使用两个端口,一个数据端口和一个命令端口(也称为控制端口)。通常,这两个端口分别是 21(命令端口)和 20(数据端口)。然而,数据端口并不总是 20,这取决于 FTP 的工作模式。这就是主动式和被动式 FTP 的主要区别。主要有两种工作模式:

  • 主动式 FTP FTP 服务器的控制端口是 21,数据端口是 20。因此,在设置静态映射时,只需要打开端口 21。服务器将使用端口 20 与客户端发起连接。
  • 被动式 FTP 服务器的控制端口是 21,数据端口是随机分配的。客户端发起与相应数据端口的连接,所以仅打开端口 21 进行静态映射是不够的。在这种情况下,需要一个 DMZ(非军事区)。

在本项目中,开发一个 FTP 扫描器主要关注以下两个方面:

  1. 扫描匿名 FTP 扫描匿名 FTP 登录主要用于批量扫描。扫描单个 FTP 服务器的成功率相对较低,但仍有可能成功。有些人可能会想,现在还有人不设置密码吗?许多网站仍然为用户提供 FTP 服务以方便下载资源,所以允许匿名登录并不奇怪。更令人惊讶的是,网站管理员为了方便更新网站访问软件而开放 FTP 匿名登录。这给我们提供了很多机会,特别是在攻击后一种类型的服务器时,它很容易受到攻击。在未来,我将解释如何在找到 FTP 目录中的网页后获取一个 shell。
  2. 扫描弱 FTP 密码 扫描弱 FTP 密码本质上就是暴力破解。为什么我们不称之为暴力破解呢?因为我们只是在扫描一些简单的密码组合,而不是所有可能的组合。另外,考虑到我们不可能活上千年,我们没有那么多时间去进行彻底的暴力破解!这只是一个密码而已。如果我们找不到弱密码,我们可以继续前进。世界上有无数的花,为什么要在一朵花上执着呢?然而,如果你真的喜欢这个 FTP 服务器,未来我会教你其他渗透服务器的方法!

FTP 匿名扫描器的实现

在这种情况下,我们将使用 Python 中 ftplib 库的 FTP 类。FTP 类实现了 FTP 客户端的大部分功能,例如连接到 FTP 服务器、查看服务器上的文件、上传和下载文件等。接下来,我们将定义函数 anonScan(hostname) 来实现对允许匿名登录的 FTP 服务器的扫描。代码如下:

## 匿名登录扫描器
def anonScan(hostname):                 ## 参数是主机名
    try:
        with FTP(hostname) as ftp:      ## 创建一个 FTP 对象
            ftp.login()                 ## FTP 匿名登录
            print('\n[*] ' + str(hostname) + " FTP 匿名登录成功!") ## 如果没有引发异常,说明登录成功
            return True
    except Exception as e:              ## 如果引发异常,说明匿名登录失败
        print('\n[-] ' + str(hostname) + " FTP 匿名登录失败!")
        return False

代码很简洁,注释解释了代码的含义。这个函数的总体思路是:首先,我们使用主机名构造一个 FTP 对象(名为 ftp)。然后,我们在这个 ftp 对象上调用不带任何参数的 login() 函数,以发起对 FTP 服务器的匿名登录。如果在登录过程中没有引发异常,说明匿名登录成功;否则,说明匿名登录失败。

FTP 弱密码扫描

FTP 弱密码扫描依赖于用户名和密码字典。在我们的实验环境中,将提供~/project/pwd.txt作为密码字典。

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

接下来,我们将在~/project目录中创建一个代码文件ftpScanner.py,以按照字典中的格式实现对 FTP 弱密码的扫描。代码如下:

## 暴力破解
def vlcLogin(hostname, pwdFile):                ## 参数(主机名,字典文件)
    try:
        with open(pwdFile, 'r') as pf:          ## 打开字典文件
            for line in pf.readlines():         ## 读取字典文件中的每一行
                time.sleep(1)                   ## 等待 1 秒
                userName = line.split(':')[0]   ## 从读取的内容中提取用户名
                passWord = line.split(':')[1].strip('\r').strip('\n')  ## 从读取的内容中提取密码
                print('[+] 尝试:' + userName + ':' + passWord)
                try:
                    with FTP(hostname) as ftp:  ## 使用主机名作为参数创建一个 FTP 对象
                        ftp.login(userName, passWord)   ## 使用提取的用户名和密码登录到 FTP 服务器
                        ## 如果没有引发异常,登录成功,打印主机名、用户名和密码
                        print('\n[+] ' + str(hostname) + ' FTP 登录成功:'+ \
                              userName + ':' + passWord)
                        return (userName, passWord)
                except Exception as e:
                    ## 如果引发异常,说明登录不成功,我们继续尝试其他用户名和密码
                    pass
    except IOError as e:
        print('错误:密码文件不存在!')
    print('\n[-] 无法破解 FTP 密码,请更换密码字典后重试!')
    return (None,None)

这段代码片段会遍历字典以读取用户名和密码,并尝试登录。如果登录成功,就意味着找到了用户名和密码。该函数将主机名定义为一个可以用逗号分隔的字符串。找到一个密码并不会终止程序,而是会继续在其他主机上扫描弱密码,直到所有主机都被扫描完毕。

命令行解析

到目前为止,我们的 FTP 扫描器几乎已经完成。代码不长且相当简单。现在,我们需要做的是让我们的脚本能够处理命令行输入,以控制扫描哪些主机。为了处理命令行参数,我们将使用 Python 中的 argparse 库。这个库是 Python 的一个内置模块,它使命令行解析变得非常简单。让我们通过查看以下代码来见证 argparse 的强大功能:

## 使用描述创建一个 ArgumentParser 对象
parser = argparse.ArgumentParser(description='FTP Scanner')
## 添加 -H 命令,其中 dest 指的是我们用于获取 -H 之后传递的值的变量名,help 提供此命令的帮助信息
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

通过使用 argparse 库来解析命令行参数,我们可以根据添加参数时提供的 help 关键字自动生成一个帮助文档。结果如下所示:

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

在处理复杂命令时,argparse 的强大功能更加明显。由于这是 Python 的一个基本特性,我不会对 Python 中包含的库进行过多详细介绍。

所有代码的整合

基本代码已经实现,现在我们只需要整合上述代码。代码如下:

from ftplib import *
import argparse
import time

## 匿名登录扫描
def anonScan(hostname):
    try:
        with FTP(hostname) as ftp:
            ftp.login()
            print('\n[*] ' + str(hostname) + " FTP 匿名登录成功!")
            return True
    except Exception as e:
        print('\n[-] ' + str(hostname) + " FTP 匿名登录失败!")
        return False

## 暴力破解
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('[+] 尝试:' + userName + ':' + passWord)
                try:
                    with FTP(hostname) as ftp:
                        ftp.login(userName, passWord)
                        print('\n[+] ' + str(hostname) + ' FTP 登录成功:'+ \
                              userName + ':' + passWord)
                        return (userName, passWord)
                except Exception as e:
                    pass
    except IOError as e:
        print('错误:密码文件不存在!')
    print('\n[-] 无法破解 FTP 密码,请更换密码字典后重试!')
    return (None,None)

def main():
    parser = argparse.ArgumentParser(description='FTP 扫描器')
    parser.add_argument('-H',dest='hostName',help='以逗号分隔的主机列表')
    parser.add_argument('-f',dest='pwdFile',help='密码字典文件')
    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('主机:' + hostName + ' 可以匿名访问!')
        elif pwdFile!= None:
            (username,password) = vlcLogin(hostName,pwdFile)
            if password!= None:
                print('\n[+] 主机:' + hostName + ' 用户名:' + username + \
                      ' 密码:' + password)

    print('\n[*]-------------------扫描结束!--------------------[*]')

if __name__ == '__main__':
    main()

至此,我们的代码就完成了。通过一些修改,我们可以让这个扫描器更加强大。例如,可以指定主机名范围以实现大规模扫描,或者修改代码以对 FTP 用户名和密码进行分布式暴力破解,增加字典容量并大幅提高成功率。

设置 FTP 服务器

接下来,我们需要在本地设置一个 FTP 服务器来测试我们的扫描器。在这里,我们将使用 Python 中的 pyftpdlib 库来设置 FTP 服务器。pyftpdlib 是一个用于 FTP 服务器的 Python 库,可用于快速构建一个 FTP 服务器。安装 pyftpdlib 非常简单,只需使用 pip 命令。在终端中输入以下命令来安装 pyftpdlib 库:

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

默认情况下,允许匿名登录。

扫描测试

既然我们的环境已经搭建好了,就可以开始测试我们的 FTP 弱密码扫描器了。

cd ~/project
python3 ftpScanner.py -H 127.0.0.1 -f pwd.txt
[*] 127.0.0.1 FTP匿名登录成功!
主机: 127.0.0.1 可以匿名访问!

[*]-------------------扫描结束!--------------------[*]

在这个测试中,我们主要关注匿名登录。至于弱密码的暴力破解,你可以找到自己的密码字典并尝试破解 FTP 服务器。

现在,我们尝试给 FTP 服务器添加一个密码并再次进行测试。首先,我们需要停止 FTP 服务器,然后使用密码重新启动它。

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匿名登录失败!
[+] 尝试: ftp:ftp
[+] 尝试: root:root
[+] 尝试: root:toor
[+] 尝试: admin:admin
[+] 尝试: geust:geust
[+] 尝试: admin:123456

[+] 127.0.0.1 FTP登录成功: admin:123456

[+] 主机: 127.0.0.1 用户名: admin 密码: 123456

[*]-------------------扫描结束!--------------------[*]

总结

本项目实现了一个 FTP 弱密码扫描器,运用了以下要点:

  1. FTP 服务器的基本概念
  2. 使用 FTPlib 逐步实现 FTP 弱密码扫描器
  3. 使用 argparse 解析命令行参数
  4. 设置测试环境的方法。
✨ 查看解决方案并练习✨ 查看解决方案并练习✨ 查看解决方案并练习✨ 查看解决方案并练习✨ 查看解决方案并练习✨ 查看解决方案并练习✨ 查看解决方案并练习