From e6d6e8d83efa3ce7c2d428cb972aadd0a8bc7919 Mon Sep 17 00:00:00 2001 From: david Date: Fri, 6 Feb 2009 19:25:11 +0000 Subject: [PATCH] Fixed a DNS decoding bug in dns-zone-transfer.nse that created garbage output and could crash Zenmap by including 0x0C bytes in XML files. The Zenmap crash looked like SAXParseException: .../zenmap-XXXXXX.xml:39:290: not well-formed (invalid token) --- CHANGELOG | 6 ++++++ scripts/dns-zone-transfer.nse | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dec1632b7..dd2d94199 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,11 @@ # Nmap Changelog ($Id$); -*-text-*- +o Fixed a DNS decoding bug in dns-zone-transfer.nse that created + garbage output and could crash Zenmap by including 0x0C bytes in XML + files. The Zenmap crash looked like + SAXParseException: .../zenmap-XXXXXX.xml:39:290: not well-formed (invalid token) + [David] + o [NSEDoc] Scripts that use modules automatically have the script arguments defined by those modules included in their documentation. It's no longer necessary to manually supply @args for the arguments diff --git a/scripts/dns-zone-transfer.nse b/scripts/dns-zone-transfer.nse index d9209d9e1..16e5b0942 100644 --- a/scripts/dns-zone-transfer.nse +++ b/scripts/dns-zone-transfer.nse @@ -263,17 +263,42 @@ end function parse_records(number, data, table, offset) while number > 0 do + tab.nextrow(table) offset = get_answer_record(table, data, offset) number = number - 1 - if number > 0 then tab.nextrow(table) end end return offset end -function dump_zone_info(table, data, offset) - local answers, line +-- An iterator that breaks up a concatentation of responses. In DNS over TCP, +-- each response is prefixed by a two-byte length (RFC 1035 section 4.2.2). +-- Reponses returned by this iterator include the two-byte length prefix. +function responses_iter(data) + local offset = 1 + + return function() + local length, remaining, response + + remaining = string.len(data) - offset + 1 + if remaining == 0 then + return nil + end + assert(remaining >= 14 + 2) + length = bto16(data, offset) + assert(length <= remaining) + -- + 2 for the length field. + length = length + 2 + response = string.sub(data, offset, offset + length - 1) + offset = offset + length + return response + end +end + +function dump_zone_info(table, data) + local answers, line, offset local questions, auth_answers, add_answers + offset = 1 -- number of available records questions = bto16(data, offset+6) answers = bto16(data, offset+8) @@ -363,8 +388,8 @@ action = function(host, port) end -- parse zone information from all returned packets - while(offset < length) do - offset = dump_zone_info(table, response_str, offset) + for r in responses_iter(response_str) do + dump_zone_info(table, r) end soc:close()