mike01 / pypacker

:package: The fastest and simplest packet manipulation lib for Python
GNU General Public License v2.0
251 stars 46 forks source link

struct.error when unpacking DNS #13

Closed jimbo1023 closed 9 years ago

jimbo1023 commented 9 years ago

Came across an error when messing with the dns module. For some reason, it seems to trip on certain packets and throw a struct.error. struct.error: unpack requires a bytes object of length 442

I'm running it on the smbtorture.cap file here

For the full context, here is the code I'm running, or trying to run. It works fine on other pcap files. (sorry for the lack of comments, this was just a quick and dirty script)

import pcapy
from pypacker.pypacker import dns_name_decode
from pypacker.layer12 import ethernet
from pypacker.layer567 import dns
import os
from socket import inet_ntop, AF_INET, AF_INET6

# https://wiki.wireshark.org/SampleCaptures#General_.2F_Unsorted
#PCAPFILE = os.path.join(os.environ['HOME'], "pcap", "SkypeIRC.cap")
# https://wiki.wireshark.org/SampleCaptures#Server_Message_Block_.28SMB.29.2FCommon_Internet_File_System_.28CIFS.29
PCAPFILE = os.path.join(os.environ['HOME'], "pcap", "smbtorture.cap")
BPF = "port 53"

capture = pcapy.open_offline(PCAPFILE)
capture.setfilter(BPF)

while True:
    try:
        header, packet = capture.next()
    except pcapy.PcapError:
        break

    pkt = ethernet.Ethernet(packet)
    dnsP = pkt.highest_layer
    if not isinstance(dnsP, dns.DNS):
        continue

    print("{0:016b}".format(dnsP.flags))
    qr_flag = dnsP.flags >> 15
    if qr_flag == dns.DNS_Q:
        for query in dnsP.queries:
            print(dnsP.id, "query", query.name_s)
    else: #if qr_flag == dns.DNS_A:
        if not dnsP.answers:
            print(dnsP.id, "response", None)
            continue
        for answer in dnsP.answers:
            if answer.type == dns.DNS_A:
                print(dnsP.id, "response", "A", inet_ntop(AF_INET, answer.address))
            elif answer.type == dns.DNS_AAAA:
                print(dnsP.id, "response", "AAAA", inet_ntop(AF_INET6, answer.address))
            elif answer.type == dns.DNS_CNAME:
                # decoding name doesn't always work if it has \xc0 pointers
                print(dnsP.id, "response", "CNAME", repr(dns_name_decode(answer.address)))
            elif answer.type == dns.DNS_PTR:
                print(dnsP.id, "response", "PTR", repr(dns_name_decode(answer.address)))
            else:
                print(dnsP.id, "response", "OTHER", repr(answer.address))

The full output, including the exception traceback:

> python3 ~/Python/quick_dns_test.py
0000000100000000
22185 query time.windows.com.
1000000110000000
22185 response None
0000000100000000
53928 query time.windows.com.localdomain.
1000000110000011
53928 response None
0000000100000000
427 query time.windows.com.
Traceback (most recent call last):
  File "/home/user/Python/quick_dns_test.py", line 30, in <module>
    print("{0:016b}".format(dnsP.flags))
  File "/home/user/python3/lib/python3.4/site-packages/pypacker/pypacker.py", line 135, in getfield_simple
    obj._unpack()
  File "/home/user/python3/lib/python3.4/site-packages/pypacker/pypacker.py", line 776, in _unpack
    header_unpacked = self._header_format.unpack(self._header_cached)
struct.error: unpack requires a bytes object of length 442

And for even more completion, here is the tcpdump output, suggesting to me that at least the packets aren't completely malformed:

> tcpdump -nnr ~/pcap/smbtorture.cap port 53
reading from file /home/user/pcap/smbtorture.cap, link-type EN10MB (Ethernet)
23:38:26.418664 IP 192.168.114.129.49157 > 192.168.114.1.53: 22185+ AAAA? time.windows.com. (34)
23:38:27.261990 IP 192.168.114.1.53 > 192.168.114.129.49157: 22185 0/1/0 (102)
23:38:27.268868 IP 192.168.114.129.49157 > 192.168.114.1.53: 53928+ AAAA? time.windows.com.localdomain. (46)
23:38:27.471756 IP 192.168.114.1.53 > 192.168.114.129.49157: 53928 NXDomain 0/1/0 (121)
23:38:27.563782 IP 192.168.114.129.49157 > 192.168.114.1.53: 427+ A? time.windows.com. (34)
23:38:27.743738 IP 192.168.114.1.53 > 192.168.114.129.49157: 427 1/5/5 A 207.46.130.100 (228)
23:38:28.844217 IP 192.168.114.129.49157 > 192.168.114.1.53: 55979+ A? teredo.ipv6.microsoft.com. (43)
23:38:28.844590 IP 192.168.114.1.53 > 192.168.114.129.49157: 55979 4/5/5 A 64.4.25.86, A 64.4.25.80, A 64.4.25.82, A 64.4.25.84 (285)
23:38:32.810654 IP 192.168.114.129.49157 > 192.168.114.1.53: 37291+ A? isatap.localdomain. (36)
23:38:32.948270 IP 192.168.114.1.53 > 192.168.114.129.49157: 37291 NXDomain 0/1/0 (111)
23:38:32.976324 IP 192.168.114.129.49157 > 192.168.114.1.53: 35498+ A? isatap.localdomain. (36)
23:38:32.976572 IP 192.168.114.1.53 > 192.168.114.129.49157: 35498 NXDomain 0/1/0 (111)
23:38:39.029400 IP 192.168.114.129.49157 > 192.168.114.1.53: 44972+ A? teredo.ipv6.microsoft.com. (43)
23:38:39.080072 IP 192.168.114.1.53 > 192.168.114.129.49157: 44972 4/5/5 A 64.4.25.84, A 64.4.25.86, A 64.4.25.80, A 64.4.25.82 (285)
23:38:39.083152 IP 192.168.114.129.49157 > 192.168.114.1.53: 11695+ A? isatap.localdomain. (36)
23:38:39.120008 IP 192.168.114.1.53 > 192.168.114.129.49157: 11695 NXDomain 0/1/0 (111)
23:38:39.122330 IP 192.168.114.129.49157 > 192.168.114.1.53: 21422+ A? isatap.localdomain. (36)
23:38:39.155815 IP 192.168.114.1.53 > 192.168.114.129.49157: 21422 NXDomain 0/1/0 (111)
23:38:39.703137 IP 192.168.114.129.49178 > 192.168.114.1.53: 63392+ A? time.windows.com. (34)
23:38:39.703434 IP 192.168.114.1.53 > 192.168.114.129.49178: 63392 1/5/5 A 207.46.130.100 (228)
23:38:39.711962 IP 192.168.114.129.49157 > 192.168.114.1.53: 19873+ A? isatap.localdomain. (36)
23:38:39.712165 IP 192.168.114.1.53 > 192.168.114.129.49157: 19873 NXDomain 0/1/0 (111)
mike01 commented 9 years ago

I'll try to check this in the next weeks. Update: Bug got fixed