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-wordlist.nse | 283 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 scripts/targets-ipv6-wordlist.nse (limited to 'scripts/targets-ipv6-wordlist.nse') diff --git a/scripts/targets-ipv6-wordlist.nse b/scripts/targets-ipv6-wordlist.nse new file mode 100644 index 0000000..163da01 --- /dev/null +++ b/scripts/targets-ipv6-wordlist.nse @@ -0,0 +1,283 @@ +local ipOps = require "ipOps" +local nmap = require "nmap" +local stdnse = require "stdnse" +local string = require "string" +local stringaux = require "stringaux" +local target = require "target" +local datafiles = require "datafiles" +local table = require "table" +local math = require "math" + +description = [[ +Adds IPv6 addresses to the scan queue using a wordlist of hexadecimal "words" +that form addresses in a given subnet. +]] + +--- +-- @usage +-- nmap -6 -p 80 --script targets-ipv6-wordlist --script-args newtargets,targets-ipv6-subnet={2001:db8:c0ca::/64} +-- +-- @output +-- Pre-scan script results: +-- | targets-ipv6-wordlist: +-- |_ node count: 1254 +-- +-- @args targets-ipv6-wordlist.wordlist File containing hexadecimal words for +-- building addresses, one per line. Default: +-- nselib/data/targets-ipv6-wordlist +-- @args targets-ipv6-wordlist.nsegments Number User can +-- indicate exactly how big the word must be on +-- Segments of 16 bits. +-- @args targets-ipv6-wordlist.fillright With this argument +-- the script will fill remaining zeros to the right +-- instead of left (2001:db8:c0a:dead:: instead of +-- 2001:db8:c0ca::dead) +-- @args targets-ipv6-subnet table/single IPv6 +-- address with prefix (Ex. 2001:db8:c0ca::/48 or +-- { 2001:db8:c0ca::/48, 2001:db8:FEA::/48 } ) + +-- Updated 03/12/2014 - V1.4 Update for inclusion in Nmap +-- Updated 21/05/2014 - V1.3 Eliminate the host phase. +-- Updated 06/05/2014 - V1.2 Minor corrections and standardization. +-- Created 29/04/2013 - v1.0 Created by Raul Fuentes +-- + +author = "Raúl Fuentes" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = { + "discovery" +} + +local function split_prefix (net) + local split = stringaux.strsplit("/", net) + return split[1], tonumber(split[2]) +end + +--- +-- Get a Prefix and for that one will add all the valid words we known. +-- +-- However two arguments from the user can affect how calculated the hosts. +-- n-segments fix to pick a number of segments (by default is any segment +-- enough small for be inside of the subnet prefix) and fill-right which alter +-- where we place the remaining zeros (Default the left). +-- @param Direccion String IPv6 address (Subnet) +-- @param Prefijo Number Prefix value of subnet +-- @param TablaPalabras Table containing all the elements to search. +-- @param User_Segs Number of segments to search. +-- @param User_Right Boolean for fill right or left (Default) +-- @return Boolean True if was successful the operation +-- @return Number Total of successfully nodes added to the scan list. +-- @return Error Any error generated, default: "" not nil. +local CrearRangoHosts = function (Direccion, Prefijo, TablaPalabras, + User_Segs, User_Right) + + local IPv6Bin, Error = ipOps.ip_to_bin(Direccion) + + if IPv6Bin == nil then + return false, 0, Error + end + + -- We have (128 - n ) / ( 16 ) + -- The first part are how many bits are left to hosts portion + -- The Second part is the size of the segments (16 bits). + local MaxRangoSegmentos + if User_Segs == nil then + MaxRangoSegmentos = math.ceil((128 - Prefijo) / 16) + User_Segs = false + else + MaxRangoSegmentos = tonumber(User_Segs) + end + + stdnse.debug1("Will be calculated %d hosts for the subnet: %s/%s", #TablaPalabras, Direccion, Prefijo) + + local iTotal = 0 + -- Palabras is a table with two elements Segmento & Binario + for Indice, Palabras in ipairs(TablaPalabras) do + + if ((tonumber(Palabras.Segmento) <= MaxRangoSegmentos) and + User_Segs == false) or + (User_Segs and (tonumber(Palabras.Segmento) == MaxRangoSegmentos)) then + + -- We are going to add binaries values but the question is + -- whenever must fill with zeros? + local Filler = string.rep("0", 128 - (Prefijo + #Palabras.Binario)) + + local Host + if User_Right ~= nil then + Host = IPv6Bin:sub(1, Prefijo) .. Palabras.Binario .. Filler + else + Host = IPv6Bin:sub(1, Prefijo) .. Filler .. Palabras.Binario + end + + -- We pass the binaries to valid IPv6 + local Error + Host, Error = ipOps.bin_to_ip(Host) + if Host == nil then + -- Something is very wrong but we don-t stop + stdnse.debug1("Failed to create IPv6 address: %s", Error) + else + if target.ALLOW_NEW_TARGETS then + local bAux, sAux = target.add(Host) + if bAux then + iTotal = iTotal + 1 + else + stdnse.debug1("Had been a error adding the node %s: %s", Host, sAux) + end + end + end + end + end + + return true, iTotal +end + +--- +-- Parsing process of concatenate each word on the dictionary with subnetworks. +-- +--@param filename The name of the file to parse +-- @return Table Table of elements returned (Nil if there was a error) +-- @return String Empty if there is no error, otherwise the error message. +local LeerArchivo = function (filename) + -- [ "^%s*(%w+)%s+[^#]+" ] = "^%s*%w+%s+([^#]+)" } + local bBoolean, Archivo = datafiles.parse_file(filename, + {"^([0-9a-fA-F]+)$",}) + if bBoolean ~= true then + return nil, Archivo + end + + local Candidatos = {} + local Registro = { + ["Segmento"] = 0, + ["Binario"] = "0", + } + + for index, reg in pairs(Archivo) do + Registro = { + ["Segmento"] = 0, + ["Binario"] = "0", + } + + Registro.Segmento = math.ceil(#reg / 4) + Registro.Binario = ipOps.hex_to_bin(reg) + table.insert(Candidatos, Registro) + + end + + stdnse.debug1("%d candidate words", #Candidatos) + return Candidatos, "" +end + +--- +-- We get the info we need from the user and other scripts then we add them to +-- our file! +-- +-- (So easy that seem we need to make them obscure) +local Prescanning = function () + local tSalida = { + Nodos = 0, + Error = "", + } + + -- First we get the info from known prefixes because we need those Prefixes + local IPv6PrefijoUsuario = stdnse.get_script_args "targets-ipv6-subnet" + local User_Segs = stdnse.get_script_args "targets-ipv6-wordlist.nsegments" + local User_Right = stdnse.get_script_args "targets-ipv6-wordlist.fillright" + local wordlist = (stdnse.get_script_args("targets-ipv6-wordlist.wordlist") + or "nselib/data/targets-ipv6-wordlist") + + -- Second, we read our vital table + local TablaPalabras, sError = LeerArchivo(wordlist) + + if TablaPalabras == nil then + tSalida.Error = sError + return false, tSalida + end + + -- We pass all the prefixes to one single table (health for the eyes) + if IPv6PrefijoUsuario == nil then + tSalida.Error = "There is not IPv6 subnets to try to scan!." .. + " You can run a script for discovering or adding your own" .. + " with the arg: targets-ipv6-subnet." + return false, tSalida + end + + local IPv6PrefijosTotales = {} + if IPv6PrefijoUsuario ~= nil then + if type(IPv6PrefijoUsuario) == "string" then + stdnse.verbose2("Number of Prefixes Known from other sources: 1 ") + table.insert(IPv6PrefijosTotales, IPv6PrefijoUsuario) + elseif type(IPv6PrefijoUsuario) == "table" then + stdnse.verbose2("Number of Prefixes Known from other sources: " .. #IPv6PrefijoUsuario) + for _, PrefixAux in ipairs(IPv6PrefijoUsuario) do + table.insert(IPv6PrefijosTotales, PrefixAux) + end + end + end + + -- We begin to explore all thoses prefixes and retrieve our work here + for _, PrefixAux in ipairs(IPv6PrefijosTotales) do + local Direccion, Prefijo = split_prefix(PrefixAux) + local bSalida, nodes, sError = CrearRangoHosts(Direccion, Prefijo, + TablaPalabras, User_Segs, User_Right) + + if bSalida ~= true then + stdnse.debug1("There was a error for the prefix %s: %s", PrefixAux, sError) + end + + if sError and sError ~= "" then + -- Not all the error are fatal for the script. + tSalida.Error = tSalida.Error .. "\n" .. sError + end + + tSalida.Nodos = tSalida.Nodos + nodes + end + + + return true, tSalida +end + + +--- +-- The script need to be working with IPv6 +function prerule () + if not (nmap.address_family() == "inet6") then + stdnse.verbose1("Need to be executed for IPv6.") + return false + end + + if stdnse.get_script_args 'newtargets' == nil then + stdnse.verbose1(" Will only work on " .. + "pre-scanning. The argument newtargets is needed for the host-scanning" .. + " to work.") + end + + return true +end + + +function action () + + --Vars for created the final report + local tOutput = stdnse.output_table() + + local bExito, tSalida = Prescanning() + + -- Now we adapt the exit to tOutput and add the hosts to the target! + if tSalida.Error and tSalida.Error ~= "" then + tOutput.warning = tSalida.Error + stdnse.debug1("Was unable to add nodes to the scan list due this error: %s", + tSalida.Error) + end + + if bExito then + if tSalida.Nodos == 0 then + stdnse.verbose2("No nodes were added " .. + " to scan list! You can increase verbosity for more information" .. + " (maybe not newtargets argument?) ") + end + tOutput["node count"] = tSalida.Nodos + end + + + return tOutput +end -- cgit v1.2.3