基于Nmap的异步无状态端口扫描技术
传统的端口扫描,主要是依靠TCP三次握手去连接,而建立连接的各个过程都存在连接状态,这些状态由操作系统在底层实现存储,可利用这些状态对应用层的数据进行处理。但是,这需要消耗大量的系统资源。一般的操作系统中,系统TCP/IP协议栈能同时保持的连接数只有几十或几百,即便是网络应用服务器,默认保持的连接数只有1500左右,很容易达到连接数的上限。因此,传统的端口扫描方式在扫描速度上受到了极大的限制。
针对上述问题,产生了一种基于无状态的端口扫描方式。无状态是指不需要操作系统关心TCP连接的状态。这种方式所建立的连接不占用操作系统的TCP/IP协议栈资源,而是应用程序在底层直接进行管理和维持,不需要操作系统对连接状态进行会话组包。在实现上,是把关键的状态位及数据信息通过程序直接放在数据包的本身。通过这种方式,能同时保持的连接数不再受操作系统的限制。应用程序直接从底层进行数据组包,并对连接进行维持和管理,决定连接的数量,从而使扫描速度得到极大的提高。
1)异步无状态端口扫描技术
扫描过程中,向目标服务器发送数据包,若采用有状态的扫描方式,需等待目标服务器的回复,要设置timeout参数。当进行大量扫描时,等待时间会成为提高扫描速率的瓶颈,即使使用多线程也会很慢,所以采用异步的无状态的扫描方式来提升扫描速度。
启动程序后,对每一个网卡建立一个异步处理的线程对,分别是发送数据包线程和接收数据包线程。如果目标服务器的端口是开放的就会返回响应数据包,响应数据包由接收数据包线程接收,并解析收到的数据包。发送数据包线程只负责发送,接收数据包线程只接收特定TCP flags字段的数据包,两者之间没有交互,这样就没有了等待回复的时间,程序工作流程图如下图所示:
- 1 数据包收发流程
地址随机化算法是将扫描目标的所有IP和PORT组成的目标地址进行随机化,组装数据包发送建立连接的请求。
发送数据包线程的执行过程如下:
(1)初始化变量;
(2)创建一个指向外部变量的指针,用于通知线程内的发送数据包的数量以及当前的发送速度等信息;
(3)初始化用户的IP和端口;
(4)设置数据包的发送速度,当速度过大,本地流量达不到要求时,会导致部分数据包丢失;
(5)计算扫描任务的扫描数量,即扫描的IP数与每个IP的端口数的乘积:NUM(IP)*NUM(PORT);
(6)循环本次扫描任务的扫描数量;
(7)执行完本次循环后,执行下一扫描范围循环;
(8)将发送队列中的剩余数据包发送出去。
接收数据包线程的执行过程如下:
(1)初始化变量;
(2)创建一个指向外部变量的指针,用于通知线程内的接收数据包的数量以及当前的接收速度等信息;
(3)将发送数据包线程分配到偶数编号的CPU,将接收数据包线程分配到奇数编号的CPU,实现更好的异步操作;
(4)利用pcap文件接收原生数据包,并创建接收表对异步操作导致的重复响应进行最优去重;
(5)如果是离线模式,等待发送线程结束后就关闭;
(6)接收数据包,执行一个while循环。
2)基于Nmap的异步无状态端口扫描技术
端口扫描有很多方法,常用的端口扫描方法以及扫描工具各有优缺点。Nmap能够主机发现,支持多端口、多网段的端口扫描,可对目标域名进行扫描;能够识别端口服务类型及版本、操作系统、设备类型等,但是如果进行大网段全端口扫描,Nmap的扫描能力就受到限制,扫描周期过长。通过前面对目标的信息收集,发现一个目标可能与多个主机相关。一个主机有65535个端口,所以,为了增大全面探测主机的效率,先采用基于异步无状态的端口扫描方式:构造相应flag的TCP报文发送到目标主机的所有端口。
通过对目标主机的所有端口采用异步无状态的端口扫描,得到目标主机所有的开放端口信息,并对开放的端口进行侦测,用来识别各个端口上所运行的服务及其版本。一般来说,每一个服务都有一个固定的默认端口。Nmap可以检测数百种应用协议,识别数千种应用的签名。调用Nmap的API进行端口探测,可以有效的识别目标主机上各个端口所运行的服务和版本。
操作系统是根据banner和fingerprint进行探测。如果直接抓到banner信息,那么很大概率上可以直接得到操作系统的类型和版本。但是如果没有,就要根据已知的指纹信息,来进行对应的推测。Nmap提供了上千种设备的指纹数据,通过调用Nmap的API对目标主机进行操作系统探测,能够有效的识别操作系统类型和版本号。
端口和操作系统探测采用基于异步无状态端口扫描和Nmap相结合的方法,工作流程如下图所示:
- 2 端口扫描流程
(1)用户输入目标,判断目标合法性。目标是前面信息收集到的所有目标相关IP。
(2)采用基于异步无状态的端口扫描方式,对全部IP进行扫描,包括每个主机的65535个端口,得到所有主机的开放端口信息。
(3)调用Nmap的API,探测开放端口的服务以及主机的操作系统类型和版本号。这里需安装python_nmap包,支持Python2.x以及3.x版本,python_nmap包提供了Python调用Nmap的一系列接口。代码中用到的重要的类以及方法分别是class PortScanner()和scan()。class PortScanner()用于创建Nmap扫描器,scan()用于设置扫描方法。
(4)结果存入数据库。
3)与Nmap端口扫描的性能比较
单独使用Nmap对主机进行扫描时,由于扫描效率低,一般只会扫描常用的1000个端口,平均每台主机耗时150秒。但是,运维工程师考虑到安全问题会更改服务的默认端口号。为保证扫描结果的全面性,本系统对全端口进行扫描。
- 3 端口扫描
对同一台主机,使用Nmap进行全端口扫描至少耗时2个小时,扫描效率比较低。采用异步无状态端口扫描和Nmap相结合方法,效率会大幅提升。如上图所示,利用异步无状态端口扫描方式,一台主机用时只有几十秒,比Nmap快了好多倍。如下图所示,针对开放端口,使用Nmap进行端口服务、操作系统类型和版本探测,平均只需2秒。实验证明,采用异步无状态端口扫描和Nmap相结合的方法比单独使用Nmap提高了近百倍。
- 4 端口扫描
综上,基于Nmap的异步无状态端口扫描技术,相比单独使用Nmap提高性能近百倍,实现端口扫描以及空间资产测绘速率的大幅提升。