diff --git a/CHANGELOG b/CHANGELOG index 2dbd0feba..65db3e1f0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added targets-xml to extract target addresses from previous Nmap XML + results files. [Daniel Miller] + o [NSE] [GH#232] Added ssl-dh-params to check for problems with weak, non-safe, and export-grade Diffie-Hellman parameters in TLS handshakes. This includes the LOGJAM vulnerability (CVE-2015-4000). [Jacob Gajek] diff --git a/scripts/script.db b/scripts/script.db index 31539e976..b1c59a1f6 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -485,6 +485,7 @@ Entry { filename = "targets-ipv6-multicast-slaac.nse", categories = { "broadcast Entry { filename = "targets-ipv6-wordlist.nse", categories = { "discovery", } } Entry { filename = "targets-sniffer.nse", categories = { "broadcast", "discovery", "safe", } } Entry { filename = "targets-traceroute.nse", categories = { "discovery", "safe", } } +Entry { filename = "targets-xml.nse", categories = { "safe", } } Entry { filename = "teamspeak2-version.nse", categories = { "version", } } Entry { filename = "telnet-brute.nse", categories = { "brute", "intrusive", } } Entry { filename = "telnet-encryption.nse", categories = { "discovery", "safe", } } diff --git a/scripts/targets-xml.nse b/scripts/targets-xml.nse new file mode 100644 index 000000000..8ebcd81cd --- /dev/null +++ b/scripts/targets-xml.nse @@ -0,0 +1,142 @@ +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