mirror of
https://github.com/nmap/nmap.git
synced 2025-12-09 14:11:29 +00:00
158 lines
4.5 KiB
Lua
158 lines
4.5 KiB
Lua
--[[
|
|
|
|
Query Autonomous System Numbers Based on IP
|
|
-------------------------------------------
|
|
Uses a 3rd party service provided by team-cymru.org to
|
|
find the autonomous system numbers of a specific IP.
|
|
This scan is performed on all hosts in a portscan but
|
|
will only output a result once for every netblock.
|
|
|
|
Be aware that because this scan uses a 3rd party
|
|
service it may result in a loss of privacy, all hosts
|
|
that you scan with this script will be sent to team-
|
|
cymru.org.
|
|
--]]
|
|
|
|
id = "ASN"
|
|
description = "This script discovers the autonomous system numbers of the \
|
|
netblock ranges that you scanned. It will return other information as well \
|
|
such as a country code, and BGP prefix. \
|
|
Caution: This script access a 3rd party database provided by team-cymru.com \
|
|
to discover this information. Using this script will expose the hosts that \
|
|
you scan to team-cymru.com in order to get the results. \
|
|
Usage: nmap <target> --script asn --script-args dns=<recursion_enabled_dns_server>"
|
|
|
|
author = "Jah, Michael"
|
|
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
|
categories = {"discovery"}
|
|
|
|
require "comm"
|
|
require "ipOps"
|
|
|
|
hostrule = function( host )
|
|
return true
|
|
end
|
|
|
|
if not nmap.registry.asn then
|
|
nmap.registry.asn = {}
|
|
nmap.registry.asn.cache = {}
|
|
end
|
|
|
|
local mutex = nmap.mutex( id )
|
|
|
|
action = function( host )
|
|
|
|
-- get args or die
|
|
local dns_server
|
|
if nmap.registry.args.dns then
|
|
dns_server = nmap.registry.args.dns
|
|
else
|
|
return
|
|
end
|
|
|
|
-- wait
|
|
mutex "lock"
|
|
|
|
-- check for cached data
|
|
for _, cache in ipairs( nmap.registry.asn.cache ) do
|
|
if ip_in_net( host.ip, cache.bgp) then
|
|
mutex "done"
|
|
return " \nBGP Prefix: " .. cache.bgp .. "\nAS number: " .. cache.asn .. "\nCountry Code: " .. cache.co_id
|
|
end
|
|
end
|
|
|
|
-- format data
|
|
local t = {}
|
|
t[4], t[3], t[2], t[1] = host.ip:match( "([^\.]*)\.([^\.]*)\.([^\.]*)\.([^\.]*)" )
|
|
local tsoh = labels( t )
|
|
local z = { "nmap", "asn", "cymru", "com" }
|
|
local zone = labels( z )
|
|
|
|
local t_id = string.char( tonumber( t[2] ), tonumber( t[3] ) ) -- not at all random...
|
|
local dns_std = string.char( 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 )
|
|
local null_char = string.char( 0x00 )
|
|
local qtype = string.char( 0x00, 0x10 )
|
|
local qclass = string.char( 0x00, 0x01 )
|
|
local query = tsoh .. zone .. null_char .. qtype .. qclass
|
|
|
|
local data = t_id .. dns_std .. query
|
|
|
|
-- send data
|
|
local options = {}
|
|
options.proto = "udp"
|
|
options.lines = 1
|
|
options.timeout = 1000
|
|
local status, result = comm.exchange( dns_server, 53, data, options )
|
|
if not status then
|
|
mutex "done"
|
|
return
|
|
end
|
|
|
|
-- read result - this method is tenuous!!
|
|
local _, offset = string.find( result, query )
|
|
local line = string.sub( result, offset + 13 )
|
|
fields = {line:match( ("([^|]*)|"):rep(3) )}
|
|
|
|
-- cache result
|
|
local blob = {}
|
|
blob.bgp = fields[2]:gsub( "^%s*(.-)%s*$", "%1" )
|
|
blob.asn = fields[1]:gsub( "^%s*[^0](.-)%s*$", "%1" )
|
|
blob.co_id = fields[3]:gsub( "^%s*(.-)%s*$", "%1" )
|
|
table.insert( nmap.registry.asn.cache, blob )
|
|
mutex "done"
|
|
|
|
-- return result
|
|
return " \nBGP Prefix: " .. blob.bgp .. "\nAS number: " .. blob.asn .. "\nCountry Code: " .. blob.co_id
|
|
|
|
end
|
|
|
|
|
|
-- labels
|
|
-- given a table of strings, return a string made up of concateneted labels
|
|
-- where each label consists of a length value (cast as char) followed by that number of characters.
|
|
function labels( t )
|
|
local ret = ""
|
|
for _, v in ipairs(t) do
|
|
ret = ret .. string.char( string.len(v) ) .. v
|
|
end
|
|
return ret
|
|
end
|
|
|
|
-- ip_in_net
|
|
-- returns true if the supplied ip address falls inside the supplied range
|
|
function ip_in_net(ip, net)
|
|
local i, j, net_lo, net_hi, dw_ip
|
|
local m_dotted = "(%d+%.%d+%.%d+%.%d+)[%s]*[-][%s]*(%d+%.%d+%.%d+%.%d+)"
|
|
local m_cidr = "(%d+)[.]*(%d*)[.]*(%d*)[.]*(%d*)[/]+(%d+)"
|
|
|
|
if net:match(m_dotted) then
|
|
net_lo, net_hi = net:match(m_dotted)
|
|
net_lo = ipOps.todword(net_lo)
|
|
net_hi = ipOps.todword(net_hi)
|
|
elseif net:match(m_cidr) then
|
|
net_lo, net_hi = two_dwords(net, m_cidr)
|
|
end
|
|
|
|
dw_ip = ipOps.todword(ip)
|
|
if net_lo <= dw_ip and dw_ip <= net_hi then return true end
|
|
return false
|
|
end
|
|
|
|
-- two_dwords
|
|
-- returns the two ip addresses at either end of a cidr range, as dwords
|
|
function two_dwords(str, patt)
|
|
local a, b, c, d, e, lo_net, host
|
|
a, b, c, d, e = str:match(patt)
|
|
local ipt = {b, c, d}
|
|
local strip = ""
|
|
for _, cap in ipairs(ipt) do
|
|
if cap == "" then cap = "0" end
|
|
strip = strip .. "." .. cap
|
|
end
|
|
lo_net = a .. strip
|
|
if e ~= "" then e = tonumber(e)
|
|
if e and e <=32 then
|
|
host = 32 - e end
|
|
end
|
|
return ipOps.todword(lo_net), ipOps.todword(lo_net) + 2^host - 1
|
|
end |