summaryrefslogtreecommitdiffstats
path: root/scripts/dns-ip6-arpa-scan.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/dns-ip6-arpa-scan.nse')
-rw-r--r--scripts/dns-ip6-arpa-scan.nse131
1 files changed, 131 insertions, 0 deletions
diff --git a/scripts/dns-ip6-arpa-scan.nse b/scripts/dns-ip6-arpa-scan.nse
new file mode 100644
index 0000000..fb9036a
--- /dev/null
+++ b/scripts/dns-ip6-arpa-scan.nse
@@ -0,0 +1,131 @@
+local coroutine = require "coroutine"
+local dns = require "dns"
+local ipOps = require "ipOps"
+local nmap = require "nmap"
+local stdnse = require "stdnse"
+local string = require "string"
+local tab = require "tab"
+local table = require "table"
+
+description = [[
+Performs a quick reverse DNS lookup of an IPv6 network using a technique
+which analyzes DNS server response codes to dramatically reduce the number of queries needed to enumerate large networks.
+
+The technique essentially works by adding an octet to a given IPv6 prefix
+and resolving it. If the added octet is correct, the server will return
+NOERROR, if not a NXDOMAIN result is received.
+
+The technique is described in detail on Peter's blog:
+http://7bits.nl/blog/2012/03/26/finding-v6-hosts-by-efficiently-mapping-ip6-arpa
+]]
+
+---
+-- @usage
+-- nmap --script dns-ip6-arpa-scan --script-args='prefix=2001:0DB8::/48'
+--
+-- @see dns-nsec3-enum.nse
+-- @see dns-nsec-enum.nse
+-- @see dns-brute.nse
+-- @see dns-zone-transfer.nse
+--
+-- @output
+-- Pre-scan script results:
+-- | dns-ip6-arpa-scan:
+-- | ip ptr
+-- | 2001:0DB8:0:0:0:0:0:2 resolver1.example.com
+-- |_2001:0DB8:0:0:0:0:0:3 resolver2.example.com
+--
+-- @args prefix the ip6 prefix to scan
+-- @args mask the ip6 mask to start scanning from
+
+author = "Patrik Karlsson"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = {"intrusive", "discovery"}
+
+
+local arg_prefix = stdnse.get_script_args(SCRIPT_NAME .. ".prefix")
+local arg_mask = stdnse.get_script_args(SCRIPT_NAME .. ".mask")
+
+-- Return a prefix and mask based on script arguments. First checks for "/"
+-- netmask syntax; then looks for a "mask" script argument if that fails. The
+-- "/" syntax wins over "mask" if both are present.
+local function get_prefix_mask(arg_prefix, arg_mask)
+ if not arg_prefix then
+ return
+ end
+ local prefix, mask = string.match(arg_prefix, "^(.*)/(.*)$")
+ if not mask then
+ prefix, mask = arg_prefix, arg_mask
+ end
+ return prefix, mask
+end
+
+prerule = function()
+ local prefix, mask = get_prefix_mask(arg_prefix, arg_mask)
+ return prefix and mask
+end
+
+local function query_prefix(query, result)
+ local condvar = nmap.condvar(result)
+ local status, res = dns.query(query, { dtype='PTR' })
+ if ( not(status) and res == "No Answers") then
+ table.insert(result, query)
+ elseif ( status ) then
+ local ip = query:sub(1, -10):gsub('%.',''):reverse():gsub('(....)', '%1:'):sub(1, -2)
+ ip = ipOps.bin_to_ip(ipOps.ip_to_bin(ip))
+ table.insert(result, { ptr = res, query = query, ip = ip } )
+ end
+ condvar "signal"
+end
+
+action = function()
+
+ local prefix, mask = get_prefix_mask(arg_prefix, arg_mask)
+ local query = dns.reverse(prefix)
+
+ -- cut the query name down to the length of the prefix
+ local len = (( mask / 8 ) * 4) + #(".ip6.arpa") - 1
+
+ local found = { query:sub(-len) }
+ local threads = {}
+
+ local i = 20
+
+ local result
+ repeat
+ result = {}
+ for _, f in ipairs(found) do
+ for q in ("0123456789abcdef"):gmatch("(%w)") do
+ local co = stdnse.new_thread(query_prefix, q .. "." .. f, result)
+ threads[co] = true
+ end
+ end
+
+ local condvar = nmap.condvar(result)
+ repeat
+ for t in pairs(threads) do
+ if ( coroutine.status(t) == "dead" ) then threads[t] = nil end
+ end
+ if ( next(threads) ) then
+ condvar "wait"
+ end
+ until( next(threads) == nil )
+
+ if ( 0 == #result ) then
+ return
+ end
+
+ found = result
+ i = i + 1
+ until( 128 == i * 2 + mask )
+
+ table.sort(result, function(a,b) return (a.ip < b.ip) end)
+ local output = tab.new(2)
+ tab.addrow(output, "ip", "ptr")
+
+ for _, item in ipairs(result) do
+ tab.addrow(output, item.ip, item.ptr)
+ end
+
+ return "\n" .. tab.dump(output)
+end