summaryrefslogtreecommitdiffstats
path: root/scripts/dns-nsid.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/dns-nsid.nse')
-rw-r--r--scripts/dns-nsid.nse109
1 files changed, 109 insertions, 0 deletions
diff --git a/scripts/dns-nsid.nse b/scripts/dns-nsid.nse
new file mode 100644
index 0000000..3a34979
--- /dev/null
+++ b/scripts/dns-nsid.nse
@@ -0,0 +1,109 @@
+local dns = require "dns"
+local nmap = require "nmap"
+local shortport = require "shortport"
+local stdnse = require "stdnse"
+local string = require "string"
+
+description = [[
+Retrieves information from a DNS nameserver by requesting
+its nameserver ID (nsid) and asking for its id.server and
+version.bind values. This script performs the same queries as the following
+two dig commands:
+ - dig CH TXT bind.version @target
+ - dig +nsid CH TXT id.server @target
+
+References:
+[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
+--
+-- @xmloutput
+-- <table key="NSID">
+-- <elem key="raw">mia01.l.root-servers.org</elem>
+-- <elem key="hex">6d696130312e6c2e726f6f742d736572766572732e6f7267</elem>
+-- </table>
+-- <elem key="id.server">mia01.l.root-servers.org</elem>
+-- <elem key="bind.version">NSD 3.2.15</elem>
+
+author = "John R. Bond"
+license = "Simplified (2-clause) BSD license--See https://nmap.org/svn/docs/licenses/BSD-simplified"
+
+categories = {"discovery", "default", "safe"}
+
+
+portrule = function (host, port)
+ if not shortport.port_or_service(53, "domain", {"tcp", "udp"})(host, port) then
+ return false
+ end
+ -- only check tcp if udp is not open or open|filtered
+ if port.protocol == 'tcp' then
+ local tmp_port = nmap.get_port_state(host, {number=port.number, protocol="udp"})
+ if tmp_port then
+ return not string.match(tmp_port.state, '^open')
+ end
+ end
+ return true
+end
+
+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
+ if #rec.data < 4 then
+ return false, "Failed to decode NSID"
+ end
+ local _, len, pos = string.unpack(">I2 I2", rec.data)
+ if ( len ~= #rec.data - pos + 1 ) then
+ return false, "Failed to decode NSID"
+ end
+ return true, string.unpack("c" .. len, rec.data, pos)
+ else
+ return true, string.unpack(">s1", rec.data)
+ end
+ end
+ end
+end
+
+action = function(host, port)
+ local result = stdnse.output_table()
+ local flag = false
+ local status, resp = dns.query("id.server", {host = host.ip, port=port.number, proto=port.protocol, 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
+ flag = true
+ -- RFC 5001 says NSID can be any arbitrary bytes, and should be displayed
+ -- as hex, but often it is a readable string. Store both.
+ result["NSID"] = { raw = nsid, hex = stdnse.tohex(nsid) }
+ setmetatable(result["NSID"], {
+ __tostring = function(t)
+ return ("%s (%s)"):format(t.raw, t.hex)
+ end
+ })
+ end
+ local status, id_server = rr_filter(resp.answers,'TXT')
+ if ( status ) then
+ flag = true
+ result["id.server"] = id_server
+ end
+ end
+ local status, bind_version = dns.query("version.bind", {host = host.ip, port=port.number, proto=port.protocol, dtype='TXT', class=dns.CLASS.CH})
+ if ( status ) then
+ flag = true
+ result["bind.version"] = bind_version
+ end
+ if flag then
+ return result
+ end
+end