lost and found ( for me ? )

craft DNS responses with python scapy

Here is sample scapy scripts of how to craft DNS responses.

Reference

I have confirmed that I can run the following scripts with python-scapy 2.2.0-1.
# dpkg -l python-scapy | tail -1
ii  python-scapy                    2.2.0-1                          all          Packet generator/sniffer and network scanner/discovery


1. return answer responses

# cat scapy_dns_answer_res.py -n
    1 from scapy.all import *
    2
    3 def dns_spoof(pkt):
    4    if pkt.haslayer(DNSQR):
    5        spoofed_pkt = IP(dst=pkt[IP].src, src=pkt[IP].dst)/\
    6                      UDP(dport=pkt[UDP].sport, sport=pkt[UDP].dport)/\
    7                      DNS(id=pkt[DNS].id, qd=pkt[DNS].qd, aa=1, qr=1, \
    8                      an=DNSRR(rrname=pkt[DNS].qd.qname, ttl=100, rdata='1.1.1.1'))
    9        send(spoofed_pkt)
   10 sniff(filter='udp and dst port 53', iface='eth0', store=0, prn=dns_spoof)

run the script
# python scapy_dns_answer_res.py
WARNING: No route found for IPv6 destination :: (no default route?)

send DNS queries
# dig @10.0.3.150 www.foo.bar.example.com.

; <<>> DiG 9.9.5-3ubuntu0.7-Ubuntu <<>> @10.0.3.150 www.foo.bar.example.com.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64819
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;www.foo.bar.example.com. IN A

;; ANSWER SECTION:
www.foo.bar.example.com. 100 IN A 1.1.1.1




2. return referral responses

This returns referral responses.
# cat -n send_referral_dns_responses.py
    1 from scapy.all import *
    2
    3 ttl=3
    4
    5 def dns_res(pkt):
    6       if pkt.haslayer(DNSQR):
    7           domain = ''
    8           query_string = pkt[DNS].qd.qname
    9           query_list = query_string.split('.')
   10 #           print query_list
   11           for i in query_list[1:-1]:
   12               domain += i + '.'
   13 #           print domain
   14           spoofed_pkt = IP(dst=pkt[IP].src, src=pkt[IP].dst)/\
   15                      UDP(dport=pkt[UDP].sport, sport=pkt[UDP].dport)/\
   16                      DNS(id=pkt[DNS].id, qd=pkt[DNS].qd, qr=1L, aa=0L, tc=0L, rd=0L, ra=1L, z=0L,\
   17                           qdcount=1, ancount=0, nscount=2, arcount=2,\
   18                      an=None,\
   19                      ns=(DNSRR(rrname=domain,type='NS',ttl=ttl,rdata='ns1.'+domain)\
   20                          /DNSRR(rrname=domain,type='NS',ttl=ttl,rdata='ns2.'+domain)\
   21                         ),\
   22                      ar=(DNSRR(rrname='ns1.'+domain,type='A',ttl=ttl,rdata='1.1.1.1')\
   23                         /DNSRR(rrname='ns2.'+domain,type='A',ttl=ttl,rdata='2.2.2.2')\
   24                         ),\
   25                     )
   26           send(spoofed_pkt)
   27
   28 sniff(filter='udp and dst port 53', iface='eth0', store=0, prn=dns_res)

run the script.
# python send_referral_dns_responses.py
WARNING: No route found for IPv6 destination :: (no default route?)

got referral responses.
# dig @10.0.3.150 www.foo.com.                  

; <<>> DiG 9.9.5-3ubuntu0.7-Ubuntu <<>> @10.0.3.150 www.foo.com.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29221
;; flags: qr ra; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 2

;; QUESTION SECTION:
;www.foo.com. IN A

;; AUTHORITY SECTION:
foo.com. 3 IN NS ns1.foo.com.
foo.com. 3 IN NS ns2.foo.com.

;; ADDITIONAL SECTION:
ns1.foo.com. 3 IN A 1.1.1.1
ns2.foo.com. 3 IN A 2.2.2.2

got referral responses.
# dig @10.0.3.150 www.a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com

; <<>> DiG 9.9.5-3ubuntu0.7-Ubuntu <<>> @10.0.3.150 www.a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16078
;; flags: qr ra; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 2

;; QUESTION SECTION:
;www.a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com. IN A

;; AUTHORITY SECTION:
a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com. 3 IN NS ns1.a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com.
a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com. 3 IN NS ns2.a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com.

;; ADDITIONAL SECTION:
ns1.a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com. 3 IN A 1.1.1.1
ns2.a.b.c.d.e.f.g.h.i.j.k.l.m.n.foo.bar.example.com. 3 IN A 2.2.2.2

3. return mismatch TXID

pick up random int from 0 to 10000 and use that as TXID.
# cat -n scapy_dns_answer_res_mismatch_txid.py
    1 from scapy.all import *
    2 import random
    3
    4 def dns_spoof(pkt):
    5    if pkt.haslayer(DNSQR):
    6        spoofed_pkt = IP(dst=pkt[IP].src, src=pkt[IP].dst)/\
    7                      UDP(dport=pkt[UDP].sport, sport=pkt[UDP].dport)/\
    8                      DNS(id=random.randint(0,10000), qd=pkt[DNS].qd, aa=1, qr=1, \
    9                      an=DNSRR(rrname=pkt[DNS].qd.qname, ttl=100, rdata='1.1.1.1'))
   10        send(spoofed_pkt)
   11 sniff(filter='udp and dst port 53', iface='eth0', store=0, prn=dns_spoof)

# dig @10.0.3.150 www.hello.com
;; Warning: ID mismatch: expected ID 36459, got 3149
;; Warning: ID mismatch: expected ID 36459, got 8024
;; Warning: ID mismatch: expected ID 36459, got 6544


; <<>> DiG 9.9.5-3ubuntu0.7-Ubuntu <<>> @10.0.3.150 www.hello.com
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.