Python是一门很好的用来编写渗透脚本的语言,拥有很多成熟的库,我们可以直接拿来使用。我们今天来看一下如何用python实现一个简单的Zamp扫描器。
zmap扫描器由Durumeric领导密歇根大学研究团队开发,扫描速度很快,可以在45分钟内扫描全网IPV4地址。
这种扫描的原理就是不进行三次握手,而是只发送SYN,随后发送RST,清空连接,再继续发送下一个数据包。那怎么知道对应端口是否开发呢?有一个专门的收包模块来识别收到的包。在这里Zmap将ip地址和port做了一个映射并保存,如果收到的数据包验证后能映射到我们已发包的ip地址和port,就说明该主机的该端口是开放的。
实验环境
kali linux 2.0
实现
我们在这里只是简单的实现,并不做这样的映射。首先我们分成两个模块,一个是收包模块,一个是发包模块。
发包模块
这里我们使用kali linux中的scapy,扫描端口、网卡、子网是自己根据自己情况写好的,定义了一个发包函数,函数中对IP地址生成的子网地址做一个遍历。对每个地址的对应端口发送SYN包和RST包。本地发送的端口我们选择一个基本不被别的进程占用的高端口,防止干扰。发送结束就自动结束运行。
from scapy.all import *
from netaddr import IPNetwork
iface = 'eth0' #网卡
portlist = [80,8080] #端口列表
source = '192.168.38.168' #本机ip
subnet = '192.168.38.0/24' #目标子网
def package_send(): #发包函数
print "Start Port Scannering*********************"
for ip in IPNetwork(subnet): #遍历子网IP
print "[-] Scannering :",ip
for port in portlist:#遍历端口列表
send(IP(src=source,dst=str(ip))/TCP(sport=50000,dport=port,flags=2),verbose=0) #发送syn包
send(IP(src=source,dst=str(ip))/TCP(sport=50000,dport=port,flags=4),verbose=0) #发送rst包
exit(0)退出
package_send()
收包模块
收包模块这里我们定义一个收包函数叫做package_sniffer,在这里先对包进行一个判断,我们只接受第四层为tcp,且目的主机是本机,而且标志位是SYN+ACK的数据包,并且将它交给deal函数处理,deal函数再判断IP地址是否在我们定义的子网中,在的话就打印出来包的地址和源端口,表示其开放。
from scapy.all import *
from netaddr import IPNetwork, IPAddress
iface = 'eth0'
portlist = [80,8080]
source = '192.168.38.168'
subnet = '192.168.38.0/24'
def deal(data):
if data[IP].src in IPNetwork(subnet):# 如果包源IP在子网里,就处理
print "Port open host:%s, port:%s"%(data[IP].src, data[TCP].sport)
def package_sniffer():
while True: #循环嗅探
sniff(iface=iface, filter="tcp and dst %s and tcp[13:1] & 18 == 18"%source, prn=deal) #嗅探iface网卡,过滤规则是第四层为tcp,且目的主机是本机,而且标志位是SYN+ACK,将收到的数据包交给deal函数处理
package_sniffer()
最终版本
最后我们将发包和收包模块使用线程结合起来。并且使用argparse模块添加一些命令行参数。在命令行中使用./ZmapScanner.py -i eth0 -H 192.168.1.0/24指定网卡和IP子网即可。
#!/usr/bin/python
from scapy.all import *
from netaddr import IPNetwork #用于划分子网
import threading
import time
import argparse
import sys
subnet = ""
portlist = [80,8080] #端口列表
source = '192.168.38.168' #源主机
def package_send():
for ip in IPNetwork(subnet):#遍历子网IP
print "[-] Scannering :",ip
for port in portlist: #遍历端口
send(IP(src=source,dst=str(ip))/TCP(sport=50000,dport=port,flags=2),verbose=0) #发送SYN包,且不显示详细信息
send(IP(src=source,dst=str(ip))/TCP(sport=50000,dport=port,flags=4),verbose=0) #发送RST包,且不显示详细信息
exit(0)
def deal(data): #数据处理函数
if data[IP].src in IPNetwork(subnet): #如果包的源IP在子网里,就处理
print "[+] Port open host:%s, port:%s"%(data[IP].src, data[TCP].sport)
def package_sniffer(iface): #嗅探函数
while True:
#嗅探iface网卡,过滤规则是第四层为tcp,且目的主机是本机,而且标志位是SYN+ACK,将收到的数据包交给deal函数处理
sniff(iface=iface, filter="tcp and dst %s and tcp[13:1] & 18 == 18"%source, prn=deal)
def main():
global subnet
parser = argparse.ArgumentParser(prog="./ZmapScanner.py", description="This program is used to scanner 80/8080 port open. Usage: ./ZmapScanner.py -i eth0 -H 192.168.1.0/24") #添加程序运行的提示
parser.add_argument('-i', dest="interface", help="select interface such as eth0", type=str) #定制网卡
parser.add_argument('-H', dest="host", help="select hosts such as 192.168.1.0/24", type=str) #定制子网
option, args = parser.parse_known_args() #得到命令行参数
iface = option.interface
addr = option.host
if iface == None or addr == None: #如果输入不符合规则,就提示退出
parser.print_help()
sys.exit(0)
subnet = addr #赋值子网
sniffer_thread = threading.Thread(target=package_sniffer, args=(iface,)) #新建嗅探线程
sniffer_thread.start()
print "Start Port Scannering*********************"
send_thread = threading.Thread(target=package_send) #新建发包线程
send_thread.start()
main()