Nmap是一款强大的端口扫描工具,渗透测试中经常用到,其功能主要有主机发现,端口扫描,版本侦测,OS侦测等。其中端口扫描是Nmap的核心功能,端口扫描有SYN扫描、TCP connect扫描、UDP扫描、ACK扫描等。为了了解Nmap的端口扫描原理,现用Python实现一个简单的端口扫描器,并用Wireshark抓包分析。附上源码:
#python3环境下运行
#encoding: utf-8
from socket import *
import threading
lock = threading.Lock()
openNum = 0
threads = []
def portScanner(host,port):
global openNum
try:
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
lock.acquire()
openNum+=1
print('[+] %d open' % port)
lock.release()
s.close()
except:
pass
def main():
setdefaulttimeout(1)
ip = input('please enter your host: ')
for p in range(1,4000):
t = threading.Thread(target=portScanner,args=(ip,p))
threads.append(t)
t.start()
for t in threads:
t.join()
print('[+] The scan is complete!')
print('[+] A total of %d open port ' % (openNum))
if __name__ == '__main__':
main()
上面源码用的socket模块下的socket函数,其中socket(AF_INET,SOCK_STREAM)
中的SOCK_STREAM
代表TCP连接,如果是SOCK_DGRAM
则代表UDP连接,上面程序还用到了多线程技术。程序运行结果如下:
下面就通过Wireshark抓包工具来看看程序是如何识别开放与关闭的端口的:
端口1的TCP数据包
端口22的TCP数据包(中间两行其他端口的被cut掉了)
运行程序后,在过滤器里面直接输入TCP,可以看到tcp数据包的传输过程,以端口1和端口22为例,由程序运行结果图可知端口1是关闭的,端口22(ssh服务)是开放的。
扫描端口1时,客户端先创建套接字,然后连接远程服务器ip和端口1,发送标志位SYN,服务器端口1并没有开放,所以服务器返回[RST,ACK]
标志位,RST代表复位,并强制关闭tcp连接。
扫描22端口时,客户端发送SYN标志位,服务器端口22是开放的,服务器会发送一个[SYN,ACK]
标志位,然后客户端发送一个ACK标志位,整个TCP三次握手完成,最后客户端还会发送一个[FIN,ACK]
,FIN标志位代表连接断开。
这是TCP端口扫描方式,其原理跟Nmap中的TCP端口扫描方式一样,这种连接方式的缺点是建立了三次握手,不够隐蔽,是无法进行SYN扫描的选择,SYN扫描没有建立三次握手,隐蔽性较强。