使用Scapy使用TCP的DNS请求

时间:2018-07-04 01:50:57

标签: python-3.x sockets scapy

想在TCP中发送DNS请求,并接收其响应。我从命名者那里收到的回复似乎..不完整。

下面是我为此编写的代码:

#!/usr/bin/python3

import socket
from scapy.all import *

def main():
        ip = IP(dst="8.8.8.8")
        request = DNS(rd=1, qd=DNSQR(qname = "cnn.com", qtype="A")) # size = 25, hex = 0x19
        twoBytesRequestSize = "\x00\x19" #BIG ENDIAN
        completeRequest = str(request) + twoBytesRequestSize
        # Create TCP Packet with SYN
        SYN = ip/TCP(sport=RandNum(1024,65535), dport=53, flags="S", seq = 32)
        # Send the crafted packet, and get SYN ACK from the other end
        SYNACK = sr1(SYN)
        # We, the client need to send ACK for the server's SYN
        ACK = ip/TCP(sport=SYNACK.dport, dport=53, flags="A", seq=SYNACK.ack, ack = SYNACK.seq +1)
        send(ACK)

        # send the request, and
        DNSREQUEST = ip/TCP(sport=SYNACK.dport, dport=53, flags="PA", seq=SYNACK.ack, ack = SYNACK.seq +1) / completeRequest
        DNSREQUEST.show2()
        DNSREPLY = sr1(DNSREQUEST, timeout=3)

        DNSREPLY.show2()
        #import pdb; pdb.set_trace()

if __name__ == "__main__":
        main()

这是我们发送的, DNSREQUEST.show2():

###[ IP ]###
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 127
  id        = 1
  flags     =
  frag      = 0
  ttl       = 64
  proto     = tcp
  chksum    = 0xa7f8
  src       = 192.168.1.200
  dst       = 8.8.8.8
  \options   \
###[ TCP ]###
     sport     = 45597
     dport     = domain
     seq       = 33
     ack       = 3264934925
     dataofs   = 5
     reserved  = 0
     flags     = PA
     window    = 8192
     chksum    = 0xe104
     urgptr    = 0
     options   = []
###[ DNS ]###
        length    = 25127
        id        = 23672
        qr        = 0
        opcode    = 6
        aa        = 0
        tc        = 0
        rd        = 0
        ra        = 0
        z         = 0
        ad        = 1
        cd        = 1
        rcode     = ok
        qdcount   = 23672
        ancount   = 12336
        nscount   = 23672
        arcount   = 12337
        qd        = ''
        an        = ''
        ns        = ''
        ar        = ''
###[ Raw ]###
           load      = "\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x03cnn\\x03com\\x00\\x00\\x01\\x00\\x01'\x00\x19"

我们得到了, 回复:

Received 51 packets, got 1 answers, remaining 0 packets
###[ IP ]###
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 40
  id        = 51159
  flags     =
  frag      = 0
  ttl       = 57
  proto     = tcp
  chksum    = 0xe778
  src       = 8.8.8.8
  dst       = 192.168.1.200
  \options   \
###[ TCP ]###
     sport     = domain
     dport     = 45597
     seq       = 3264934925
     ack       = 0
     dataofs   = 5
     reserved  = 0
     flags     = R
     window    = 0
     chksum    = 0x7465
     urgptr    = 0
     options   = []
###[ Padding ]###
        load      = '\x00\x00\x13\xa9\xa3\x11'

虽然不确定它是否正在工作,或者我没有从中提取DNS响应。我们收到的DNS回复中应该包含更多内容,不是吗?我什至不知道此查询是否成功-我们发送的字节数超过了我们收到的回复:

(Pdb) len(DNSREQUEST)
127
(Pdb) len(DNSREPLY)
46
(Pdb)

(Pdb) DNSREPLY
<IP  version=4 ihl=5 tos=0x0 len=40 id=46137 flags= frag=0 ttl=58 proto=tcp chksum=0xfa16 src=8.8.8.8 dst=192.168.1.200 options=[] |<TCP  sport=domain dport=11225 seq=1761828349 ack=0 dataofs=5 reserved=0 flags=R window=0 chksum=0xea51 urgptr=0 |<Padding  load='\x00\x00\x813\x8d\xd2' |>>>

