Nmap Development mailing list archives

DNS cache snooping script


From: Eugene Alexeev <eugene.alexeev () gmail com>
Date: Mon, 12 Apr 2010 10:18:23 -0600

All,

I'm submitting the following NSE script for your scrutiny.  Please note that
it may error out with versions that do not include the fix to dns.lua that
was addressed by svn revision 17270.


description = [[
Performs DNS cache snooping against a DNS server.

This script has two modes of operation: non-recursive (used by default) and
timed.  The default mode makes DNS type A queries to the dns server with the

Recursion Desired (RD) flag set to 0 and tries set to 0.  Any successful
queries
are assumed to come from the server's cache.  The timed mode uses temporal
analysis to deterime where or not each host is in the server's cache.
First,
it sends a recursive DNS query for www.google.com to the server.  This
ensures
that the response for www.google.com has been cached. It then makes
recursive
requests for each host in the list and records their timing information.
Then
the mean cached query time is calculated along with cached query time sigma.

Each host's timing data is then evaluated, if the query tooklonger than
cached
mean + ( cached sigma * multiplier), then the response is considered not to
have
been cached.

Please note that the timed mode will pollute the DNS server's cache.
]]

---
-- @param snoop_mode timed: use the timed mode rather than the default
--                          non-recursive mode.
-- @param snoop_multiplier x.x: can be used to adjust the maxDeviation
parameter
--                          used in timed mode.
-- @param snoop_hosts {host0,host1,hostN}: check if the supplied hosts are
--                          in the DNS cache rather than querying using
default
--                          snoop_hosts table.
--
-- @output
-- 53/udp open|filtered domain
-- | dns-cache-snoop: DNS cache contains:
-- | -->    login.yahoo.com
-- | -->    mail.aol.com
-- | -->    my.screenname.aol.com
-- | -->    gmx.com
-- | -->    hotmail.com
-- | -->    login.live.com
-- | -->    www.facebook.com
-- | -->    facebook.com
-- | -->    www.twitter.com
-- | -->    twitter.com
-- | -->    www.linkedin.com
-- |_-->    linkedin.com
--
-- @usage
-- nmap --script dns-cache-snoop.nse \
--      --script-args snoop_mode=timed,
--                    snoop_multiplier=x.x,
--                    snoop_hosts={host0\,host1\,hostN}

require('shortport')
require('dns')
require('stdnse')
require('nmap')
require('math')

author = "Eugene V. Alexeev"

license = 'Same as Nmap--See http://nmap.org/book/man-legal.html&apos;

categories = {'default', 'intrusive', 'discovery'}

portrule = shortport.portnumber(53, 'udp')


--- Default list of hosts to check
--@class table
--@name snoop_hosts
local snoop_hosts = {
    'mail.google.com', 'gmail.com',                 --- Gmail
    'mail.yahoo.com', 'login.yahoo.com',            --- Yahoo Mail
    'mail.aol.com', 'my.screenname.aol.com',        --- AOL/AIM Mail
    'www.gmx.com', 'gmx.com',                       --- GMX Mail
    'hotmail.com', 'login.live.com',                --- Hotmail / MSN Live
    'www.facebook.com', 'facebook.com',             --- Facebook
    'www.twitter.com', 'twitter.com',               --- Twitter
    'www.linkedin.com', 'linkedin.com',             --- LinkedIn
    'www.plaxo.com', 'plaxo.com',                   --- Plaxo
    'www.myspace.com', 'myspace.com',               --- MySpace
    'www.ivillage.com', 'ivillage.com',             --- iVillage
    'www.flickr.com', 'flickr.com',                 --- Flickr
    'www.youtube.com', 'youtube.com',               --- Youtube
    'www.digg.com', 'digg.com',                     --- Digg
    'www.reddit.com', 'reddit.com',                 --- Reddit
    'www.craigslist.com', 'craigslist.com',         --- Craigslist
    'update.microsoft.com',                         --- MS Patches
    'www.microsoft.com', 'microsoft.com',           --- General MS
    'technet.microsoft.com',                        --- Technet Access
    'rhn.com','rhn.redhat.com','redhat.com',        --- RHN Access
    'www.novell.com', 'novell.com',                 --- SLES / SLED
    'www.kernel.org', 'kernel.org',                 --- Kernel Sources, etc
    'www.ubuntu.com', 'ubuntu.com',                 --- Ubuntu
    'www.debian.com', 'debian.com',                 --- Debian
    'www.freebsd.org', 'freebsd.org',               --- FreeBSD
    'www.openbsd.org', 'openbsd.org',               --- OpenBSD
    'www.oracle.com', 'oracle.com',                 --- Oracle
    'docs.sun.com', 'www.sun.com', 'sun.com',       --- Sun/Solaris Docs
    'www.centos.org', 'centos.org',                 --- CentOS
    'www.nmap.org', 'nmap.org',                     --- Couldn't Resist
    'ha.ckers.org', 'sla.ckers.org'                 --- Should not be
present
                                                    --- in most caches!
}


--- Default snoop_multiplier, used to control the maxDeviation paramter in
--  timed mode, has no meaning in non-recursive mode.
--  @class number
--  @name snoop_multiplier
local snoop_multiplier = 1.0


