o [NSE] Added script dns-nsid by John Bond, that retrieves name server ID and

version information.

o [NSE] Applied patch to DNS library by John Bond that adds support for the
  CHAOS class and NSID requests.
This commit is contained in:
patrik 2012-01-17 11:37:19 +00:00
parent 0fad67e9e1
commit c579d844ba
4 changed files with 119 additions and 10 deletions

View file

@ -1,5 +1,11 @@
# Nmap Changelog ($Id$); -*-text-*-
o [NSE] Added script dns-nsid by John Bond, that retrieves name server ID and
version information.
o [NSE] Applied patch to DNS library by John Bond that adds support for the
CHAOS class and NSID requests.
o [NSE] Changed the dnsbl library to take a threaded approach into querying
DNSBL provides drastically improving performance. [Patrik]

View file

@ -62,6 +62,7 @@ types = {
CLASS = {
IN = 1,
CH = 3,
ANY = 255
}
@ -252,6 +253,7 @@ function query(dname, options)
local dtype, host, port = options.dtype, options.host, options.port
local class = options.class or CLASS.IN
if not options.tries then options.tries = 10 end -- don't get into an infinite loop
if not options.sendCount then options.sendCount = 2 end
@ -279,12 +281,18 @@ function query(dname, options)
end
local pkt = newPacket()
addQuestion(pkt, dname, dtype)
addQuestion(pkt, dname, dtype, class)
if options.norecurse then pkt.flags.RD = false end
if options.dnssec then
addOPT(pkt, {DO = true})
end
if ( options.dnssec ) then
if ( options.nsid ) then
addNSID(pkt, {DO = true})
else
addOPT(pkt, {DO = true})
end
elseif ( options.nsid ) then
addNSID(pkt, {})
end
if ( options.flags ) then pkt.flags.raw = options.flags end
if ( options.id ) then pkt.id = options.id end
@ -1076,6 +1084,25 @@ decoder[types.TXT] =
end
---
-- Decodes OPT record, puts it in <code>entry.OPT</code>.
--
-- <code>entry.OPT</code> has the fields <code>mname</code>, <code>rname</code>,
-- <code>serial</code>, <code>refresh</code>, <code>retry</code>,
-- <code>expire</code>, and <code>minimum</code>.
-- @param entry RR in packet.
-- @param data Complete encoded DNS packet.
-- @param pos Position in packet after RR.
decoder[types.OPT] =
function(entry, data, pos)
local np = pos - #entry.data - 6
local opt = { bufsize = entry.class }
np, opt.rcode, opt.version, opt.zflags, opt.rdlen = bin.unpack(">CCSS", data, np)
np, opt.data = bin.unpack("A" .. opt.rdlen, data, np)
entry.OPT = opt
end
-- Decodes MX record, puts it in <code>entry.MX</code>.
--
-- <code>entry.MX</code> has the fields <code>pref</code> and
@ -1109,7 +1136,6 @@ decoder[types.SRV] =
np, entry.SRV.target = decStr(data, np)
end
---
-- Decodes returned resource records (answer, authority, or additional part).
-- @param data Complete encoded DNS packet.
-- @param count Value of according counter in header.
@ -1226,13 +1252,14 @@ end
-- @param pkt Table representing DNS packet.
-- @param dname Domain name to be asked.
-- @param dtype RR to be asked.
function addQuestion(pkt, dname, dtype)
function addQuestion(pkt, dname, dtype, class)
if type(pkt) ~= "table" then return nil end
if type(pkt.questions) ~= "table" then return nil end
local class = class or CLASS.IN
local q = {}
q.dname = dname
q.dtype = dtype
q.class = CLASS.IN
q.class = class
table.insert(pkt.questions, q)
return pkt
end
@ -1269,12 +1296,18 @@ local function encodeOPT_Z(flags)
return table.concat(bits)
end
function addNSID (pkt,Z)
local udp_payload_size = 4096
local opt = bin.pack(">SS",3, 0) -- nsid data
addOPT(pkt,Z,opt)
end
---
-- Adds an OPT RR to a DNS packet's additional section. Only the table of Z
-- flags is supported (i.e., not RDATA). See RFC 2671 section 4.3.
-- @param pkt Table representing DNS packet.
-- @param Z Table of Z flags. Only DO is supported.
function addOPT(pkt, Z)
function addOPT(pkt, Z, opt)
local rdata = opt or ""
if type(pkt) ~= "table" then return nil end
if type(pkt.additional) ~= "table" then return nil end
local _, Z_int = bin.unpack(">S", bin.pack("B", encodeOPT_Z(Z)))
@ -1282,8 +1315,8 @@ function addOPT(pkt, Z)
type = types.OPT,
class = 4096, -- Actually the sender UDP payload size.
ttl = 0 * (0x01000000) + 0 * (0x00010000) + Z_int,
rdlen = 0,
rdata = "",
rdlen = #rdata,
rdata = rdata,
}
table.insert(pkt.additional, opt)
return pkt

