DNS-запрос с использованием TCP с использованием scapy - PullRequest
0 голосов
/ 04 июля 2018

Хотел отправить DNS-запрос в TCP и получить его ответ. Ответ, который я получаю от имен, кажется ... неполным.

Ниже приведен код, который я написал для этого:

#!/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-запрос, ответ, очевидно, присутствует в ответном пакете.

Как визуализировать действительный ответ DNS от пакета ответа TCP?

Редактировать 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:

Предотвращение RST, как я узнал из этой страницы:

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

Я вижу, что DNS-сервер отвечает в моем ngrep при выполнении следующего кода:

#!/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()

Однако я все еще не вижу связанных с DNS вещей в DNSReply:

(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 голосов
/ 04 июля 2018

Используя последний выпуск 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 в стек ОС.

...