Python Forum
Sending DNS responses with python - research
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Sending DNS responses with python - research
#1
Hi,
I am researching DNS and i am attempting to write/modify a small DNS server application written in python to see if it is possible to send special characters and non-digits in the DNS A response, i will then use dig from my local machine to see if i can map a domain name to a corrupted IP address such as '123%^&*(^'.
I understand this may not be possible as RFC say that the field must be a 32 bit numeric integer, however i would like to build a proof of concept script to test and demonstrate.
I have found a small DNS server script online that sucessfully returns a user supplied IP address for any domain that is requested:
import socket

class DNSQuery:
  def __init__(self, data):
    self.data=data
    self.dominio=''

    tipo = (ord(data[2]) >> 3) & 15   # Opcode bits
    if tipo == 0:                     # Standard query
      ini=12
      lon=ord(data[ini])
      while lon != 0:
        self.dominio+=data[ini+1:ini+lon+1]+'.'
        ini+=lon+1
        lon=ord(data[ini])

  def respuesta(self, ip):
    packet=''
    if self.dominio:
      packet+=self.data[:2] + "\x81\x80"
      packet+=self.data[4:6] + self.data[4:6] + '\x00\x00\x00\x00'   # Questions and Answers Counts
      packet+=self.data[12:]                                         # Original Domain Name Question
      packet+='\xc0\x0c'                                             # Pointer to domain name
      packet+='\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04'             # Response type, ttl and resource data length -> 4 bytes
      packet+=str.join('',map(lambda x: str(str(x)), ip.split('-'))) # 4bytes of IP
    return packet

if __name__ == '__main__':
  ip='192.168.1.1'
  print 'pyminifakeDNS:: dom.query. 60 IN A %s' % ip

  udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  udps.bind(('',53))

  try:
    while 1:
      data, addr = udps.recvfrom(1024)
      p=DNSQuery(data)
      udps.sendto(p.respuesta(ip), addr)
      print 'Respuesta: %s -> %s' % (p.dominio, ip)
  except KeyboardInterrupt:
    print 'Finalizando'
    udps.close()
I need to modify the packet section to accept all characters, and remove the IP split function, i havee changed the chr/int to str/str as below

  def respuesta(self, ip):
    packet=''
    if self.dominio:
      packet+=self.data[:2] + "\x81\x80"
      packet+=self.data[4:6] + self.data[4:6] + '\x00\x00\x00\x00'   # Questions and Answers Counts
      packet+=self.data[12:]                                         # Original Domain Name Question
      packet+='\xc0\x0c'                                             # Pointer to domain name
      packet+='\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04'             # Response type, ttl and resource data length -> 4 bytes
      packet+=str.join('',map(lambda x: str(str(x)), ip.split('-'))) # 4bytes of IP
    return packet
I am attempting to send the following DNS response with the A name record as
Quote: test123^&*^

so the script looks like this:
import socket

class DNSQuery:
  def __init__(self, data):
    self.data=data
    self.dominio=''

    tipo = (ord(data[2]) >> 3) & 15   # Opcode bits
    if tipo == 0:                     # Standard query
      ini=12
      lon=ord(data[ini])
      while lon != 0:
        self.dominio+=data[ini+1:ini+lon+1]+'.'
        ini+=lon+1
        lon=ord(data[ini])

  def respuesta(self, ip):
    packet=''
    if self.dominio:
      packet+=self.data[:2] + "\x81\x80"
      packet+=self.data[4:6] + self.data[4:6] + '\x00\x00\x00\x00'   # Questions and Answers Counts
      packet+=self.data[12:]                                         # Original Domain Name Question
      packet+='\xc0\x0c'                                             # Pointer to domain name
      packet+='\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04'             # Response type, ttl and resource data length -> 4 bytes
      packet+=str.join('',map(lambda x: str(str(x)), ip.split('-'))) # 4bytes of IP
    return packet

if __name__ == '__main__':
  ip='test123^&*^'
  print 'pyminifakeDNS:: dom.query. 60 IN A %s' % ip

  udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  udps.bind(('',53))

  try:
    while 1:
      data, addr = udps.recvfrom(1024)
      p=DNSQuery(data)
      udps.sendto(p.respuesta(ip), addr)
      print 'Respuesta: %s -> %s' % (p.dominio, ip)
  except KeyboardInterrupt:
    print 'Finalizando'
    udps.close()
The script executes and waits for the DNS request:
Quote:pyminifakeDNS:: dom.query. 60 IN A test123^&*^

When i make the request from my local machine the script shows that it has sent the payload:
Quote:Respuesta: google.com. -> test123^&*^

But when i look at my nslookup request and response from my host it shows that the A record has been mapped to a random IP address i have no idea where this has came from:
Quote:nslookup google.com myserver
Server: myserver
Address: myserver.49#53

Non-authoritative answer:
Name: google.com
Address: 116.101.115.116

Additionally when i run it with dig with different payloads instead of an IP address i receive the following:
Quote:; <<>> DiG 9.10.3-P4-Ubuntu <<>> @myserver google.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32328
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: Message has 61 extra bytes at end

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;google.com. IN A

;; Query time: 15 msec
;; SERVER: 159.65.87.49#53(159.65.87.49)
;; WHEN: Sun Aug 05 12:51:28 BST 2018
;; MSG SIZE rcvd: 100

When i change the size of the IP address field in the script, the MSG sizes changes in proportion with the length of the payload,so it would suggest that the corrupt response is being received, however something strange is happening, maybe the corrupt IP address is being inserted into a different parameter of the dns response other then the A name?

Wireshark also shows that the response has been received however i can not find the corrupted IP address anywhere in the DNS response packet.

So, I am guessing the IP split function has something to do with this, i am new with python and not sure how to remove it or what to replace it with, can anybody shed some light on this?

any idea why when i run nslookup on the modified script i receive a random IP address each time? ( currently receiving an IP from vietnam).

What other modifications do i need to make in the script so it sends any characters in the IP parameter?


Thanks in advance
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Python + PHP. Sending data from "Moodle" (php) to python CGI-script and get it back stanislav 0 1,527 May-07-2022, 10:32 AM
Last Post: stanislav
  Threading with python in sending multiple commands? searching1 0 3,992 Jun-12-2019, 09:13 PM
Last Post: searching1
  How to run local python script to remote machine without sending krishna1989 1 8,330 Feb-21-2019, 05:18 PM
Last Post: marienbad
  sending email with python shahpy 4 14,135 Oct-03-2016, 10:00 PM
Last Post: shahpy

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020