coolbins/system/usr/share/nmap/scripts/targets-ipv6-wordlist.nse

284 lines
9.1 KiB
Lua

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 <ra.fuentess.sam+nmap@gmail.com>
--
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