|
In scapy, you can use "/" to stack up the packets in different layers.
DNS packet construction: DNS and DNSQRAccording to the scapy documentation, the member variable qd for the question section is of type DNSQR. Here, QR stands for "Question Record".
Note:
In the lab, you need to spoof the answer section, which uses type
DNSRR
In the documentation:
Search for "DNS(", "DNSQR(", and "DNSRR("
sr1() functionFor sending and receving packets using functionsr1(), you can
check
this documentation for more detail.
|
$ sudo ./dns_pkt.py
##[ IP ]### ...(omitted)...
###[ DNS ]###
id = 0
qr = 0
opcode = QUERY
aa = 0
tc = 0
rd = 1
ra = 0
z = 0
ad = 0
cd = 0
rcode = ok
qdcount = 1
ancount = 0
nscount = 0
arcount = 0
\qd \
|###[ DNS Question Record ]###
| qname = 'en.wikipedia.org'
| qtype = A
| qclass = IN
an = None
ns = None
ar = None
Begin emission:
.Finished sending 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
###[ IP ]### ...(omitted)...
###[ DNS ]###
id = 0
qr = 1
opcode = QUERY
aa = 1
tc = 0
rd = 1
...(omitted)...
\qd \
|###[ DNS Question Record ]###
| qname = 'en.wikipedia.org.'
| qtype = A
| qclass = IN
\an \
|###[ DNS Resource Record ]###
| rrname = 'en.wikipedia.org.'
| type = CNAME
| rclass = IN
| ttl = 86400
| rdlen = None
| rdata = 'dyna.wikimedia.org.'
ns = None
ar = None
|
We will simulate ns1.wikimedia.org. Recall the dig result we saw:
$ dig @ns1.wikimedia.org en.wikipedia.org ; <<>> DiG 9.11.3-1ubuntu1.13-Ubuntu <<>> @ns1.wikimedia.org en.wikipedia.org ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27943 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 1024 ; COOKIE: 2db0c1bf9d498a555cbc370a3e8ec13b (good) ;; QUESTION SECTION: ;en.wikipedia.org. IN A ;; ANSWER SECTION: en.wikipedia.org. 86400 IN CNAME dyna.wikimedia.org. ;; Query time: 43 msec ;; SERVER: 208.80.153.231#53(208.80.153.231) ;; WHEN: Wed Jul 27 16:03:26 EDT 2022 ;; MSG SIZE rcvd: 94
In IT430, we learned how to create a UDP socket and receive packets.
We will not use the standard DNS port 53; instead, we will use 3000.
Note that pkt in the above contains a DNS message.
Therefore, we can construct a scapy DNS object from pkt as follows:
Now, let's run a dig command.
dig @127.0.0.1 -p 3000 en.wikipedia.orgNote -p option is used to specifiy the special port 3000 that our name server uses. The result is shown on the right. |
$ sudo ./dns_server.py
###[ DNS ]###
id = 42534
qr = 0
opcode = QUERY
...(omitted)...
nscount = 0
arcount = 1
\qd \
|###[ DNS Question Record ]###
| qname = 'en.wikipedia.org.'
| qtype = A
| qclass = IN
an = None
ns = None
\ar \
|###[ DNS OPT Resource Record ]###
| rrname = '.'
| type = OPT
| rclass = 4096
| extrcode = 0
| version = 0
| z = 0
| rdlen = None
| \rdata \
| |###[ DNS EDNS0 TLV ]###
| | optcode = 10
| | optlen = 8
| | optdata = '5\x9deP\x82e\xa2A'
|
For the question section, we can simply copy the question section from the request packet (req.qd)
ans_qd = req.qd
For the answer section, we need more work. First, we need to use
DNSRR (reponse record) class for this section.
class scapy.layers.dns.DNSRR(_pkt, /, *, rrname=b'.', type=1, rclass=1, ttl=0, rdlen=None, rdata=None)
Recall we need to reply with something like the following:
en.wikipedia.org. 86400 IN CNAME dyna.wikimedia.org.
en.wikipedia.org. corresponds to rrname
(response recorde name).
CNAME is type.
dyna.wikimedia.org. is rdata (response data).
ans_an = DNSRR( rrname = "en.wikipedia.org", ttl=86400, type="CNAME", rdata="dyna.wikimedia.org")
class scapy.layers.dns.DNS(_pkt, /, *, length=None, id=0, qr=0, opcode=0, aa=0, tc=0, rd=1, ra=0, z=0, ad=0, cd=0,
rcode=0, qdcount=None, ancount=None, nscount=None, arcount=None, qd=DNSQR(), an=None, ns=None, ar=None)
For the most parts, we can just use the default values except for the fields
important to us:
id: That is the DNS packet identifier. We need to use the
same id that the query packet uses.
qr: This boolean value tells whether it's the packet is
a query (qr=0 or answer (qr=1).
aa: This boolean value tells whether it's an
authoritative answer. Although it's not, we will just pretend
that our reply comes from the official DNS server for the wikipedia domain.
qdcount=1) and the answer section (ancount=1).
Likewise, we need to set the data for these sections as well.
ans = DNS( id = req.id, qr=1, aa=1, qdcount=1, ancount=1, qd=ans_qd, an=ans_an)
#!/usr/bin/python3
# dns_server.py
from scapy.all import *
from socket import *
sock = socket(AF_INET, SOCK_DGRAM)
sock.bind( ("0.0.0.0", 3000) )
pkt, addr = sock.recvfrom(4096)
req = DNS(pkt)
# construct the DNS reply
# -- question section
ans_qd = req.qd
# -- answer section
ans_an = DNSRR( rrname = "en.wikipedia.org", ttl=86400, type="CNAME", rdata="dyna.wikimedia.org")
# DNS reply packet
ans = DNS( id = req.id, qr=1, aa=1, qdcount=1, ancount=1, qd=ans_qd, an=ans_an)
# send the reply back
sock.sendto(bytes(ans), addr)
Here are the resuts:
$ dig @127.0.0.1 -p 3000 en.wikipedia.org
; <<>> DiG 9.16.1-Ubuntu <<>> @127.0.0.1 -p 3000 en.wikipedia.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37357
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available
;; QUESTION SECTION:
;en.wikipedia.org. IN A
;; ANSWER SECTION:
en.wikipedia.org. 86400 IN CNAME dyna.wikimedia.org.
;; Query time: 11 msec
;; SERVER: 127.0.0.1#3000(127.0.0.1)
;; WHEN: Thu Aug 04 19:26:07 EDT 2022
;; MSG SIZE rcvd: 83
Against an attacker who is on the path of the DNS query sequence (usually called an "on-path" attacker), DNS is completely insecure. Since everything is sent over plaintext, attacker can read the request, construct a malicious response message with malicious records and the correct ID field, and race to send the malicious reply before the legitimate response.
The DNS spoofing proceeds as follows:
In the above picture, if the user is changed to the local DNS server, the cache of the local DNS server will be poisoned. If the time-to-live (TTL) of the malicious records is set to a very high number, then the local DNS server (i.e., the victim) will cache those malicous records for a very long time. Now, for all subsequent DNS queries, this DNS server will give wrong answers based on the poisoned cache.
There were some more subtle attacks that uses the additional section to poison
the cache with malicious IP addresses. Suppose that there is a DNS server that
handles the zone for *.real-website.com.
www.google.com
with an attacker-owned IP address 123.123.123.123.
$ dig @192.176.10.30 www.real-website.come
...
;; ADDITIONAL SECTION:
www.real-website.com 172800 IN A 192.176.10.31
www.google.com 999999 IN A 123.123.123.123
...
If the querier is implemented to believe whatever information from a DNS response packet, this attack will be successful.
In a Pharming attack, the adversary install malicious code in a DNS server to misdirect users to fraudulent websites without their knowledge or consent.
This can be done by exploiting vulnerabilities in the DNS protocol or by compromising insecure DNS servers and adding entries that redirect traffic. By causing the DNS server to give the user the incorrect answer, the pharmer can send users to a fake site for a malicious purpose.