69
scripts/dns-nsid.nse Normal file
View file

@ -0,0 +1,69 @@
description = [[
Ateemps to get more information from a server by requesting the server nsid[1],
and asking for id.server[2] and version.bind. This script dose the same as the
following two dig commands:
- dig CH TXT bind.version @target
- dig +nsid CH TXT id.server @target
[1]http://www.ietf.org/rfc/rfc5001.txt
[2]http://www.ietf.org/rfc/rfc4892.txt
]]
---
-- @usage
-- nmap -sSU -p 53 --script dns-nsid <target>
--
-- @output
-- 53/udp open domain udp-response
-- | dns-nsid:
-- | NSID dns.example.com (646E732E6578616D706C652E636F6D)
-- | id.server: dns.example.com
-- |_ bind.version: 9.7.3-P3
---
author = "John Bond"
license = "Simplified (2-clause) BSD license--See http://nmap.org/svn/docs/licenses/BSD-simplified"
categories = {"discovery", "default"}
require "stdnse"
require "shortport"
require "dns"
portrule = shortport.port_or_service(53, "domain", {"tcp", "udp"})
local function rr_filter(pktRR, label)
for _, rec in ipairs(pktRR, label) do
if ( rec[label] and 0 < #rec.data ) then
if ( dns.types.OPT == rec.dtype ) then
local pos, _, len = bin.unpack(">SS", rec.data)
if ( len ~= #rec.data - pos + 1 ) then
return false, "Failed to decode NSID"
end
return true, select(2, bin.unpack("A" .. len, rec.data, pos))
else
return true, select(2, bin.unpack("p", rec.data))
end
end
end
end
action = function(host, port)
local result = {}
local status, resp = dns.query("id.server", {host = host.ip, dtype='TXT', class=dns.CLASS.CH, retAll=true, retPkt=true, nsid=true, dnssec=true})
if ( status ) then
local status, nsid = rr_filter(resp.add,'OPT')
if ( status ) then
table.insert(result, ("NSID: %s (%s)"):format(nsid, stdnse.tohex(nsid)))
end
local status, id_server = rr_filter(resp.answers,'TXT')
if ( status ) then
table.insert(result, ("id.server: %s"):format(id_server))
end
end
local status, bind_version = dns.query("version.bind", {host = host.ip, dtype='TXT', class=dns.CLASS.CH})
if ( status ) then
table.insert(result, ("bind.version: %s"):format(bind_version))
end
return stdnse.format_output(true, result)
end

View file

@ -55,6 +55,7 @@ Entry { filename = "dns-brute.nse", categories = { "discovery", "intrusive", } }
Entry { filename = "dns-cache-snoop.nse", categories = { "discovery", "intrusive", } }
Entry { filename = "dns-fuzz.nse", categories = { "fuzzer", "intrusive", } }
Entry { filename = "dns-nsec-enum.nse", categories = { "discovery", "intrusive", } }
Entry { filename = "dns-nsid.nse", categories = { "default", "discovery", } }
Entry { filename = "dns-random-srcport.nse", categories = { "external", "intrusive", } }
Entry { filename = "dns-random-txid.nse", categories = { "external", "intrusive", } }
Entry { filename = "dns-recursion.nse", categories = { "default", "safe", } }