如果它是UDP查询,则答案显然在答复数据包中。

如何从TCP响应数据包中可视化有效的DNS响应?

编辑1

#!/usr/bin/python3

import socket
from scapy.all import *

def main():
        ip = IP(dst="8.8.8.8")
        request = DNS(rd=1, qd=DNSQR(qname = "cnn.com", qtype="A")) # size = 25, hex = 0x19
        # Create TCP Packet with SYN
        SYN = ip/TCP(sport=RandNum(1024,65535), dport=53, flags="S", seq = 32)
        # Send the crafted packet, and get SYN ACK from the other end
        SYNACK = sr1(SYN)
        # We, the client need to send ACK for the server's SYN
        ACK = ip/TCP(sport=SYNACK.dport, dport=53, flags="A", seq=SYNACK.ack, ack = SYNACK.seq +1)
        send(ACK)

        # send the request, and
        DNSREQUEST = ip/TCP(sport=SYNACK.dport, dport=53, flags="PA", seq=SYNACK.ack, ack = SYNACK.seq +1) / request

        _, answers = sr(DNSREQUEST, timeout=3, multi=1)
        import pdb; pdb.set_trace()

if __name__ == "__main__":
        main()

编辑2:

this页面上了解到的预防RST:

iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

运行以下代码时,我看到ngrep中的DNS服务器响应:

#!/usr/bin/python3
from scapy.all import *

ip=IP(dst="8.8.8.8")

request = DNS(rd=1, qd=DNSQR(qname = "cnn.com", qtype="TXT")) #size = 27(dec) = 1b (hex)
twoBytesRequestSize = "\x00\x1b" #BIG ENDIAN
completeRequest = str(request) + twoBytesRequestSize

SYN=ip/TCP(sport=RandNum(1024,65535), dport=53, flags="S", seq=42)
SYNACK=sr1(SYN)

ACK=ip/TCP(sport=SYNACK.dport, dport=53, flags="A", seq=SYNACK.ack, ack=SYNACK.seq + 1)
send(ACK)

DNSRequest = ip/TCP(sport=SYNACK.dport, dport=53, flags="PA", seq=SYNACK.ack, ack=SYNACK.seq + 1) / completeRequest
#DNSReply = sr1(DNSRequest, timeout = 1)
DNSReply = sr1(DNSRequest, timeout = 1, multi=1)
import pdb; pdb.set_trace()

但是,我仍然没有在DNSReply中看到与DNS相关的内容:

(Pdb) DNSReply.show2()
###[ IP ]### 
  version   = 4
  ihl       = 5
  tos       = 0x0
  len       = 40
  id        = 36387
  flags     = 
  frag      = 0
  ttl       = 120
  proto     = tcp
  chksum    = 0xe22c
  src       = 8.8.8.8
  dst       = 192.168.1.200
  \options   \
###[ TCP ]### 
     sport     = domain
     dport     = 2466
     seq       = 3994942779
     ack       = 130
     dataofs   = 5
     reserved  = 0
     flags     = A
     window    = 28640
     chksum    = 0x77c1
     urgptr    = 0
     options   = []
###[ Padding ]### 
        load      = '\x00\x00^\x97\xf94'

我在这里想念什么?

1 个答案:

答案 0 :(得分:2)

使用Scapy的最新版本(2.4.0),您无需在DNS层的开头添加长度,因为它将自动添加。

您的代码不起作用,因为您在得到答案之前会收到一个普通的ACK数据包(无数据)。

这里的一个选项是使用sr([...], multi=1)。您可以在代码中尝试类似的方法:

    answers, _ = sr(DNSREQUEST, timeout=3, multi=1)
    DNSREPLY = answers[DNS][0]

此外,像往常一样,在使用TCP和Scapy时,您需要确保您的操作系统堆栈不会干扰您的数据包(通常,它会以重置数据包的形式回复您收到的syn + ack数据包) 。通常的方法是使用防火墙来防止syn + ack数据包到达操作系统堆栈。