漏洞扫描-端口
目的:构建一个简单的漏洞扫描器,它的主要功能是连接一个TCP套接字,从目标服务器上读取banner,并将其与自定义的漏洞服务器版本相比较。
实施前奏:
变量:在python中,变量是指 可以存储可变数据的标识体,这个数据可以是整数型、浮点型、字符型、布尔型,或者是列表、字典等更复杂的数据。接下来定义一个变量port用来存储整型和一个变量banner用来存储字符串。然后将这两个变量进行拼接,因为某些特性这里将整型的port变量所存储的值临时转换为字符型。
>>> port = 21 >>> banner = "FTP Server" >>> print "[+] Checking for "+banner+" on port "+str(port) [+] Checking for FTP Server on port 21
当我们声明变量时python程序准备给变量预留内存空间,而解释器会自动的为它们进行类型分配并确定通知后台程序具体分配多少内存空间,比如下面这个样子:
>>> type(banner) <type 'str'> >>> type(port) <type 'int'> >>> portList = [21,22,80.445] >>> type(portList) <type 'list'> >>> portOpen = True >>> type(portOpen) <type 'bool'>
字符串:在python中有一个string模块可以进行一系列的字符串处理。这里我们介绍string模块中四个方法的使用,upper()将字符串转换成大写形式,lower()将字符串转换成小写形式,replace(old,new)用new字符串代替old字符串。find()返回字符在字符串中第一次出现时的偏移量。但是这种更改并不会改变变量空间的值
>>> print banner.upper() FTP SERVER >>> print banner.lower() ftp server >>> print banner.replace('ftp','Ability ftp') FTP Server >>> print banner.replace('FTP','Ability ftp') Ability ftp Server >>> print banner.find("ftp") -1 >>> print banner.find("Server") 4 >>> banner 'FTP Server'
List(列表):list数据结构是python中用来存储对象数组的。在内置的list模块中具有添加、插入、删除、出站、索引、计数、排序、反转等功能。
>>> portList = [] >>> portList.append(21) >>> portList.append(80) >>> portList.append(443) >>> portList.append(25) >>> portList [21, 80, 443, 25] >>> portList.sort() >>> portList [21, 25, 80, 443] >>> pos = portList.index(80) >>> print "[+] There are "+str(pos)+" ports to scan before 80." [+] There are 2 ports to scan before 80. >>> portList.remove(443) >>> portList [21, 25, 80] >>> cnt = len(portList) >>> print "[+] Scanning "+str(cnt)+" Total Ports." [+] Scanning 3 Total Ports.
字典:由n对键和值的项组成,是可以存储任意数量的对象的hash表。在扫描指定的TCP端口时,包含有各个端口及对应的常用服务名的字典就很有用。如创建一个相关的字典之后,在我们查找ftp之类的关键字,就会返回与之关联的端口值-21。
创建字典时,每个键和它的值都是以’:‘分隔同时以’,‘分隔各项。
>>> services = {'ftp':21,'ssh':22,'smtp':25,'http':80} >>> services.keys() ['ftp', 'http', 'smtp', 'ssh'] >>> services.items() [('ftp', 21), ('http', 80), ('smtp', 25), ('ssh', 22)] >>> services.has_key('ftp') True >>> services['ftp'] 21 >>> print "[+] Found vuln with FTP on port "+str(services['ftp']) [+] Found vuln with FTP on port 21
网络:socket模块是python中进行网络连接的库。下面编写一个快速抓取banner的脚本,我们的脚本会在连上指定的IP地址和TCP端口后,将banner打印出来。
步骤-导入socket模块->实例化一个变量接收socket类->使用connect方法连接IP和PORT->使用套接字进行读写操作,recv(1024)方法读取->打印得到的结果。
>>> import socket >>> socket.setdefaulttimeout(2) >>> s = socket.socket() >>> s.connect(("192.168.44.132",21)) >>> ans = s.recv(1024) >>> print(ans) b'220 FileZilla Server 0.9.60 beta written by Tim Kosse (Tim.Kosse@gmx.de) Please visit http://sourceforge.\r\n'
错误示范:
>>> s.connect("192.168.44.132",21)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: connect() takes exactly one argument (2 given)
>>>
条件选择语句:IF语句是对逻辑表达式进行求值,并根据求值结果做出决定。我们仍以抓取脚本为例:我们想要知道某个指定的FTP服务器中是否存在可以攻漏洞。这就需要将服务器的响应结果与已知存在的漏洞FTP服务版本进行比较。注意哈:python2中接收到的recv()会以str赋值给ans,而在python3中recv()是以byte赋值给ans。
>>> import socket >>> socket.setdefaulttimeout(2) >>> s = socket.socket() >>> s.connect(("192.168.44.132",21)) >>> ans = s.recv(1024) >>> print ans >>> if ("FreeFloat Ftp Server (Version 1.00)" in ans): ... print "[+] FreeFloat FTP Server is vulnerable." ... elif ("3Com 3CDaemon FTP Server Version 2.0" in banner): ... print "[+] 3CDeamon FTP Server is vulnerable." ... elif ("Sami FTP Server 2.0.2" in banner): ... print "[+] Sami FTP Server is vulnerable." ... else: ... print "[-] FTP Server is not vulnerable."
[-] FTP Server is not vulnerable.
异常处理:我们在编写脚本的时候经常会碰到各种报错,并且会终止程序的执行。但是如果我们不想就这样简单结束,就需要我们进行自定义获取。如下面的两种情况:
>>> print 123123/0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: integer division or modulo by zero >>> >>> try: ... print "[+] 123/0 = "+str(123/0) ... except: ... print "[-] Error." ... [-] Error. >>> try: ... print "[+] 123/0 = "+str(123/0) ... except Exception,e : ... print "[-] Error = "+str(e) ... [-] Error = integer division or modulo by zero
现在我们用异常来更新抓取banner的脚本。我们把网络连接代码写在try语句内,接下来我们尝试连接到一台没有TCP端口21运行FTP服务器的机器。如果等待的连接超时,就会看到一条表明网络连接操作超时的消息。
>>> import socket >>> socket.setdefaulttimeout(2) >>> s = socket.socket() >>> try: ... s.connect(("192.168.44.128",21)) ... except Exception,e: ... print "[-] Error = "+str(e) ... [-] Error = timed out
函数:关键字def()表示函数开始。我们可以在()中填写任意变量,然后这些变量会被引用的方式传递给函数,也就是说,函数内对这些变量的任何更改都会影响它们在函数中的值。
>>> import socket >>> def retBanner(ip,port): ... try: ... socket.setdefaulttimeout(2) ... s = socket.socket() ... s.connect((ip,port)) ... banner = s.recv(1024) ... return banner ... except: ... return ... >>> def main(): ... ip1 = "192.168.44.124" ... ip2 = "192.168.44.132" ... port = 21 ... banner1 = retBanner(ip1,port) ... if banner1: ... print '[+] '+ip1+': '+banner1 ... banner2 = retBanner(ip2,port) ... if banner2: ... print '[+] '+ip2+': '+banner2 ... >>> if __name__ == '__main__': ... main() ... [+] 192.168.44.132: 220 FileZilla Server 0.9.60 beta written by Tim Kosse (Tim.Kosse@gmx.de) Please visit http://sourceforge.
迭代:当我们做重复的事情时,很自然的会感觉到烦躁,这是正常的。所以就引用出了迭代。它可以帮我们自行做很多重复的工作以降低我的压力。
>>> for x in range(10,20): ... print "192.168.44."+str(x)+":21 " ... 192.168.44.10:21 192.168.44.11:21 192.168.44.12:21 192.168.44.13:21 192.168.44.14:21 192.168.44.15:21 192.168.44.16:21 192.168.44.17:21 192.168.44.18:21 192.168.44.19:21
文件输入/输出:当我们开始烦躁重复的向脚本添加新的具有漏洞的服务时,想到了为什么不可以外部引用。这就出现了读取文件内容操作。我们事先写好一个带有漏洞的服务的文本。
3Com 3CDaemon FTP Server Version 2.0 Ability Server 2.34 CCProxy Telnet Service Ready ESMTP TABS Mail Server for Windows NT FreeFloat Ftp Server (Version 1.00) IMAP4revl MDaemin 9.6.4 ready MailEnable Service,Version: 0-1.54 NetDecision-HTTP-Server 1.0 PSO Proxy 0.9 SAMBAR Sami FTP Server 2.0.2 Spipe 1.0 TelSrv 1.5 MDaemon 6.8.5 WinGate 6.1.1 Xitami YahooPOPs! Simple Mail Transfer Service Ready
然后我对其经行读取引用。这里以只读模式(’r')打开文本文件,用.readlist()方法遍历文件中的每一行,并将其与我们的banner进行比较。.strip('\n')方法将每一行的回车键去掉。
>>> def checkVulns(banner): ... f = open("C:\Users\HK\Desktop\note\bak\python_team\vuln_banners.txt",'r') ... for line in f.readlines(): ... if line.strip('\n') in banner: ... print "[+] Server is vulnerable: "+banner.strip('\n') ...
sys模块:其包括了标志、版本、整型数的最大尺寸、可用的模块、hook路径、标准错误/输入/输出的位置,以及调用解释器的命令行参数。
>>> import sys >>> if len(sys.argv)==2: ... filename = sys.argv[1] ... print "[+] Reading Vulnerabilities From:"+filename ...
C:\Users>python PortScan.py vuln_banners.txt
[+] Reading Vulnerabilities From: vuln_banners.txt
os模块:本模块允许程序独立的与操作系统环境、文件系统、用户数据库以及权限进行交互。
import sys import os if len(sys.argv) == 2: filename = sys.argv[1] if not os.path.isfile(filename): print '[-] ' + filename + ' does not exist.' exit(0) if not os.access(filename,os.R_OK): print '[-] ' + filename + ' access denied.' exidt(0) print "[+] Reading Vulnerabilities From: "+filename
最终整合:将之前学到的进行整合修改后得到一个简陋的FTP扫描脚本
import socket import sys import os
#连接函数 def retBanner(ip,port): try: socket.setdefaulttimeout(2) s = socket.socket() s.connect((ip,port)) banner = s.recv(1024) return banner except: return
#检查漏洞函数 def checkVulns(banner,filename): f = open(filename,'r') for line in f.readlines(): if line.strip('\n') in banner: print '[+] Server is vulnerable.'\ +banner.strip('\n')
#主函数 def main(): if len(sys.argv) == 2: filename = sys.argv[1] if not os.path.isfile(filename): print '[-] ' + filename +\ ' does not exist.' exit(0) if not os.access(filename,os.R_OK): print '[-] ' + filename +\ ' access denied.' exit(0) else: print '[-] Usage: ' + str(sys.argv[0]) +\ ' <vuln filename.' exit(0) portlist = [21,22,25,80,110,443] for x in range(2,50): ip = '172.16.212.'+str(x) for port in portlist: banner = retBanner(ip,port) if banner: print '[+] ' + ip + ': '+banner checkVulns(banner,filename)
#调用 if __name__ == '__main__': main()
ENDING....