mirror of
https://github.com/nmap/nmap.git
synced 2026-02-07 05:56:34 +00:00
Add IPv6 multicast host discovery scripts from Weilin.
This commit is contained in:
@@ -226,6 +226,9 @@ Entry { filename = "ssl-known-key.nse", categories = { "discovery", "safe", "vul
|
||||
Entry { filename = "sslv2.nse", categories = { "default", "safe", } }
|
||||
Entry { filename = "stuxnet-detect.nse", categories = { "discovery", "intrusive", } }
|
||||
Entry { filename = "svn-brute.nse", categories = { "auth", "intrusive", } }
|
||||
Entry { filename = "targets-ipv6-multicast-echo.nse", categories = { "discovery", } }
|
||||
Entry { filename = "targets-ipv6-multicast-invalid-dst.nse", categories = { "discovery", } }
|
||||
Entry { filename = "targets-ipv6-multicast-slaac.nse", categories = { "discovery", } }
|
||||
Entry { filename = "targets-sniffer.nse", categories = { "broadcast", "discovery", "safe", } }
|
||||
Entry { filename = "targets-traceroute.nse", categories = { "discovery", "safe", } }
|
||||
Entry { filename = "telnet-brute.nse", categories = { "auth", "intrusive", } }
|
||||
|
||||
122
scripts/targets-ipv6-multicast-echo.nse
Normal file
122
scripts/targets-ipv6-multicast-echo.nse
Normal file
@@ -0,0 +1,122 @@
|
||||
description = [[
|
||||
Multicast echo ping.
|
||||
Do a very fast host discovery on link-local IPv6 network.
|
||||
]]
|
||||
|
||||
---
|
||||
-- @usage
|
||||
-- ./nmap -6 --script=targets-ipv6-multicast-echo.nse --script-args 'newtargets,interface=eth0,ipv6.src=2001:da8:215:3320:223:aeff:fe5d:3b10' -sL
|
||||
-- @args newtargets If true, add discovered targets to the scan queue.
|
||||
-- @args interface The interface to use for host discovery.
|
||||
-- @args ipv6.src The source IPv6 address in the probe packets.
|
||||
|
||||
author = "David and Weilin"
|
||||
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
|
||||
categories = {"discovery"}
|
||||
|
||||
require 'nmap'
|
||||
require 'target'
|
||||
require 'packet'
|
||||
local bit = require 'bit'
|
||||
|
||||
prerule = function()
|
||||
return nmap.is_privileged() and
|
||||
(stdnse.get_script_args("interface") or nmap.get_interface())
|
||||
end
|
||||
|
||||
catch = function()
|
||||
dnet:ethernet_close()
|
||||
pcap:pcap_close()
|
||||
end
|
||||
try = nmap.new_try(catch)
|
||||
|
||||
local function get_ipv6_interface_info_by_name(if_name)
|
||||
local ifaces = nmap.list_interfaces()
|
||||
local iface
|
||||
local if_nfo
|
||||
for _,iface in pairs(ifaces) do
|
||||
if if_name == iface.device and (#iface.address>15 or string.find(iface.address, "::")) then
|
||||
if_nfo = iface
|
||||
return if_nfo
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get_identifier(ip6_addr)
|
||||
return string.sub(ip6_addr, 9, 16)
|
||||
end
|
||||
|
||||
action = function()
|
||||
local if_name = stdnse.get_script_args("targets-ipv6-multicast.interface") or nmap.get_interface()
|
||||
local if_nfo = get_ipv6_interface_info_by_name(if_name)
|
||||
if not if_nfo then
|
||||
stdnse.print_debug("Invalid interface: " .. if_name)
|
||||
return false
|
||||
end
|
||||
local src_mac = if_nfo.mac
|
||||
local src_ip6 = packet.ip6tobin(stdnse.get_script_args("ipv6.src")) or packet.ip6tobin(if_nfo.address)
|
||||
local dst_mac = packet.mactobin("33:33:00:00:00:01")
|
||||
local dst_ip6 = packet.ip6tobin("ff02::1")
|
||||
local id_set = {}
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
--Multicast echo ping probe
|
||||
|
||||
local dnet = nmap.new_dnet()
|
||||
local pcap = nmap.new_socket()
|
||||
|
||||
try(dnet:ethernet_open(if_name))
|
||||
pcap:pcap_open(if_name, 128, false, "icmp6 and ip6[6:1] = 58 and ip6[40:1] = 129")
|
||||
|
||||
local probe = packet.Frame:new()
|
||||
probe.mac_src = src_mac
|
||||
probe.mac_dst = dst_mac
|
||||
probe.ip6_src = src_ip6
|
||||
probe.ip6_dst = dst_ip6
|
||||
probe.echo_id = 5
|
||||
probe.echo_seq = 6
|
||||
probe.echo_data = "Nmap host discovery."
|
||||
probe:build_icmpv6_echo_request()
|
||||
probe:build_icmpv6_header()
|
||||
probe:build_ipv6_packet()
|
||||
probe:build_ether_frame()
|
||||
|
||||
try(dnet:ethernet_send(probe.frame_buf))
|
||||
|
||||
pcap:set_timeout(1000)
|
||||
local pcap_timeout_count = 0
|
||||
local nse_timeout = 5
|
||||
local start_time = nmap:clock()
|
||||
local cur_time = nmap:clock()
|
||||
|
||||
local found_targets = 0
|
||||
|
||||
repeat
|
||||
local status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
cur_time = nmap:clock()
|
||||
if not status then
|
||||
pcap_timeout_count = pcap_timeout_count + 1
|
||||
else
|
||||
local reply = packet.Frame:new(layer2..layer3)
|
||||
if reply.mac_dst == src_mac then
|
||||
local identifier = get_identifier(reply.ip6_src)
|
||||
if not id_set[identifier] then
|
||||
id_set[identifier] = true
|
||||
local target_str = packet.toipv6(reply.ip6_src)
|
||||
target.add(target_str)
|
||||
found_targets = found_targets + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout
|
||||
|
||||
stdnse.print_debug(0, "[Echo ping] Found %d targets.", found_targets)
|
||||
|
||||
dnet:ethernet_close()
|
||||
pcap:pcap_close()
|
||||
|
||||
return true
|
||||
end
|
||||
140
scripts/targets-ipv6-multicast-invalid-dst.nse
Normal file
140
scripts/targets-ipv6-multicast-invalid-dst.nse
Normal file
@@ -0,0 +1,140 @@
|
||||
description = [[
|
||||
Multicast invalid destination options ping.
|
||||
Do a very fast host discovery on link-local IPv6 network.
|
||||
]]
|
||||
|
||||
---
|
||||
-- @usage
|
||||
-- ./nmap -6 --script=targets-ipv6-multicast-invalid-dst.nse --script-args 'newtargets,interface=eth0,ipv6=2001:da8:215:3320:223:aeff:fe5d:3b10' -sP
|
||||
-- @args newtargets If true, add discovered targets to the scan queue.
|
||||
-- @args interface The interface to use for host discovery.
|
||||
-- @args ipv6.src The source IPv6 address in the probe packets.
|
||||
|
||||
author = "David and Weilin"
|
||||
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
|
||||
categories = {"discovery"}
|
||||
|
||||
require 'nmap'
|
||||
require 'target'
|
||||
require 'packet'
|
||||
local bit = require 'bit'
|
||||
|
||||
prerule = function()
|
||||
return nmap.is_privileged() and
|
||||
(stdnse.get_script_args("interface") or nmap.get_interface())
|
||||
end
|
||||
|
||||
catch = function()
|
||||
dnet:ethernet_close()
|
||||
pcap:pcap_close()
|
||||
end
|
||||
try = nmap.new_try(catch)
|
||||
|
||||
local function get_ipv6_interface_info_by_name(if_name)
|
||||
local ifaces = nmap.list_interfaces()
|
||||
local iface
|
||||
local if_nfo
|
||||
for _,iface in pairs(ifaces) do
|
||||
if if_name == iface.device and (#iface.address>15 or string.find(iface.address, "::")) then
|
||||
if_nfo = iface
|
||||
return if_nfo
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get_identifier(ip6_addr)
|
||||
return string.sub(ip6_addr, 9, 16)
|
||||
end
|
||||
|
||||
--- Build an IPv6 invalid extension header.
|
||||
-- @param nxt_hdr integer that stands for next header's type
|
||||
local function build_invalid_extension_header(nxt_hdr)
|
||||
local ex_invalid_opt = string.char(0x80,0x01,0xfe,0x18,0xfe,0x18,0xfe,0x18,0x0,0x0,0x0,0x0,0x0,0x0)
|
||||
local ext_header =
|
||||
string.char(nxt_hdr) .. --next header
|
||||
string.char(#ex_invalid_opt/16) .. --length (16bytes)
|
||||
ex_invalid_opt
|
||||
return ext_header
|
||||
end
|
||||
|
||||
action = function()
|
||||
local if_name = stdnse.get_script_args("targets-ipv6-multicast.interface") or nmap.get_interface()
|
||||
local if_nfo = get_ipv6_interface_info_by_name(if_name)
|
||||
if not if_nfo then
|
||||
stdnse.print_debug("Invalid interface: " .. if_name)
|
||||
return false
|
||||
end
|
||||
local src_mac = if_nfo.mac
|
||||
local src_ip6 = packet.ip6tobin(stdnse.get_script_args("ipv6.src")) or packet.ip6tobin(if_nfo.address)
|
||||
local dst_mac = packet.mactobin("33:33:00:00:00:01")
|
||||
local dst_ip6 = packet.ip6tobin("ff02::1")
|
||||
local id_set = {}
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
--Multicast invalid destination exheader probe
|
||||
|
||||
local dnet = nmap.new_dnet()
|
||||
local pcap = nmap.new_socket()
|
||||
|
||||
try(dnet:ethernet_open(if_name))
|
||||
pcap:pcap_open(if_name, 128, false, "icmp6 and ip6[6:1] = 58 and ip6[40:1] = 4")
|
||||
|
||||
local probe = packet.Frame:new()
|
||||
probe.mac_src = src_mac
|
||||
probe.mac_dst = dst_mac
|
||||
probe.ip6_src = src_ip6
|
||||
probe.ip6_dst = dst_ip6
|
||||
|
||||
probe.echo_id = 5
|
||||
probe.echo_seq = 6
|
||||
probe.echo_data = "Nmap host discovery."
|
||||
probe:build_icmpv6_echo_request()
|
||||
probe:build_icmpv6_header()
|
||||
|
||||
probe.exheader = build_invalid_extension_header(packet.IPPROTO_ICMPV6)
|
||||
probe.ip6_nxt_hdr = packet.IPPROTO_DSTOPTS
|
||||
|
||||
probe:build_ipv6_packet()
|
||||
probe:build_ether_frame()
|
||||
|
||||
try(dnet:ethernet_send(probe.frame_buf))
|
||||
|
||||
pcap:set_timeout(1000)
|
||||
local pcap_timeout_count = 0
|
||||
local nse_timeout = 5
|
||||
local start_time = nmap:clock()
|
||||
local cur_time = nmap:clock()
|
||||
|
||||
local found_targets = 0
|
||||
|
||||
repeat
|
||||
local status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
cur_time = nmap:clock()
|
||||
if not status then
|
||||
pcap_timeout_count = pcap_timeout_count + 1
|
||||
else
|
||||
local reply = packet.Frame:new(layer2)
|
||||
if reply.mac_dst == src_mac then
|
||||
reply = packet.Packet:new(layer3)
|
||||
local target_addr = reply.ip6_src
|
||||
found_targets = found_targets + 1
|
||||
local identifier = get_identifier(reply.ip6_src)
|
||||
if not id_set[identifier] then
|
||||
id_set[identifier] = true
|
||||
local target_str = packet.toipv6(target_addr)
|
||||
target.add(target_str)
|
||||
end
|
||||
end
|
||||
end
|
||||
until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout
|
||||
|
||||
stdnse.print_debug(0, "[Invalid DSTOPTS] Found %d targets.", found_targets)
|
||||
|
||||
dnet:ethernet_close()
|
||||
pcap:pcap_close()
|
||||
|
||||
return true
|
||||
end
|
||||
179
scripts/targets-ipv6-multicast-slaac.nse
Normal file
179
scripts/targets-ipv6-multicast-slaac.nse
Normal file
@@ -0,0 +1,179 @@
|
||||
description = [[
|
||||
SLAAC-based host discovery.
|
||||
Do a very fast host discovery on link-local IPv6 network.
|
||||
]]
|
||||
|
||||
---
|
||||
-- @usage
|
||||
-- ./nmap -6 --script=slaac_host_discovery.nse --script-args 'newtargets,interface=eth0,ipv6="2001:da8:215:3320:223:aeff:fe5d:3b10"' -sP
|
||||
|
||||
author = "David and Weilin"
|
||||
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
|
||||
categories = {"discovery"}
|
||||
|
||||
require 'nmap'
|
||||
require 'target'
|
||||
require 'packet'
|
||||
require "os"
|
||||
require "math"
|
||||
|
||||
prerule = function()
|
||||
return nmap.is_privileged() and
|
||||
(stdnse.get_script_args("targets-ipv6-multicast.interface") or nmap.get_interface())
|
||||
end
|
||||
|
||||
catch = function()
|
||||
dnet:ethernet_close()
|
||||
pcap:pcap_close()
|
||||
end
|
||||
try = nmap.new_try(catch)
|
||||
|
||||
local function get_ipv6_interface_info_by_name(if_name)
|
||||
local ifaces = nmap.list_interfaces()
|
||||
local iface
|
||||
local if_nfo
|
||||
for _,iface in pairs(ifaces) do
|
||||
if if_name == iface.device and iface.address and (#iface.address>15 or string.find(iface.address, "::")) then
|
||||
if_nfo = iface
|
||||
return if_nfo
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function get_identifier(ip6_addr)
|
||||
return string.sub(ip6_addr, 9, 16)
|
||||
end
|
||||
|
||||
--- Get a Unique-local Address with random global ID.
|
||||
-- @param local_scope The scope of the address, local or reserved.
|
||||
-- @return A 16-byte string of IPv6 address, and the length of the prefix.
|
||||
local function get_radom_ula_prefix(local_scope)
|
||||
local ula_prefix
|
||||
math.randomseed(os.time())
|
||||
local global_id = string.char(math.random(256)-1,math.random(256)-1,math.random(256)-1,math.random(256)-1,math.random(256)-1)
|
||||
|
||||
if local_scope then
|
||||
ula_prefix = packet.ip6tobin("fd00::")
|
||||
else
|
||||
ula_prefix = packet.ip6tobin("fc00::")
|
||||
end
|
||||
ula_prefix = string.sub(ula_prefix,1,1) .. global_id .. string.sub(ula_prefix,7,-1)
|
||||
return ula_prefix,64
|
||||
end
|
||||
|
||||
--- Build an ICMPv6 payload of Router Advertisement.
|
||||
-- @param mac_src six-byte string of the source MAC address.
|
||||
-- @param prefix 16-byte string of IPv6 address.
|
||||
-- @param prefix_len integer that represents the length of the prefix.
|
||||
-- @param valid_time integer that represents the valid time of the prefix.
|
||||
-- @param preferred_time integer that represents the preferred time of the prefix.
|
||||
local function build_router_advert(mac_src,prefix,prefix_len,valid_time,preferred_time)
|
||||
local ra_msg = string.char(0x0, --cur hop limit
|
||||
0x08, --flags
|
||||
0x00,0x00, --router lifetime
|
||||
0x00,0x00,0x00,0x00, --reachable time
|
||||
0x00,0x00,0x00,0x00) --retrans timer
|
||||
local prefix_option_msg = string.char(prefix_len,
|
||||
0xc0) .. --flags: Onlink, Auto
|
||||
packet.set_u32("....",0,valid_time) ..
|
||||
packet.set_u32("....",0,preferred_time) ..
|
||||
string.char(0,0,0,0) .. --unknown
|
||||
prefix
|
||||
local icmpv6_prefix_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_PREFIX_INFORMATION,prefix_option_msg)
|
||||
local icmpv6_src_link_option = packet.Packet:set_icmpv6_option(packet.ND_OPT_SOURCE_LINKADDR,mac_src)
|
||||
local icmpv6_payload = ra_msg .. icmpv6_prefix_option .. icmpv6_src_link_option
|
||||
return icmpv6_payload
|
||||
end
|
||||
|
||||
action = function()
|
||||
local if_name = stdnse.get_script_args("targets-ipv6-multicast.interface") or nmap.get_interface()
|
||||
local if_nfo = get_ipv6_interface_info_by_name(if_name)
|
||||
if not if_nfo then
|
||||
stdnse.print_debug("Invalid interface: " .. if_name)
|
||||
return false
|
||||
end
|
||||
local src_mac = if_nfo.mac
|
||||
local src_ip6 = packet.ip6tobin(stdnse.get_script_args("ipv6.src")) or packet.ip6tobin(if_nfo.address)
|
||||
local dst_mac = packet.mactobin("33:33:00:00:00:01")
|
||||
local dst_ip6 = packet.ip6tobin("ff02::1")
|
||||
local id_set = {}
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
--SLAAC-based host discovery probe
|
||||
|
||||
local dnet = nmap.new_dnet()
|
||||
local pcap = nmap.new_socket()
|
||||
|
||||
try(dnet:ethernet_open(if_name))
|
||||
pcap:pcap_open(if_name, 128, true, "src ::0/128 and dst net ff02::1:0:0/96 and icmp6 and ip6[6:1] = 58 and ip6[40:1] = 135")
|
||||
|
||||
local actual_prefix = string.sub(src_ip6,1,8)
|
||||
local ula_prefix, prefix_len = get_radom_ula_prefix()
|
||||
|
||||
-- preferred_lifetime <= valid_lifetime.
|
||||
-- Nmap will get the whole IPv6 addresses of each host if the two parameters are both longer than 5 seconds.
|
||||
-- Sometimes it makes sense to regard the several addresses of a host as different hosts, as the host's administrator may apply different firewall configurations on them.
|
||||
local valid_lifetime = 6
|
||||
local preferred_lifetime = 6
|
||||
|
||||
local probe = packet.Frame:new()
|
||||
|
||||
probe.ip6_src = packet.mac_to_lladdr(src_mac)
|
||||
probe.ip6_dst = dst_ip6
|
||||
probe.mac_src = src_mac
|
||||
probe.mac_dst = packet.mactobin("33:33:00:00:00:01")
|
||||
|
||||
local icmpv6_payload = build_router_advert(src_mac,ula_prefix,prefix_len,valid_lifetime,preferred_lifetime)
|
||||
probe:build_icmpv6_header(packet.ND_ROUTER_ADVERT, 0, icmpv6_payload)
|
||||
probe:build_ipv6_packet()
|
||||
probe:build_ether_frame()
|
||||
|
||||
try(dnet:ethernet_send(probe.frame_buf))
|
||||
|
||||
local expected_mac_dst_prefix = packet.mactobin("33:33:ff:00:00:00")
|
||||
local expected_ip6_src = packet.ip6tobin("::")
|
||||
local expected_ip6_dst_prefix = packet.ip6tobin("ff02::1:0:0")
|
||||
|
||||
pcap:set_timeout(1000)
|
||||
local pcap_timeout_count = 0
|
||||
local nse_timeout = 5
|
||||
local start_time = nmap:clock()
|
||||
local cur_time = nmap:clock()
|
||||
|
||||
local found_targets = 0
|
||||
|
||||
repeat
|
||||
local status, length, layer2, layer3 = pcap:pcap_receive()
|
||||
cur_time = nmap:clock()
|
||||
if not status then
|
||||
pcap_timeout_count = pcap_timeout_count + 1
|
||||
else
|
||||
local reply = packet.Frame:new(layer2)
|
||||
if string.sub(reply.mac_dst, 1, 3) == string.sub(expected_mac_dst_prefix, 1, 3) then
|
||||
reply = packet.Packet:new(layer3)
|
||||
if reply.ip6_src == expected_ip6_src and
|
||||
string.sub(expected_ip6_dst_prefix,1,12) == string.sub(reply.ip6_dst,1,12) then
|
||||
local ula_target_addr_str = packet.toipv6(reply.ns_target)
|
||||
local identifier = get_identifier(reply.ns_target)
|
||||
found_targets = found_targets + 1
|
||||
--Filter out the reduplicative identifiers.
|
||||
--A host will send several NS packets with the same interface identifier if it receives several RA packets with different prefix during the discovery phase.
|
||||
if not id_set[identifier] then
|
||||
id_set[identifier] = true
|
||||
local actual_addr_str = packet.toipv6(actual_prefix .. identifier)
|
||||
target.add(actual_addr_str)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout
|
||||
|
||||
stdnse.print_debug(0, "[SLAAC] Found %d targets.", found_targets)
|
||||
|
||||
dnet:ethernet_close()
|
||||
pcap:pcap_close()
|
||||
return true
|
||||
end
|
||||
Reference in New Issue
Block a user