local ipOps = require "ipOps" local nmap = require "nmap" local stdnse = require "stdnse" local string = require "string" local table = require "table" local target = require "target" description = [[ This script runs in the pre-scanning phase to map IPv4 addresses onto IPv6 networks and add them to the scan queue. The technique is more general than what is technically termed "IPv4-mapped IPv6 addresses." The lower 4 bytes of the IPv6 network address are replaced with the 4 bytes of IPv4 address. When the IPv6 network is ::ffff:0:0/96, then the script generates IPv4-mapped IPv6 addresses. When the network is ::/96, then it generates IPv4-compatible IPv6 addresses. ]] --- -- @usage -- nmap -6 --script targets-ipv6-map4to6 --script-args newtargets,targets-ipv6-map4to6.IPv4Hosts={192.168.1.0/24},targets-ipv6-subnet={2001:db8:c0ca::/64} -- -- @output -- Pre-scan script results: -- | targets-ipv6-map4to6: -- | node count: 256 -- | addresses: -- |_ 2001:db8:c0ca:0:0:0:c0a8:100/120 -- -- @args targets-ipv6-map4to6.IPv4Hosts This must have at least one IPv4 -- Host for the script be able to work -- (Ex. 192.168.1.1 or -- { 192.168.1.1, 192.168.2.2 } ) or Subnet -- Addresses ( 192.168.1.0/24 or -- { 192.168.1.0/24, 192.168.2.0/24 } ) -- -- @args targets-ipv6-subnet Table/single IPv6 address with prefix -- (Ex. 2001:db8:c0ca::/48 or -- { 2001:db8:c0ca::/48, 2001:db8:FEA::/48 }) -- -- @xmloutput -- 256 -- -- 2001:db8:c0ca:0:0:0:c0a8:100/120 --
-- -- Version 1.4 -- Update 01/12/2014 - V 1.4 Update for inclusion in Nmap by Daniel Miller -- Update 05/05/2014 - V 1.3 Eliminate the Host phase. -- Update 05/05/2014 - V 1.2 Minor corrections and standardization. -- Update 18/10/2013 - V 1.1 Added SaveMemory option -- Update 29/03/2013 - V 1.0 Functional script -- Created 28/03/2013 - v0.1 Created by Raúl Fuentes -- author = "Raúl Armando Fuentes Samaniego" license = "Same as Nmap--See https://nmap.org/book/man-legal.html" categories = { "discovery", } local function split_prefix (net) local split = stdnse.strsplit("/", net) return split[1], tonumber(split[2]) end --- -- This function will add all the list of IPv4 host to IPv6 -- -- The most normal is returning X:X:X:X::Y.Y.Y.Y/128 -- The conversion is going to be totally IPv6 syntax (we are going to -- concatenate strings). -- @param IPv6_Network A IPv6 Address ( X:X:X:X::/YY ) -- @param IPv4SHosts A IPv4 String can be: X.X.X.X or X.X.X.X/YY -- @param addr_table A table to hold the generated addresses. -- @return Number Total succesfuly nodes added to the scan. -- @return Error A warning if something happened. (Nil otherwise) local From_4_to_6 = function (IPv6_Network, IPv4SHosts, addr_table) --We check if the PRefix are OK, anything less than 96 is fine local v6_base, IPv6_Prefix = split_prefix(IPv6_Network) if IPv6_Prefix > 96 then return 0, string.format("The IPv6 subnet %s can't support a direct Mapping 4 to 6.", IPv6_Network) end local sBin6, sError = ipOps.ip_to_bin(v6_base) if sBin6 == nil then return 0, sError end -- two options: String or Table, the bes thing to do: make string Table local tTabla if type(IPv4SHosts) == "table" then tTabla = IPv4SHosts else tTabla = { IPv4SHosts } end stdnse.debug1("Total IPv4 objects to analyze: %d for IPv6 subnet %s", #tTabla, IPv6_Network) local iTotal = 0 for _, Host in ipairs(tTabla) do stdnse.debug2("IPv4 Object: %s", Host) local v4base, prefix = split_prefix(Host) local sBin4 sBin4, sError = ipOps.ip_to_bin(v4base) if sBin4 == nil then return 0, sError end local IPAux IPAux, sError = ipOps.bin_to_ip(sBin6:sub(1, 96) .. sBin4) if prefix then prefix = prefix + (128 - 32) -- adjust for different address lengths IPAux = string.format("%s/%d", IPAux, prefix) else prefix = 128 end stdnse.debug2("IPv6 address: %s", IPAux) addr_table[#addr_table+1] = IPAux if target.ALLOW_NEW_TARGETS then local bool bool, sError = target.add(IPAux) if bool then iTotal = iTotal + 2^(128 - prefix) else stdnse.debug1("Error adding node %s: %s", IPAux, sError) end else iTotal = iTotal + 2^(128 - prefix) end end return iTotal end local IPv4Sub = stdnse.get_script_args(SCRIPT_NAME .. ".IPv4Hosts") local IPv6User = stdnse.get_script_args("targets-ipv6-subnet") --- -- We populated the host discovery list. local Prescanning = function () local errors = {} local tSalida = { Nodos = 0, addrs = {}, } local Grantotal = 0 stdnse.debug2("Beginning the work.") if type(IPv6User) == "string" then IPv6User = { IPv6User } end -- TODO: Gather IPv6 subnets from other sources. -- This was implemented in the original version of the script, but stripped -- for now until the other scripts are integrated. -- http://seclists.org/nmap-dev/2013/q4/285 for _, IPv6_Subnet in ipairs(IPv6User) do stdnse.debug1("Processing %s", IPv6_Subnet) local IPv6Host, sError = From_4_to_6(IPv6_Subnet, IPv4Sub, tSalida.addrs) if sError ~= nil then stdnse.debug1( "ERROR: One IPv6 subnet wasn't translated") errors[#errors+1] = sError end if IPv6Host then -- We need to concatenate the new nodes Grantotal = Grantotal + IPv6Host end end tSalida.Nodos = Grantotal if #errors > 0 then tSalida.Error = table.concat(errors, "\n") end return true, tSalida end --- -- The script need to be working with IPv6 -- --(To bad can't do it with both at same time ) function prerule () if not (nmap.address_family() == "inet6") then stdnse.verbose1("This script is IPv6 only.") return false end -- Because Nmap current limitation of working ONE single IP family we must -- be sure to have everything for work the Mapped IPv4 to IPv6 if IPv4Sub == nil then stdnse.verbose1( "There are no IPv4 addresses to map!\z You must provide it using the %s.IPv4Hosts script-arg.", SCRIPT_NAME) return false end -- Now we need to have based IPv6 Prefix, the most important is the previous -- known but we have a last-option too . if IPv6User == nil then stdnse.verbose1("There are no IPv6 subnets to scan!\z You must provide it using the targets-ipv6-subnet script-arg.") return false end return true end function action () --Vars for created the final report local tOutput = stdnse.output_table() local bExito = false local tSalida bExito, tSalida = Prescanning() -- Now we adapt the exit to tOutput and add the hosts to the target! tOutput.warning = tSalida.Error if bExito then --Final report of the Debug Lvl of Prescanning stdnse.debug1("Successful Mapped IPv4 to IPv6 added to the scan: %d", tSalida.Nodos) tOutput["node count"] = tSalida.Nodos tOutput["addresses"] = tSalida.addrs if tSalida.Error then stdnse.debug1("Warnings: %s", tSalida.Error) end else stdnse.debug1("Was unable to add nodes to the scan list due this error: %s", tSalida.Error) end return tOutput end