143 lines
3.5 KiB
Plaintext
143 lines
3.5 KiB
Plaintext
|
local io = require "io"
|
||
|
local nmap = require "nmap"
|
||
|
local slaxml = require "slaxml"
|
||
|
local stdnse = require "stdnse"
|
||
|
local string = require "string"
|
||
|
local table = require "table"
|
||
|
local target = require "target"
|
||
|
|
||
|
description = [[
|
||
|
Loads addresses from an Nmap XML output file for scanning.
|
||
|
|
||
|
Address type (IPv4 or IPv6) is determined according to whether -6 is specified to nmap.
|
||
|
]]
|
||
|
|
||
|
---
|
||
|
--@args targets-xml.iX Filename of an Nmap XML file to import
|
||
|
--@args targets-xml.state Only hosts with this status will have their addresses
|
||
|
-- input. Default: "up"
|
||
|
--
|
||
|
--@usage
|
||
|
-- nmap --script targets-xml --script-args newtargets,iX=oldscan.xml
|
||
|
--
|
||
|
--@output
|
||
|
--Pre-scan script results:
|
||
|
--|_targets-xml: Added 16 ipv4 addresses
|
||
|
--
|
||
|
--@xmloutput
|
||
|
--16
|
||
|
|
||
|
-- TODO: more filtering options: port status, string search, etc.
|
||
|
|
||
|
author = "Daniel Miller"
|
||
|
categories = {"safe"}
|
||
|
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
|
||
|
|
||
|
local filename = stdnse.get_script_args(SCRIPT_NAME .. ".iX")
|
||
|
|
||
|
prerule = function ()
|
||
|
if not filename then
|
||
|
stdnse.verbose1("Need to supply a file name with the %s.iX argument", SCRIPT_NAME);
|
||
|
return false
|
||
|
end
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
local startElement = {
|
||
|
host = function (state)
|
||
|
state.addresses = {}
|
||
|
state.up = nil
|
||
|
end,
|
||
|
status = function (state)
|
||
|
state.parser._call.attribute = function (name, attribute)
|
||
|
if name == "state" then
|
||
|
state.up = attribute == state.status
|
||
|
end
|
||
|
end
|
||
|
end,
|
||
|
address = function (state)
|
||
|
state.parser._call.attribute = function (name, attribute)
|
||
|
if name == "addrtype" then
|
||
|
state.valid = attribute == state.addrtype
|
||
|
elseif name == "addr" then
|
||
|
state.address = attribute
|
||
|
end
|
||
|
end
|
||
|
end,
|
||
|
}
|
||
|
|
||
|
local closeElement = {
|
||
|
host = function (state)
|
||
|
if state.up then
|
||
|
state.added = state.added + #state.addresses
|
||
|
if target.ALLOW_NEW_TARGETS then
|
||
|
target.add(table.unpack(state.addresses))
|
||
|
end
|
||
|
end
|
||
|
state.up = nil
|
||
|
end,
|
||
|
status = function (state)
|
||
|
state.parser._call.attribute = nil
|
||
|
end,
|
||
|
address = function (state)
|
||
|
if state.valid and state.address then
|
||
|
table.insert(state.addresses, state.address)
|
||
|
end
|
||
|
state.parser._call.attribute = nil
|
||
|
state.address = nil
|
||
|
state.valid = false
|
||
|
end,
|
||
|
}
|
||
|
|
||
|
action = function ()
|
||
|
local status = stdnse.get_script_args(SCRIPT_NAME .. ".state") or "up"
|
||
|
local input, err = io.open(filename, "r")
|
||
|
if not input then
|
||
|
stdnse.debug1("Couldn't open %s: %s", filename, err)
|
||
|
return nil
|
||
|
end
|
||
|
|
||
|
local state = {
|
||
|
status = status,
|
||
|
addrtype = "ipv4",
|
||
|
added = 0,
|
||
|
}
|
||
|
if nmap.address_family() == "inet6" then
|
||
|
state.addrtype = "ipv6"
|
||
|
end
|
||
|
|
||
|
state.parser = slaxml.parser:new({
|
||
|
startElement = function (name)
|
||
|
return startElement[name] and startElement[name](state) or nil
|
||
|
end,
|
||
|
closeElement = function (name)
|
||
|
return startElement[name] and closeElement[name](state) or nil
|
||
|
end,
|
||
|
})
|
||
|
|
||
|
local buf = ""
|
||
|
local function next_chunk()
|
||
|
local read, starts, ends
|
||
|
repeat
|
||
|
read = input:read(8192)
|
||
|
if not read then
|
||
|
return buf, true
|
||
|
end
|
||
|
starts, ends = string.find(read, ">.-$")
|
||
|
if not starts then
|
||
|
buf = buf .. read
|
||
|
end
|
||
|
until starts
|
||
|
local ret = buf .. string.sub(read, 1, starts)
|
||
|
buf = string.sub(read, starts+1)
|
||
|
return ret, false
|
||
|
end
|
||
|
local chunk
|
||
|
local eof = false
|
||
|
while not eof do
|
||
|
chunk, eof = next_chunk()
|
||
|
state.parser:parseSAX(chunk)
|
||
|
end
|
||
|
return state.added, ("Found %s %s addresses"):format(state.added, state.addrtype)
|
||
|
end
|