1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
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=[[
Discovers hosts and routing information from devices running RIPv2 on the
LAN. It does so by sending a RIPv2 Request command and collects the responses
from all devices responding to the request.
]]
---
-- @usage
-- nmap --script broadcast-rip-discover
--
-- @output
-- Pre-scan script results:
-- | broadcast-rip-discover:
-- | Discovered RIPv2 devices
-- | 10.0.200.107
-- | ip netmask nexthop metric
-- | 10.46.100.0 255.255.255.0 0.0.0.0 1
-- | 10.46.110.0 255.255.255.0 0.0.0.0 1
-- | 10.46.120.0 255.255.255.0 0.0.0.0 1
-- | 10.46.123.0 255.255.255.0 10.0.200.123 1
-- | 10.46.124.0 255.255.255.0 10.0.200.124 1
-- | 10.46.125.0 255.255.255.0 10.0.200.125 1
-- | 10.0.200.101
-- | ip netmask nexthop metric
-- |_ 0.0.0.0 0.0.0.0 10.0.200.1 1
--
-- @args broadcast-rip-discover.timeout timespec defining how long to wait for
-- a response. (default 5s)
--
-- Version 0.1
-- Created 29/10/2011 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
--
author = "Patrik Karlsson"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"broadcast", "safe"}
prerule = function() return not( nmap.address_family() == "inet6") end
RIPv2 = {
Command = {
Request = 1,
Response = 2,
},
AddressFamily = {
IP = 2,
},
-- The Request class contains functions to build a RIPv2 Request
Request = {
-- Creates a new Request instance
--
-- @param command number containing the RIPv2 Command to use
-- @return o instance of request
new = function(self, command)
local o = {
version = 2,
command = command,
domain = 0,
family = 0,
tag = 0,
address = 0,
subnet = 0,
nexthop = 0,
metric = 16
}
setmetatable(o, self)
self.__index = self
return o
end,
-- Converts the whole request to a string
__tostring = function(self)
assert(self.command, "No command was supplied")
assert(self.metric, "No metric was supplied")
assert(self.address, "No address was supplied")
local RESERVED = 0
-- RIPv2 stuff, should be 0 for RIPv1
local tag, subnet, nexthop = 0, 0, 0
local data = string.pack(">BB I2 I2 I2 I4 I4 I4 I4",
self.command, self.version, self.domain, self.family, self.tag,
self.address, self.subnet, self.nexthop, self.metric)
return data
end,
},
-- The Response class contains code needed to parse a RIPv2 response
Response = {
-- Creates a new Response instance based on raw socket data
--
-- @param data string containing the raw socket response
-- @return o Response instance
new = function(self, data)
local o = { data = data }
if ( not(data) or #data < 3 ) then
return
end
local pos, _
o.command, o.version, _, pos = string.unpack(">BBI2", data)
if ( o.command ~= RIPv2.Command.Response or o.version ~= 2 ) then
return
end
local routes = tab.new(2)
tab.addrow(routes, "ip", "netmask", "nexthop", "metric")
while( #data - pos >= 20 ) do
local family, address, metric, netmask, nexthop
family, _, address, netmask, nexthop,
metric, pos = string.unpack(">I2 I2 I4 I4 I4 I4", data, pos)
if ( family == RIPv2.AddressFamily.IP ) then
local ip = ipOps.fromdword(address)
netmask = ipOps.fromdword(netmask)
nexthop = ipOps.fromdword(nexthop)
tab.addrow(routes, ip, netmask, nexthop, metric)
end
end
if ( #routes > 1 ) then o.routes = routes end
setmetatable(o, self)
self.__index = self
return o
end,
}
}
action = function()
local timeout = stdnse.parse_timespec(stdnse.get_script_args('broadcast-rip-discover.timeout'))
timeout = (timeout or 5) * 1000
local socket = nmap.new_socket("udp")
socket:set_timeout(timeout)
local rip = RIPv2.Request:new(RIPv2.Command.Request)
local status, err = socket:sendto("224.0.0.9",
{ number = 520, protocol = "udp" },
tostring(rip))
local result = {}
repeat
local data
status, data = socket:receive()
if ( status ) then
local status, _, _, rhost, _ = socket:get_info()
local response = RIPv2.Response:new(data)
table.insert(result, rhost)
if ( response and response.routes and #response.routes > 0 ) then
--response.routes.name = "Routes"
table.insert(result, { tab.dump(response.routes) } )
end
end
until( not(status) )
if ( #result > 0 ) then
result.name = "Discovered RIPv2 devices"
end
return stdnse.format_output(true, result)
end
|