python-实现TCP端口扫描器

时间:2022-01-14 10:28:01

1.编写TCP全连接扫描

 

#!/usr/bin/python
#coding=utf-8
import optparse
import socket
from socket import *

def connScan(tgtHost,tgtPort):
    try:
        connSkt = socket(AF_INET,SOCK_STREAM)
        connSkt.connect((tgtHost,tgtPort))
        connSkt.send('ViolentPython\r\n')
        result = connSkt.recv(100)
        print '[+] %d/tcp open'%tgtPort
        print '[+] ' + str(result)
        connSkt.close()
    except:
        print '[-] %d/tcp closed'%tgtPort

def portScan(tgtHost,tgtPorts):
    try:
        tgtIP = gethostbyname(tgtHost)
    except:
        print "[-] Cannot resolve '%s' : Unknown host"%tgtHost
        return

    try:
        tgtName = gethostbyaddr(tgtIP)
        print '\n[+] Scan Results for: ' + tgtName[0]
    except:
        print '\n[+] Scan Results for: ' + tgtIP

    setdefaulttimeout(1)

    for tgtPort in tgtPorts:
        print 'Scanning port' + tgtPort
        connScan(tgtHost,int(tgtPort))

def main():
    parser = optparse.OptionParser("[*] Usage : ./portscanner.py -H <target host> -p <target port>")
    parser.add_option('-H',dest='tgtHost',type='string',help='specify target host')
    parser.add_option('-p',dest='tgtPort',type='string',help='specify target port[s]')
    (options,args) = parser.parse_args()
    tgtHost = options.tgtHost
    tgtPorts = str(options.tgtPort).split(',')
    if (tgtHost == None) | (tgtPorts[0] == None):
        print parser.usage
        exit(0)
    portScan(tgtHost,tgtPorts)

if __name__ == '__main__':
    main()

 

这段代码实现了命令行参数输入,需要用户输入主机IP和扫描的端口号,其中多个端口号之间可以用,号分割开;若参数输入不为空时(注意检测端口参数列表不为空即检测至少存在第一个值不为空即可)则调用函数进行端口扫描;在portScan()函数中先尝试调用gethostbyname()来从主机名获取IP,若获取不了则解析IP失败程序结束,若成功则继续尝试调用gethostbyaddr()从IP获取主机名相关信息,若获取成功则输出列表的第一项主机名否则直接输出IP,接着遍历端口调用connScan()函数进行端口扫描;在connScan()函数中,socket方法中有两个参数AF_INET和SOCK_STREAM,分别表示使用IPv4地址和TCP流,这两个参数是默认的,在上一章的代码中没有添加但是默认是这两个参数,其余的代码和之前的差不多了。

注意一个小问题就是,设置命令行参数的时候,是已经默认添加了-h和--help参数来提示参数信息的,如果在host参数使用-h的话就会出现错误,因而要改为用大写的H即书上的“-H”即可。

调用方式:

scan.py -H 192.168.1.1 -p 21,22,25,80,143,443,8080

 

2.实现线程扫描

将上面的代码修改一下,添加线程实现,同时为了让一个函数获得完整的屏幕控制权,这里使用一个信号量semaphore,它能够阻止其他线程运行而避免出现多线程同时输出造成的乱码和失序等情况。在打印输出前带调用screenLock.acquire()函数执行一个加锁操作,若信号量还没被锁定则线程有权继续运行并输出打印到屏幕上,若信号量被锁定则只能等待直到信号量被释放。

使用多线程之后端口的扫描并不是按输入的顺序进行的了,而是同时进行,但是因为有信号量实现加锁等操作所以输出的结果并没有出现乱码等情况。

#!/usr/bin/python
#coding=utf-8
import optparse
import socket
from socket import *
from threading import *

#定义一个信号量
screenLock = Semaphore(value=1)

def connScan(tgtHost,tgtPort):
    try:
        connSkt = socket(AF_INET,SOCK_STREAM)
        connSkt.connect((tgtHost,tgtPort))
        connSkt.send('ViolentPython\r\n')
        result = connSkt.recv(100)

        #执行一个加锁操作
        screenLock.acquire()

        print '[+] %d/tcp open'%tgtPort
        print '[+] ' + str(result)
    except:
        #执行一个加锁操作
        screenLock.acquire()
        print '[-] %d/tcp closed'%tgtPort
    finally:
        #执行释放锁的操作,同时将socket的连接在其后关闭
        screenLock.release()
        connSkt.close()

def portScan(tgtHost,tgtPorts):
    try:
        tgtIP = gethostbyname(tgtHost)
    except:
        print "[-] Cannot resolve '%s' : Unknown host"%tgtHost
        return

    try:
        tgtName = gethostbyaddr(tgtIP)
        print '\n[+] Scan Results for: ' + tgtName[0]
    except:
        print '\n[+] Scan Results for: ' + tgtIP

    setdefaulttimeout(1)

    for tgtPort in tgtPorts:
        t = Thread(target=connScan,args=(tgtHost,int(tgtPort)))
        t.start()

def main():
    parser = optparse.OptionParser("[*] Usage : ./portscanner.py -H <target host> -p <target port>")
    parser.add_option('-H',dest='tgtHost',type='string',help='specify target host')
    parser.add_option('-p',dest='tgtPort',type='string',help='specify target port[s]')
    (options,args) = parser.parse_args()
    tgtHost = options.tgtHost
    tgtPorts = str(options.tgtPort).split(',')
    if (tgtHost == None) | (tgtPorts[0] == None):
        print parser.usage
        exit(0)
    portScan(tgtHost,tgtPorts)

if __name__ == '__main__':
    main()

 

调用方式:

scan.py -H 192.168.1.1 -p 21,22,25,80,143,443,8080

 

3.使用nmap端口扫描代码

 

#!/usr/bin/python
#coding=utf-8
import nmap
import optparse

def nmapScan(tgtHost,tgtPort):
    #创建一个PortScanner()类对象
    nmScan = nmap.PortScanner()

    #调用PortScanner类的scan()函数,将目标和端口作为参数输入并进行nmap扫描
    nmScan.scan(tgtHost,tgtPort)

    #输出扫描结果中的状态信息
    state = nmScan[tgtHost]['tcp'][int(tgtPort)]['state']
    print '[*] ' + tgtHost + " tcp/" + tgtPort + " " + state

def main():
    parser=optparse.OptionParser("[*] Usage : ./nmapScan.py -H <target host> -p <target port[s]>")
    parser.add_option('-H',dest='tgtHost',type='string',help='specify target host')
    parser.add_option('-p',dest='tgtPorts',type='string',help='specify target port[s]')    
    (options,args)=parser.parse_args()
    tgtHost = options.tgtHost
    tgtPorts = str(options.tgtPorts).split(',')
    if (tgtHost == None) | (tgtPorts[0] == None):
        print parser.usage
        exit(0)
    for tgtPort in tgtPorts:
        nmapScan(tgtHost,tgtPort)

if __name__ == '__main__':    
    main()

如果在前面没有下载该模块,则需要先到http://xael.org/pages/python-nmap-en.html中下载Python-Nmap

 

调用方式:

nmapscan.py -H 192.168.1.1 -p 21,22,25,80,143,443,8080