只是一次简单的课程设计,通过Python实现端口扫描器的功能,附加ping扫描以及简单的banner获取,支持导出扫描结果。
程序运行实例
- 打印装逼信息:
- 扫描实例:
- 具体用法程序中有说明
程序说明
程序中默认扫描一些常见的端口、支持用户设置端口、支持多端口扫描、支持多IP扫描、支持网段存活主机发现、支持导出。
通过发送ping包,根据返回包的TTL值判断主机是否存活,关键代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21def run(self):
try:
cmd = ["ping", "-{op}".format(op=self.get_os()),
"1", self.ip_pre]
output = os.popen(" ".join(cmd)).readlines()
except:
return False
if lock.acquire():
flag = False
for line in list(output):
if not line:
continue
if str(line).upper().find("TTL") >=0:
flag = True
break
if flag:
print "[+] IP: %s is OK " % self.ip_pre
ip_str.append(self.ip_pre)
lock.release()
return True通过socket建立tcp全连接来判断端口开放信息以及banner信息的抓取,关键代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21def Ping(self, Port):
global OpenPort, lock, Timeout
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.settimeout(Timeout)
address = (self.IP, Port)
try:
sock.connect(address)
ready = select.select([sock],[],[],1)
except:
return False
if lock.acquire():
OpenPort.append(str(Port))
ScanIP_list.append(self.IP)
if ready[0]:
print "IP:%s Port:%d Open " % (self.IP, Port) +sock.recv(4096)
sock.close()
else:
print "IP:%s Port:%d Open " % (self.IP, Port) + "Unknow!\n"
sock.close()
lock.release()
return True通过队列来判断扫描目标的端口列表是否为空,通过判空来控制在端口扫描的时候不会漏扫,还有就是在多IP端口扫描的时候避免出现误扫IP的状况,关键代码如下:
1
2
3
4def run(self):
while not self.SingleQueue.empty():
p = self.SingleQueue.get()
self.Ping(p)调用cmd模块来进行交互,用户通过这个模块来设置线程(在中程序中控制在1-5000,可以修改)、设置连接超时时间、设置端口、进行端口扫描、ping扫描等。关键代码如下:(贴出设置端口、单IP扫描、ping扫描的代码,具体代码请看源码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17def do_port(self, argv):
global PortList
PortList = []
ListTmp = argv.split(' ')
for port in ListTmp:
if port.find("..") < 0:
if not port.isdigit():
print "Input error!"
return False
PortList.append(int(port))
else:
RangeLst = port.split("..")
if not (RangeLst[0].isdigit() and RangeLst[1].isdigit()):
raise ValueError
exit()
for i in range(int(RangeLst[0]), int(RangeLst[1])):
PortList.append(i)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21def do_scan(self, argv):
print "Start Time %s" % time.ctime() + '\n'
global nThread, PortList, strIP, ScanIP_list, OpenPort
del ScanIP_list[:]
del OpenPort[:]
ThreadList = []
try:
strIP = socket.gethostbyname(str(argv))
except:
print "Input error!"
return False
SingleQueue = GetQueue(PortList)
if PortList != None:
for i in range(0, nThread):
t = ScanThreadSingle(strIP, SingleQueue)
ThreadList.append(t)
for t in ThreadList:
t.start()
for t in ThreadList:
t.join()
print '\n' + "End Time %s" % time.ctime()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17def do_ping(self, argv):
global commandargs
ThreadList = []
print "Start Time %s" % time.ctime() + '\n'
commandargs = str(argv)
print "[+] Input is %s " % commandargs + '\n'
args = "".join(commandargs)
ip_prefix = '.'.join(args.split('.')[:-1])
for i in range(1,255):
ip = '%s.%s' % (ip_prefix,i)
s = PING(ip)
ThreadList.append(s)
for s in ThreadList:
s.start()
for s in ThreadList:
s.join()
print '\n' + "End Time %s" % time.ctime()这些就是整个程序中核心的几个模块,具体代码请看源码。
总结
此次设计参考了P牛早期的一个设计以及Python线程锁的处理方法。实现的功能比较单一,还可以添加SYN半连接扫描、UDP扫描、僵尸扫描等功能;但是由于Windows底层的原因,利用Python在Windows上构造数据包有些困难;在linux上可以通过scapy进行原始数据包的构造与发送,通过网络流量中的一些特征来判断。一些扫描脚本可以看四层发现中的一些脚本。