Nmap Development mailing list archives

Re: DNS cache snooping script


From: Eugene Alexeev <eugene.alexeev () gmail com>
Date: Mon, 12 Apr 2010 13:46:26 -0600

Patrick,

Thanks for the feedback.  It looks like it should not be very difficult to
scrape the resources you mentioned.  Although malwareurl alone is ~62k
entries -- not something you just want to launch.  I can see this being an
added argument in terms of: go scrape these pages, uniq the host names and
probe for those URLs.  I don't think we'd want to used timed mode on this
because of the potential for delay -- up to 4 seconds / request...62k
entries at worst is about 2.87 days worth of queries if done sequentially.
If we stick to non-recursive queries only, 62k is done in roughly 2.5 hours
assuming ~150ms per query.  So there would be a need to parallelize the
querying to bring this back into a reasonable time frame.

Eugene

On Mon, Apr 12, 2010 at 1:06 PM, Patrik Karlsson <patrik () cqure net> wrote:

This looks like a really cool/useful script!
It reminds me of this perl app used to detect cached domains used by
malware:
http://www.innismir.net/article/467

The perl app uses this list of domains to do so:
https://zeustracker.abuse.ch/blocklist.php?download=domainblocklist

//Patrik

On 12 apr 2010, at 18.33, Ron wrote:

Hey Eugene,

That script looks really cool! I was thinking of writing something
similar, but you saved me the trouble.

Out of curiosity, where did you get the list of domains you look for, or
is it simply arbitrary? I'm trying to think of which domains would be the
most interesting - maybe others will have some better input than me. My
first thought is those used by automatic updaters (java update, oracle,
windows, etc), those used by different Linux distributions, and those used
by known malware. All of them could be interesting when testing a network. I
was thinking of the top-xxx sites from some service (Alexa, I think?), but I
don't think that'd give you anything interesting.

How long does it take to look up the different domains? Are/can you look
up more than one hostname per DNS request to speed it up? How many domains
can be realistically checked in a single query? Tens, hundreds, thousands?


On Mon, 12 Apr 2010 10:18:23 -0600 Eugene Alexeev
<eugene.alexeev () gmail com> wrote:
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/


--
Ron Bowes
http://www.skullsecurity.org
http://www.twitter.com/iagox86
_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/

--
Patrik Karlsson
http://www.cqure.net
http://www.twitter.com/nevdull77





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

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


Current thread: