From 0d47952611198ef6b1163f366dc03922d20b1475 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:42:04 +0200 Subject: Adding upstream version 7.94+git20230807.3be01efb1+dfsg. Signed-off-by: Daniel Baumann --- scripts/targets-ipv6-multicast-invalid-dst.nse | 199 +++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 scripts/targets-ipv6-multicast-invalid-dst.nse (limited to 'scripts/targets-ipv6-multicast-invalid-dst.nse') diff --git a/scripts/targets-ipv6-multicast-invalid-dst.nse b/scripts/targets-ipv6-multicast-invalid-dst.nse new file mode 100644 index 0000000..3f08d38 --- /dev/null +++ b/scripts/targets-ipv6-multicast-invalid-dst.nse @@ -0,0 +1,199 @@ +local coroutine = require "coroutine" +local ipOps = require "ipOps" +local nmap = require "nmap" +local packet = require "packet" +local stdnse = require "stdnse" +local string = require "string" +local tab = require "tab" +local table = require "table" +local target = require "target" + +description = [[ +Sends an ICMPv6 packet with an invalid extension header to the +all-nodes link-local multicast address (ff02::1) to +discover (some) available hosts on the LAN. This works because some +hosts will respond to this probe with an ICMPv6 Parameter Problem +packet. +]] + +--- +-- @usage +-- ./nmap -6 --script=targets-ipv6-multicast-invalid-dst.nse --script-args 'newtargets,interface=eth0' -sP +-- @output +-- Pre-scan script results: +-- | targets-ipv6-multicast-invalid-dst: +-- | IP: 2001:0db8:0000:0000:0000:0000:0000:0001 MAC: 11:22:33:44:55:66 IFACE: eth0 +-- |_ Use --script-args=newtargets to add the results as targets +-- @args newtargets If true, add discovered targets to the scan queue. +-- @args targets-ipv6-multicast-invalid-dst.interface The interface to use for host discovery. + +author = {"David Fifield", "Xu Weilin"} + +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" + +categories = {"discovery","broadcast"} + + +prerule = function() + return nmap.is_privileged() +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) + -- RFC 2640, section 4.2 defines the TLV format of options headers. + -- It is important that the first byte have 10 in the most significant + -- bits; that instructs the receiver to send a Parameter Problem. + -- Option type 0x80 is unallocated; see + -- http://www.iana.org/assignments/ipv6-parameters/. + return string.char(nxt_hdr, 0) .. --next header, length 8 + "\x80\x01\x00\x00\x00\x00" +end + +local function get_interfaces() + local interface_name = stdnse.get_script_args(SCRIPT_NAME .. ".interface") + or nmap.get_interface() + + -- interfaces list (decide which interfaces to broadcast on) + local interfaces = {} + if interface_name then + -- single interface defined + local if_table = nmap.get_interface_info(interface_name) + if if_table and ipOps.ip_to_str(if_table.address) and if_table.link == "ethernet" then + interfaces[#interfaces + 1] = if_table + else + stdnse.debug1("Interface not supported or not properly configured.") + end + else + for _, if_table in ipairs(nmap.list_interfaces()) do + if ipOps.ip_to_str(if_table.address) and if_table.link == "ethernet" then + table.insert(interfaces, if_table) + end + end + end + + return interfaces +end + +local function single_interface_broadcast(if_nfo, results) + stdnse.debug1("Starting " .. SCRIPT_NAME .. " on " .. if_nfo.device) + + local condvar = nmap.condvar(results) + local src_mac = if_nfo.mac + local src_ip6 = ipOps.ip_to_str(if_nfo.address) + local dst_mac = packet.mactobin("33:33:00:00:00:01") + local dst_ip6 = ipOps.ip_to_str("ff02::1") + + ---------------------------------------------------------------------------- + --Multicast invalid destination exheader probe + + local dnet = nmap.new_dnet() + local pcap = nmap.new_socket() + + local function catch () + dnet:ethernet_close() + pcap:pcap_close() + end + local try = nmap.new_try(catch) + + try(dnet:ethernet_open(if_nfo.device)) + pcap:pcap_open(if_nfo.device, 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.ip_bin_src = src_ip6 + probe.ip_bin_dst = dst_ip6 + + -- In addition to setting an invalid option in + -- build_invalid_extension_header, we set an unknown ICMPv6 type of + -- 254. (See http://www.iana.org/assignments/icmpv6-parameters for + -- allocations.) Mac OS X 10.6 appears to send a Parameter Problem + -- response only if both of these conditions are met. In this we differ + -- from the alive6 tool, which sends a proper echo request. + probe.icmpv6_type = 254 + probe.icmpv6_code = 0 + -- Add a non-empty payload too. + probe.icmpv6_payload = "\x00\x00\x00\x00" + probe:build_icmpv6_header() + + probe.exheader = build_invalid_extension_header(packet.IPPROTO_ICMPV6) + probe.ip6_nhdr = 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 addrs = {} + + 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 l2reply = packet.Frame:new(layer2) + if l2reply.mac_dst == src_mac then + local reply = packet.Packet:new(layer3) + local target_str = reply.ip_src + if not results[target_str] then + if target.ALLOW_NEW_TARGETS then + target.add(target_str) + end + results[#results + 1] = { address = target_str, mac = stdnse.format_mac(l2reply.mac_src), iface = if_nfo.device } + results[target_str] = true + end + end + end + until pcap_timeout_count >= 2 or cur_time - start_time >= nse_timeout + + dnet:ethernet_close() + pcap:pcap_close() + + condvar("signal") +end + +local function format_output(results) + local output = tab.new() + + for _, record in ipairs(results) do + tab.addrow(output, "IP: " .. record.address, "MAC: " .. record.mac, "IFACE: " .. record.iface) + end + if #results > 0 then + output = { tab.dump(output) } + if not target.ALLOW_NEW_TARGETS then + output[#output + 1] = "Use --script-args=newtargets to add the results as targets" + end + return stdnse.format_output(true, output) + end +end + +action = function() + local threads = {} + local results = {} + local condvar = nmap.condvar(results) + + for _, if_nfo in ipairs(get_interfaces()) do + -- create a thread for each interface + local co = stdnse.new_thread(single_interface_broadcast, if_nfo, results) + threads[co] = true + end + + repeat + for thread in pairs(threads) do + if coroutine.status(thread) == "dead" then threads[thread] = nil end + end + if ( next(threads) ) then + condvar "wait" + end + until next(threads) == nil + + return format_output(results) +end -- cgit v1.2.3