1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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
|