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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。