python如何编写类似nmap的扫描工具
本文主要是利用scapy包编写了一个简易扫描工具,支持ARP、ICMP、TCP、UDP发现扫描,支持TCPSYN、UDP端口扫描,如下:
usage:pythonscan.py<-pping扫描类型><-s端口发现类型>[-ttarget][--portports] 简单扫描工具,可以进行存活扫描及端口扫描. 存活扫描包括:ARP扫描、ICMP扫描、TCP扫描、UDP扫描. 端口扫描包括:TCPSYN扫描、TCPACK扫描、TCPFIN扫描. optionalarguments: -h,--helpshowthishelpmessageandexit -v,--versionshowprogram'sversionnumberandexit targetgroup: 用于设置IP、PORT参数 --targetTARGETtarget为IP或IP段,如192.168.1.1,192.168.1.x,或1 92.168.1.1-254 --portPORTport为待扫描的端口,如21,80,...或21-80 pinggroup: 用于开启存活扫描相关选项 -p开启存活扫描 --ARP启动ARP扫描 --ICMP启动ICMP扫描 --TCP启动TCP扫描 --UDP启动UDP扫描 portscangroup: 用于开启端口扫描相关选项 -s开启端口扫描 --SYN开启SYN扫描 --ACK开启ACK扫描 --FIN开启FIN扫描 --UPORT开启UDP端口扫描 utilsgroup: 用于开启扫描过程中的一些实用选项 --timeoutTIMEOUT设置发包超时时间,默认0.5秒 --retryRETRY设置发包重试次数,默认不重试 以上做为说明,祝好运!
一、发现扫描
1.首先进行ARP扫描
pythonscan.py-p--target192.168.1.1-254--ARP [+]IP:192.168.1.1=>MAC:14:75:90:xx:xx:xx [+]IP:192.168.1.111=>MAC:c6:36:55:xx:xx:xx [+]总共耗时9.84091806412秒.
通过retry参数增加发包尝试次数,如下:
pythonscan.py-p--target192.168.1.1-254--ARP--retry2
[+]IP:192.168.1.1=>MAC:14:75:90:xx:xx:xx
[+]IP:192.168.1.111=>MAC:c6:36:55:xx:xx:xx
[+]IP:192.168.1.102=>MAC:58:1f:28:xx:xx:xx
[+]IP:192.168.1.114=>MAC:6c:8d:c1:xx:xx:xx
[+]IP:192.168.1.103=>MAC:84:38:38:xx:xx:xx
[+]总共耗时20.429942131秒.
2.使用ICMP扫描,若没有指定任何扫描类型参数,默认会启用ICMP扫描,如下:
pythonscan.py-p--target192.168.1.1-254 [+]没有指定任何ping扫描方式,默认选择ICMP扫描 [+]IP:主机192.168.1.1echo-reply. [+]IP:主机192.168.1.111echo-reply. [+]总共耗时10.7177450657秒.
通过timeout参数,设置较长的超时,可以防止网络状况不好造成的丢包,如下:
pythonscan.py-p--target192.168.1.1-254--timeout2 [+]没有指定任何ping扫描方式,默认选择ICMP扫描 [+]IP:主机192.168.1.1echo-reply. [+]IP:主机192.168.1.111echo-reply. [+]IP:主机192.168.1.114echo-reply. [+]总共耗时10.7566649914秒.
3.使用TCP扫描
pythonscan.py-p--target192.168.1.100-120--TCP--timeout1 [+]请稍等,时间较长! [!]扫描...192.168.1.100 [!]扫描...192.168.1.101 [!]扫描...192.168.1.102 [!]扫描...192.168.1.103 [!]扫描...192.168.1.104 [!]扫描...192.168.1.105 [!]扫描...192.168.1.106 [!]扫描...192.168.1.107 [!]扫描...192.168.1.108 [!]扫描...192.168.1.109 [!]扫描...192.168.1.110 [!]扫描...192.168.1.111 [!]扫描...192.168.1.112 [!]扫描...192.168.1.113 [!]扫描...192.168.1.114 [!]扫描...192.168.1.115 [!]扫描...192.168.1.116 [!]扫描...192.168.1.117 [!]扫描...192.168.1.118 [!]扫描...192.168.1.119 [!]扫描...192.168.1.120 [+]正在处理扫描信息. ==================== [+]主机192.168.1.102在线. [+]主机192.168.1.103在线. [+]主机192.168.1.111在线. [+]主机192.168.1.114在线. [+]总共耗时16.4359779358秒.
4.使用UDP扫描
pythonscan.py-p--target192.168.1.100-120--UDP--retry3 [+]请稍等,时间较长! [!]扫描...192.168.1.100 [!]扫描...192.168.1.101 [!]扫描...192.168.1.102 [!]扫描...192.168.1.103 [!]扫描...192.168.1.104 [!]扫描...192.168.1.105 [!]扫描...192.168.1.106 [!]扫描...192.168.1.107 [!]扫描...192.168.1.108 [!]扫描...192.168.1.109 [!]扫描...192.168.1.110 [!]扫描...192.168.1.111 [!]扫描...192.168.1.112 [!]扫描...192.168.1.113 [!]扫描...192.168.1.114 [!]扫描...192.168.1.115 [!]扫描...192.168.1.116 [!]扫描...192.168.1.117 [!]扫描...192.168.1.118 [!]扫描...192.168.1.119 [!]扫描...192.168.1.120 [+]正在处理扫描信息. ==================== [+]主机192.168.1.102在线. [+]主机192.168.1.103在线. [+]主机192.168.1.111在线. [+]主机192.168.1.114在线. [+]总共耗时33.5198891163秒.
二、端口扫描
1、TCPSYN端口扫描,不设置端口参数,则默认扫描1-1024端口
pythonscan.py--target192.168.1.110-115-s--SYN [+]没有指定任何扫描端口,默认扫描1-1024 [!]扫描...192.168.1.110 [!]扫描...192.168.1.111 [!]扫描...192.168.1.112 [!]扫描...192.168.1.113 [!]扫描...192.168.1.114 [!]扫描...192.168.1.115 [+]正在处理扫描信息. ==================== [+]主机192.168.1.111开放的TCP端口有:[80] [+]总共耗时165.125555992秒.
扫描指定端口:
pythonscan.py--target192.168.1.1-254-s--SYN--port80--timeout1 [!]扫描...192.168.1.1 [!]扫描...192.168.1.2 [!]扫描...192.168.1.3 [!]扫描...192.168.1.4 ... [!]扫描...192.168.1.253 [!]扫描...192.168.1.254 [+]正在处理扫描信息. ==================== [+]主机192.168.1.111开放的TCP端口有:[80] [+]主机192.168.1.1开放的TCP端口有:[80] [+]总共耗时9.72222185135秒.
2、扫描UDP端口
pythonscan.py--target192.168.1.1-s--UPORT--timeout1 [+]没有指定任何扫描端口,默认扫描1-1024 [!]扫描...192.168.1.1 [+]正在处理扫描信息. ==================== [+]主机192.168.1.1开放的UDP端口有:[520] [+]总共耗时27.4742250443秒.
也可同时进行发现扫描与端口扫描,如下:
pythonscan.py--target192.168.1.1-254-p--ARP-s--SYN--port80--timeout1--retry2 [+]IP:192.168.1.1=>MAC:14:75:90:xx:xx:xx [+]IP:192.168.1.102=>MAC:58:1f:28:xx:xx:xx [+]IP:192.168.1.114=>MAC:6c:8d:c1:xx:xx:xx [+]IP:192.168.1.103=>MAC:84:38:38:xx:xx:xx [+]IP:192.168.1.101=>MAC:5c:f7:e6:xx:xx:xx [!]扫描...192.168.1.1 [!]扫描...192.168.1.2 ... [!]扫描...192.168.1.253 [!]扫描...192.168.1.254 [+]正在处理扫描信息. ==================== [+]主机192.168.1.1开放的TCP端口有:[80] [+]主机192.168.1.111开放的TCP端口有:[80] [+]总共耗时45.2775988579秒.
OK,最后附上源码:
importargparse importre importtime importthreading fromscapy.allimport* importlogging logging.getLogger('scapy.runtime').setLevel(logging.ERROR) classDiscovery_Scan(object): ''' 说明:用于发现扫描 ''' def__init__(self,args,timeout=0.5,retry=0): self.targets=parse_target(args) self.timeout=timeout self.retry=retry defarp_scan(self,pdst): #ARP发现扫描 ans=sr1(ARP(pdst=pdst),timeout=self.timeout,retry=self.retry,verbose=False) ifans: ifans[ARP].op==2:#操作码为2是is-at,是ARP响应 print'[+]IP:%s=>MAC:%s'%(pdst,ans[ARP].hwsrc) deficmp_scan(self,dst): #ICMP发现扫描 ans=sr1(IP(dst=dst)/ICMP(),timeout=self.timeout,retry=self.retry,verbose=False) ifans: ifans[ICMP].type==0:#ICMPtype为0表示是ICMPecho-reply print'[+]IP:主机%secho-reply.'%dst tcp_info={} deftcp_scan(self,dst,port): #TCPSYN,发送TCPSYN包,有响应表示端口开放 ans,unans=sr(IP(dst=dst)/TCP(sport=RandShort(),dport=port,flags='S'), timeout=self.timeout,retry=self.retry,verbose=False) ifans.res: ifans.res[0][0][IP].dstnotinDiscovery_Scan.tcp_info: Discovery_Scan.tcp_info[ans.res[0][0][IP].dst]=True udp_info={} defudp_scan(self,dst,port): #UDP,发送UDP包,有响应表示端口开放 ans,uans=sr(IP(dst=dst)/UDP(sport=RandShort(),dport=port), timeout=self.timeout,retry=self.retry,verbose=False) ifans.res: ifans.res[0][0][IP].dstnotinDiscovery_Scan.udp_info: Discovery_Scan.udp_info[ans.res[0][0][IP].dst]=True classPort_Scan(object): ''' 说明:用于进行端口扫描,判断端口是否开放 ''' def__init__(self,args,timeout=0.5,retry=0): self.targets=parse_target(args) self.timeout=timeout self.retry=retry syn_port_dict={} defsyn_port_scan(self,dst,port): #TCPSYN端口扫描,若SYN包返回携带SYN、ACK(即TCP.flags=18)标志的包,则表明此端口打开。 ans,uans=sr(IP(dst=dst)/TCP(sport=RandShort(),dport=port,flags='S'), timeout=self.timeout,retry=self.retry,verbose=False) ifans: first_respons_pkt=ans.res[0][1] iffirst_respons_pkt[TCP]andfirst_respons_pkt[TCP].flags==18: iffirst_respons_pkt[IP].srcnotinPort_Scan.syn_port_dict: Port_Scan.syn_port_dict[first_respons_pkt[IP].src]=[first_respons_pkt[TCP].sport] else: Port_Scan.syn_port_dict[first_respons_pkt[IP].src].append(first_respons_pkt[TCP].sport) udp_port_dict={} defudp_port_scan(self,dst,port): #UDP端口扫描,若UDP端口返回ICMPport-unreachable,则表示端口打开。(排除某些主机对任何UDP端口的探测都响应为ICMPport-unrechable) ans,uans=sr(IP(dst=dst)/UDP(sport=RandShort(),dport=port), timeout=self.timeout,retry=self.retry,verbose=False) ifans.resandans.res[0][1].haslayer(UDPerror): first_respons_pkt=ans.res[0][1] iffirst_respons_pkt[IP].srcnotinPort_Scan.udp_port_dict: Port_Scan.udp_port_dict[first_respons_pkt[IP].src]=[first_respons_pkt[UDPerror].dport] else: Port_Scan.udp_port_dict[first_respons_pkt[IP].src].append(first_respons_pkt[UDPerror].dport) defparse_opt(): ''' @说明:通过argparse模块解析程序传入的参数 @return:args ''' usage='python%(prog)s<-pping扫描类型><-s端口发现类型>[-ttarget][--portports]' description='简单扫描工具,可以进行存活扫描及端口扫描.\n'\ '存活扫描包括:ARP扫描、ICMP扫描、TCP扫描、UDP扫描.\n'\ '端口扫描包括:TCPSYN扫描、TCPACK扫描、TCPFIN扫描.' epilog='以上做为说明,祝好运!' parser=argparse.ArgumentParser(usage=usage,description=description,epilog=epilog,version='v1.0') target_group=parser.add_argument_group('targetgroup',description='用于设置IP、PORT参数') target_group.add_argument('--target',dest='target',action='store', help='target为IP或IP段,如192.168.1.1,192.168.1.x,或192.168.1.1-254') target_group.add_argument('--port',dest='port',action='store', help='port为待扫描的端口,如21,80,...或21-80') ping_group=parser.add_argument_group('pinggroup',description='用于开启存活扫描相关选项') ping_group.add_argument('-p',dest='ping',action='store_true',help='开启存活扫描') ping_group.add_argument('--ARP',dest='ARP',action='store_true',help='启动ARP扫描') ping_group.add_argument('--ICMP',dest='ICMP',action='store_true',help='启动ICMP扫描') ping_group.add_argument('--TCP',dest='TCP',action='store_true',help='启动TCP扫描') ping_group.add_argument('--UDP',dest='UDP',action='store_true',help='启动UDP扫描') port_scan_group=parser.add_argument_group('portscangroup',description='用于开启端口扫描相关选项') port_scan_group.add_argument('-s',dest='scan',action='store_true',help='开启端口扫描') port_scan_group.add_argument('--SYN',dest='SYN',action='store_true',help='开启SYN扫描') port_scan_group.add_argument('--ACK',dest='ACK',action='store_true',help='开启ACK扫描') port_scan_group.add_argument('--FIN',dest='FIN',action='store_true',help='开启FIN扫描') port_scan_group.add_argument('--UPORT',dest='UPORT',action='store_true',help='开启UDP端口扫描') utils_group=parser.add_argument_group('utilsgroup',description='用于开启扫描过程中的一些实用选项') utils_group.add_argument('--timeout',dest='timeout',action='store',type=float,help='设置发包超时时间,默认0.5秒') utils_group.add_argument('--retry',dest='retry',action='store',type=int,help='设置发包重试次数,默认不重试') args=parser.parse_args() ifnotargs.pingandnotargs.scan: print'[-]必须通过-p/-s选项开启一种扫描' print'\n' parser.print_help() exit(1) elifnotargs.target: print'[-]必须通过--target选项指定扫描的对象' print'\n' parser.print_help() exit(1) ifargs.ping: ifnotargs.ARPandnotargs.ICMPandnotargs.TCPandnotargs.UDP: args.ICMP=True#若没有指定任何ping扫描方式,则默认选择ICMP扫描 print'[+]没有指定任何ping扫描方式,默认选择ICMP扫描' ifargs.scan: ifnotargs.SYNandnotargs.ACKandnotargs.FINandnotargs.UPORT: args.SYN=True#若没有指定任何端口扫描方式,则默认选择SYN扫描 print'[+]没有指定任何端口扫描方式,默认选择SYN扫描' ifnotargs.port: args.port='1-1024'#若没有指定任何扫描端口,则默认扫描1-1024 print'[+]没有指定任何扫描端口,默认扫描1-1024' returnargs defparse_target(args): ''' @说明:用于解析如'192.168.1.1,192.168.1.x,...或192.168.1.1-254'格式的IP为单独的IP,用于解析如'21,80,...或21-80'格式的端口为单独的端口 @param:args,一个namespace对象 @return:(ip_list,port_list) ''' pattern1=r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$' pattern2=r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}-\d{1,3}$' pattern3=r'\d{1,5}$' pattern4=r'\d{1,5}-\d{1,5}$' ip_list,port_list=None,None ifargs.target: ifre.search(pattern1,args.target): ip_list=args.target.split(',') elifre.match(pattern2,args.target): _split=args.target.split('-') first_ip=_split[0] ip_split=first_ip.split('.') ipdot4=range(int(ip_split[3]),int(_split[1])+1) ip_list=[ip_split[0]+'.'+ip_split[1]+'.'+ip_split[2]+'.'+str(p)forpinipdot4] else: print'[-]target格式输入有误,请查看帮助!' exit(1) ifargs.port: ifre.match(pattern4,args.port): _split=args.port.split('-') port_list=range(int(_split[0]),int(_split[1])+1) elifre.search(pattern3,args.port): port_list=args.port.split(',') else: print'[-]port格式输入有误,请查看帮助!' exit(1) returnip_list,port_list defmain(): ''' @说明:扫描的主程序,首先根据条件创建Ping扫描或端口扫描对象,然后调用相关的扫描方法进行扫描。 ''' args=parse_opt() ifargs.ping:#是否启动Ping扫描 ifnotargs.timeoutandnotargs.retry: obj_ping=Discovery_Scan(args) elifargs.timeoutandnotargs.retry: obj_ping=Discovery_Scan(args,timeout=args.timeout) elifnotargs.timeoutandargs.retry: obj_ping=Discovery_Scan(args,retry=args.retry) else: obj_ping=Discovery_Scan(args,args.timeout,args.retry) ip_list=obj_ping.targets[0] ifip_list: #ARP扫描 ifargs.ARP: forpdstinip_list: t=threading.Thread(target=obj_ping.arp_scan,args=(pdst,)) t.start() whilethreading.activeCount()!=1:#避免线程还没有运行完就提前输出不全的结果 time.sleep(1) #ICMP扫描 elifargs.ICMP: fordstinip_list: t=threading.Thread(target=obj_ping.icmp_scan,args=(dst,)) t.start() whilethreading.activeCount()!=1:#避免线程还没有运行完就提前输出不全的结果 time.sleep(1) #TCP扫描 elifargs.TCP: port_list=[80,443,21,22,23,25,53,135,139,137,445,1158,1433,1521,3306,3389,7001,8000,8080,9090] print'[+]请稍等,时间较长!' fordstinip_list: print'[!]扫描...',dst forportinport_list: t=threading.Thread(target=obj_ping.tcp_scan,args=(dst,port)) t.start() print'[+]正在处理扫描信息.' whilethreading.activeCount()!=1:#避免线程还没有运行完就提前输出不全的结果 time.sleep(1) ifnotobj_ping.tcp_info: print'\n' print'='*20 print'[+]未发现在线主机.' else: print'\n' print'='*20 forip_ainsorted(obj_ping.tcp_info.keys()): print'[+]主机%s在线.'%ip_a #UDP扫描 elifargs.UDP: port_list=[7,9.13,15,37,53,67,68,69,135,137,138,139,445,520] print'[+]请稍等,时间较长!' fordstinip_list: print'[!]扫描...',dst forportinport_list: t=threading.Thread(target=obj_ping.udp_scan,args=(dst,port)) t.start() print'[+]正在处理扫描信息.' whilethreading.activeCount()!=1:#避免线程还没有运行完就提前输出不全的结果 time.sleep(1) ifnotobj_ping.udp_info: print'\n' print'='*20 print'[+]未发现在线主机.' else: print'\n' print'='*20 forip_ainsorted(obj_ping.udp_info.keys()): print'[+]主机%s在线.'%ip_a ifargs.scan:#是否启动端口扫描 ifnotargs.timeoutandnotargs.retry: obj_port=Port_Scan(args) elifargs.timeoutandnotargs.retry: obj_port=Port_Scan(args,timeout=args.timeout) elifnotargs.timeoutandargs.retry: obj_port=Port_Scan(args,retry=args.retry) else: obj_port=Port_Scan(args,args.timeout,args.retry) ip_list,port_list=obj_port.targets ifip_listandport_list: ifargs.SYN: fordstinip_list: print'[!]扫描...',dst forportinport_list: t=threading.Thread(target=obj_port.syn_port_scan,args=(dst,int(port))) t.start() print'[+]正在处理扫描信息.' whilethreading.activeCount()!=1:#避免线程还没有运行完就提前输出不全的结果 time.sleep(1) ifnotobj_port.syn_port_dict: print'\n' print'='*20 print'[+]未发现开放TCP端口.' else: print'\n' print'='*20 fork,vinobj_port.syn_port_dict.items(): print'[+]主机%s开放的TCP端口有:%s'%(k,str(v)) elifargs.ACK: pass#基本不能使用 elifargs.FIN: pass#基本不能使用 elifargs.UPORT: fordstinip_list: print'[!]扫描...',dst forportinport_list: t=threading.Thread(target=obj_port.udp_port_scan,args=(dst,int(port))) t.start() print'[+]正在处理扫描信息.' whilethreading.activeCount()!=1:#避免线程还没有运行完就提前输出不全的结果 time.sleep(1) ifnotobj_port.udp_port_dict: print'\n' print'='*20 print'[+]未发现开放UDP端口.' else: print'\n' print'='*20 fork,vinobj_port.udp_port_dict.items(): print'[+]主机%s开放的UDP端口有:%s'%(k,str(v)) if__name__=='__main__': try: start_time=time.time() main() stop_time=time.time() print'[+]总共耗时'+str(stop_time-start_time)+'秒.' exceptException,e: print'[-]执行出错,具体错误见下面信息.' printe
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。