--- Function to determine the standard deviation of a table
--  @class function
--  @name standardDeviation
--  @param t table containing numeric values
--- @return sigma for values in table t
--  THIS FUNCTION WAS NOT WRITTED BY ME, FULL CREDIT GOES TO THE AUTHOR OF:
--  http://lua-users.org/wiki/SimpleStats
function standardDeviation( t )
  local m
  local vm
  local sum = 0
  local count = 0
  local result

  m = mean( t )

  for k,v in pairs(t) do
    if type(v) == 'number' then
      vm = v - m
      sum = sum + (vm * vm)
      count = count + 1
    end
  end

  result = math.sqrt(sum / (count-1))

  return result
end


--- Function to determine the mean value of a table
--  @class function
--  @name mean
--  @param t table containing numeric values
--  @return the mean for values in table t
--  THIS FUNCTION WAS NOT WRITTED BY ME, FULL CREDIT GOES TO THE AUTHOR OF:
--  http://lua-users.org/wiki/SimpleStats
function mean( t )
  local sum = 0
  local count= 0

  for k,v in pairs(t) do
    if type(v) == 'number' then
      sum = sum + v
      count = count + 1
    end
  end

  return (sum / count)
end


--- Wrapper for nselib/dns.query function, performs non-recursive DNS
queries
--  @class function
--  @name nr_query
--  @param hostname hostname to look up
--  @param host host table provided by NSE
--  @param port port table provided by NSE
--  @return true if an answer is received
--  @return false if no answer is recevied
function nr_query(hostname, host, port)
  local q = dns.query(hostname,             -- Host name to query for
                     {host=host.ip,         -- IP of DNS server
                      port=port.number,     -- Port of DNS server
                      tries = 0,            -- Do not query other servers
                      norecurse=true})      -- Perform a non-recursive query
  if q then
    return true

else

    return false
  end
end


--- Function to calculate the time (ms) it took to perform a specific
recursive
--  DNS query.
--  @class function
--  @name timed_query
--  @param hostname hostname to look up
--  @param host host table provided by NSE
--  @param port port table provided by NSE
--  @return response time in ms
--  @return -1 if an error occured
function timed_query(hostname, host, port)
  local start = nmap.clock_ms()

  local q = dns.query(hostname,             -- Host name to query for
                     {host=host.ip,         -- IP of DNS server
                      port=port.number,     -- Port of DNS server
                      tries=0,              -- Do not query other servers
                      norecurse=false})     -- Perform a recursive query

  local stop = nmap.clock_ms()

  if q then
    return (stop - start)
  else
    return -1
  end
end


action = function(host, port)
  local inCache = {}

  if nmap.registry.args.snoop_hosts ~= nil then
    stdnse.print_debug("Will snoop for %d custom hosts",
                       #nmap.registry.args.snoop_hosts)
    snoop_hosts = nmap.registry.args.snoop_hosts
  end

  --- Timed mode
  if nmap.registry.args.snoop_mode ~= nil and
     nmap.registry.args.snoop_mode == "timed" then
     stdnse.print_debug("Using timed mode.")

    if nmap.registry.args.snoop_multiplier ~= nil then
      stdnse.print_debug("Setting snoop_multiplier to %f",
                         nmap.registry.args.snoop_multiplier)

      snoop_multiplier = nmap.registry.args.snoop_multiplier
    end

    timed_query('www.google.com', host, port)

    local cachedTimes = {}

    for i=1,25 do
      local ms = timed_query('www.google.com', host, port)
      if ms > 0 then
        table.insert(cachedTimes, ms)
      end
    end

    local queryTimes = {}

    for i,hostname in ipairs(snoop_hosts) do
      local ms = timed_query(hostname, host, port)
      if ms > 0 then
        queryTimes[hostname] = ms
      end
    end

    local cachedMean = mean(cachedTimes)
    local cachedSigma = standardDeviation(cachedTimes)
    local maxDeviation = cachedSigma * snoop_multiplier
    local maxCachedTime = cachedMean + maxDeviation

    stdnse.print_debug("Mean cached response time: %f ms",  cachedMean)
    stdnse.print_debug("Cached response time sigma: %f ms", cachedSigma)
    stdnse.print_debug("Max Deviation: %f ms",              maxDeviation)

    for hostname, response_time in pairs(queryTimes) do
      stdnse.print_debug("%s : %f", hostname, response_time)
      if response_time > 0 and response_time <= maxCachedTime then
        table.insert(inCache, hostname)
      end
    end

  --- Non-recursive mode
  else
    for i,hostname in ipairs(snoop_hosts) do
      if nr_query(hostname, host, port) then
        table.insert(inCache, hostname)
      end
    end
  end

  --- Organize and return the results
  local resultString = "DNS cache contains:\n"

  for i,hostname in ipairs(inCache) do
    resultString =  resultString .. "-->\t" .. hostname .. "\n"
  end

  if # resultString > 20 then return resultString else return end
end


Thanks for your time & looking forward to your feedback.

Eugene
_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/


Current thread: