Sunday, August 28, 2011

Nmap script to check if IP range is part of a Zeus botnet

My first shot at Nmap NSE scripting. Nothing fancy but it does what is says

Roman Huessy was kind to give his OK to use his Zeustracker DNS service in this manner, *use* but not abuse.

Let me know if you find it useful

/M


description = [[
 Check if your IP-range is part of a Zeus botnet!
 Information supplied by ZTDNS @ abuse.ch!
 
Please review the following information before you start to scan
 https://zeustracker.abuse.ch/ztdns.php
 ]]
 
---
-- @usage
-- nmap --script=zeustracker.nse <target IP/IP-range>
-- @output
-- Host script results:
-- | zeustracker:
-- |   IP: 208.87.242.18 : SBL: Not listed : ASN: 40676  Country: US
-- |_  Status: unknown  Level: Unknown Files_online: 0  Dateadded: 2010-12-28
 
 author = "Mikael Keri"
 license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
 categories = {"safe", "discovery", "external", "malware"}
 
 require "dns"
 require "ipOps"
 require "stdnse"


 hostrule = function(host)
   return not ipOps.isPrivate(host.ip)
 end
 
 action = function(host)

 local dname = dns.reverse(host.ip)
 dname = dname:gsub ("%.in%-addr%.arpa",".ipbl.zeustracker.abuse.ch")
 result = dns.query(dname, {dtype='TXT'})
 
 local fields = stdnse.strsplit("|", result)    
 local info = {}
 local query = math.floor((# fields) / 9)
  for i = 0, (query - 1) do
          local start = i * 8
          local ipaddress = fields[start + 2]
          local sbl = fields[start + 3]
          local asn = fields[start + 4]
          local country = fields[start + 5]
          local status = fields[start + 6]
          local level = fields[start + 7]

  if level == 5 then
     level = "Hosted on a FastFlux botnet"
   elseif level == 4 then
     level = "Unknown"
   elseif level == 3 then
     level = "Free hosting service"
   elseif level == 2 then
     level = "Hacked webserver" 
   else 
     level = "Bulletproof hosted"
    end       
          local files_online = fields[start + 8]
          local dateadded = fields[start + 9]
          local formatted = string.format("IP:%s: SBL:%s: ASN:%s Country:%s\n  Status:%s Level:%s Files_online:%s Dateadded:%s", ipaddress, sbl, asn, country, status, level, files_online, dateadded)
                table.insert(info, formatted)
        end
        return stdnse.format_output(true, info)
 end