-- -*- mode: lua -*-: -- vim: set filetype=lua : description = [[ Sniffs the local network for a configurable amount of time and prints discovered addresses. If newtargets is true, adds the addresses to the queue to be scanned. Requires root privileges. Either the targets-sniffer.iface script argument or -e Nmap option to define which interface to use. ]] --- -- @usage -- nmap -sL --script=targets-sniffer --script-args=newtargets,targets-sniffer.timeout=5s,targets-sniffer.iface=eth0 -- @args targets-sniffer.timeout The amount of time to listen for packets. Default 10s. -- @args targets-sniffer.iface The interface to use for sniffing. -- @args newtargets If true, add discovered targets to the scan queue. -- @output -- Pre-scan script results: -- | targets-sniffer: -- | 192.168.0.1 -- | 192.168.0.3 -- | 192.168.0.35 -- |_192.168.0.100 -- Thanks to everyone for the feedback and especially Henri Doreau for his detailed feedback and suggestions author = "Nick Nikolaou " categories = {"broadcast", "discovery"} license = "Same as Nmap--See http://nmap.org/book/man-legal.html" require("stdnse") require("target") require("nmap") require("packet") require("bin") local interface_info local all_addresses= {} local unique_addresses = {} --Make sure the IP is not a broadcast or the local address local function check_if_valid(address) local broadcast = interface_info.broadcast local local_address = interface_info.address if address == local_address or address == broadcast or address == "255.255.255.255" then return false else return true end end local function get_ip_addresses(layer3) local ip = packet.Packet:new(layer3, layer3:len()) return packet.toip(ip.ip_bin_src),packet.toip(ip.ip_bin_dst) end prerule = function() return nmap.is_privileged() and (stdnse.get_script_args("targets-sniffer.iface") or nmap.get_interface()) end action = function() local sock = nmap.new_socket() local ip_src,ip_dst local packet_counter = 0 local ip_counter = 0 local DEFAULT_TIMEOUT_SEC = 10 -- Default timeout value in seconds if the timeout argument is not specified local timeoutstr = stdnse.get_script_args("targets-sniffer.timeout") or tostring(DEFAULT_TIMEOUT_SEC) local timeout = (stdnse.parse_timespec(timeoutstr) * 1000) local interface = stdnse.get_script_args("targets-sniffer.iface") or nmap.get_interface() interface_info = nmap.get_interface_info(interface) if interface_info==nil then -- Check if we have the interface information stdnse.print_debug(1,"Error: Unable to get interface info. Did you specify the correct interface using 'targets-sniffer.iface=' or '-e '?") return end if sock==nil then stdnse.print_debug(1,"Error - unable to open socket using interface %s",interface) return else sock:pcap_open(interface, 104, false , "ip") stdnse.print_debug(1, "Will sniff for %s seconds on interface %s.", (timeout/1000),interface) repeat local start_time = nmap.clock_ms() -- Used for script timeout sock:set_timeout(timeout) local status, _, _, layer3 = sock:pcap_receive() if status then packet_counter=packet_counter+1 ip_src,ip_dst = get_ip_addresses(layer3) stdnse.print_debug(1,"Got IP addresses %s and %s",ip_src,ip_dst) if check_if_valid(ip_src) == true then if not unique_addresses[ip_src] then unique_addresses[ip_src] = true table.insert(all_addresses,ip_src) end end if check_if_valid(ip_dst) == true then if not unique_addresses[ip_dst] then unique_addresses[ip_dst] = true table.insert(all_addresses,ip_dst) end end end -- Update timeout timeout = timeout - (nmap.clock_ms() - start_time) until timeout <= 0 sock:pcap_close() end if target.ALLOW_NEW_TARGETS == true then for _,v in pairs(all_addresses) do target.add(v) end else stdnse.print_debug(1,"Not adding targets to newtargets. If you want to do that use the 'newtargets' script argument.") end if #all_addresses>0 then stdnse.print_debug(1,"Added %s address(es) to newtargets", #all_addresses) end return string.format("Sniffed %s address(es). \n", #all_addresses) .. stdnse.strjoin("\n",all_addresses) end