diff --git a/CHANGELOG b/CHANGELOG index c5d301b67..f232df27c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,11 @@ #Nmap Changelog ($Id$); -*-text-*- +o [NSE] New rand.lua library uses the best sources of random available on the + system to generate random strings. [Daniel Miller] + +o [NSE] Collected utility functions for manipulating and searching tables into + a new library, tableaux.lua. [Daniel Miller] + o [GH#1355] When searching for Lua header files, actually use them where they are found instead of forcing /usr/include. [Fabrice Fontaine, Daniel Miller] diff --git a/nse_main.lua b/nse_main.lua index 656024ee6..1afa26f23 100644 --- a/nse_main.lua +++ b/nse_main.lua @@ -266,17 +266,7 @@ end -- recursively copy a table, for host/port tables -- not very rigorous, but it doesn't need to be -local function tcopy (t) - local tc = {}; - for k,v in pairs(t) do - if type(v) == "table" then - tc[k] = tcopy(v); - else - tc[k] = v; - end - end - return tc; -end +local tcopy = require "tableaux".tcopy -- copies the host table while preserving the registry local function host_copy(t) diff --git a/nselib/creds.lua b/nselib/creds.lua index c56f08ccf..116070656 100644 --- a/nselib/creds.lua +++ b/nselib/creds.lua @@ -120,6 +120,7 @@ local ipOps = require "ipOps" local nmap = require "nmap" local stdnse = require "stdnse" local table = require "table" +local tableaux = require "tableaux" _ENV = stdnse.module("creds", stdnse.seeall) @@ -306,7 +307,7 @@ Account = { -- which will cause the table to yield its values sorted by key. local function sorted_pairs (sortby) return function (t) - local order = stdnse.keys(t) + local order = tableaux.keys(t) table.sort(order, sortby) return coroutine.wrap(function() for i,k in ipairs(order) do diff --git a/nselib/data/http-default-accounts-fingerprints.lua b/nselib/data/http-default-accounts-fingerprints.lua index 0a78bf4f7..9d60ee7e0 100644 --- a/nselib/data/http-default-accounts-fingerprints.lua +++ b/nselib/data/http-default-accounts-fingerprints.lua @@ -5,6 +5,7 @@ local math = require "math" local shortport = require "shortport" local stdnse = require "stdnse" local table = require "table" +local tableaux = require "tableaux" local url = require "url" local have_openssl, openssl = pcall(require, 'openssl') @@ -24,20 +25,6 @@ local have_openssl, openssl = pcall(require, 'openssl') -- * login_check - Login function of the target --- --- Recursively copy a table. --- Only recurs when a value is a table, other values are copied by assignment. -local function tcopy (t) - local tc = {}; - for k,v in pairs(t) do - if type(v) == "table" then - tc[k] = tcopy(v); - else - tc[k] = v; - end - end - return tc; -end - --- -- Requests given path using http.get() but disabling cache and redirects. -- @param host The host to connect to @@ -47,7 +34,7 @@ end -- @return A response table (see library http.lua for description) --- local function http_get_simple (host, port, path, options) - local opts = tcopy(options or {}) + local opts = tableaux.tcopy(options or {}) opts.bypass_cache = true opts.no_cache = true opts.redirect_ok = false @@ -66,7 +53,7 @@ end -- @return A response table (see library http.lua for description) --- local function http_post_simple (host, port, path, options, postdata) - local opts = tcopy(options or {}) + local opts = tableaux.tcopy(options or {}) opts.no_cache = true opts.redirect_ok = false return http.post(host, port, path, opts, nil, postdata) @@ -172,7 +159,7 @@ end -- @see url.build --- local function url_build_defaults (host, port, parsed) - local parts = tcopy(parsed or {}) + local parts = tableaux.tcopy(parsed or {}) parts.host = parts.host or stdnse.get_hostname(host, port) parts.scheme = parts.scheme or shortport.ssl(host, port) and "https" or "http" if not parts.port and port.number ~= url.get_default_port(parts.scheme) then diff --git a/nselib/dhcp.lua b/nselib/dhcp.lua index bffa0cae0..ac7949b0d 100644 --- a/nselib/dhcp.lua +++ b/nselib/dhcp.lua @@ -22,6 +22,7 @@ local stdnse = require "stdnse" local string = require "string" local strbuf = require "strbuf" local table = require "table" +local tableaux = require "tableaux" _ENV = stdnse.module("dhcp", stdnse.seeall) @@ -37,16 +38,7 @@ request_types = DHCPINFORM = 8 } ---Invert a one-to-one mapping -local function invert(t) - local out = {} - for k, v in pairs(t) do - out[v] = k - end - return out -end - -request_types_str = invert(request_types) +request_types_str = tableaux.invert(request_types) ---Read an IP address or a list of IP addresses. Print an error if the length isn't a multiple of 4. -- diff --git a/nselib/http.lua b/nselib/http.lua index ed807659e..2dba6a491 100644 --- a/nselib/http.lua +++ b/nselib/http.lua @@ -122,6 +122,7 @@ local slaxml = require "slaxml" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "tableaux" local url = require "url" local smbauth = require "smbauth" local unicode = require "unicode" @@ -135,20 +136,6 @@ USER_AGENT = stdnse.get_script_args('http.useragent') or "Mozilla/5.0 (compatibl local host_header = stdnse.get_script_args('http.host') local MAX_REDIRECT_COUNT = 5 --- Recursively copy a table. --- Only recurs when a value is a table, other values are copied by assignment. -local function tcopy (t) - local tc = {}; - for k,v in pairs(t) do - if type(v) == "table" then - tc[k] = tcopy(v); - else - tc[k] = v; - end - end - return tc; -end - --- Recursively copy into a table any elements from another table whose key it -- doesn't have. local function table_augment(to, from) @@ -881,8 +868,8 @@ local function getPipelineMax(response) if response then local hdr = response.header or {} local opts = stdnse.strsplit("%s+", (hdr.connection or ""):lower()) - if stdnse.contains(opts, "close") then return 1 end - if response.version >= "1.1" or stdnse.contains(opts, "keep-alive") then + if tableaux.contains(opts, "close") then return 1 end + if response.version >= "1.1" or tableaux.contains(opts, "keep-alive") then return tonumber((hdr["keep-alive"] or ""):match("max=(%d+)")) or 40 end end @@ -992,7 +979,7 @@ local function lookup_cache (method, host, port, path, options) else mutex "done"; record.last_used = os.time(); - return tcopy(record.result), state; + return tableaux.tcopy(record.result), state; end end end @@ -1035,7 +1022,7 @@ local function insert_cache (state, response) cache[key] = state.old_record; else local record = { - result = tcopy(response), + result = tableaux.tcopy(response), last_used = os.time(), method = state.method, size = type(response.body) == "string" and #response.body or 0, @@ -1288,7 +1275,7 @@ function generic_request(host, port, method, path, options) if digest_auth and have_ssl then -- If we want to do digest authentication, we have to make an initial -- request to get realm, nonce and other fields. - local options_with_auth_removed = tcopy(options) + local options_with_auth_removed = tableaux.tcopy(options) options_with_auth_removed["auth"] = nil local r = generic_request(host, port, method, path, options_with_auth_removed) local h = r.header['www-authenticate'] @@ -1304,7 +1291,7 @@ function generic_request(host, port, method, path, options) if ntlm_auth and have_ssl then - local custom_options = tcopy(options) -- to be sent with the type 1 request + local custom_options = tableaux.tcopy(options) -- to be sent with the type 1 request custom_options["auth"] = nil -- removing the auth options -- let's check if the target supports ntlm with a simple get request. -- Setting a timeout here other than nil messes up the authentication if this is the first device sending diff --git a/nselib/shortport.lua b/nselib/shortport.lua index 5da0ca101..36ba34e11 100644 --- a/nselib/shortport.lua +++ b/nselib/shortport.lua @@ -8,24 +8,11 @@ local nmap = require "nmap" local stdnse = require "stdnse" +local tableaux = require "tableaux" local comm _ENV = stdnse.module("shortport", stdnse.seeall) ---- --- See if a table contains a value. --- @param t A table representing a set. --- @param value The value to check for. --- @return True if t contains value, false otherwise. -local function includes(t, value) - for _, elem in ipairs(t) do - if elem == value then - return true - end - end - return false -end - --- Just like includes, but can match simple port ranges +-- Just like tableaux.contains, but can match simple port ranges local function port_includes(t, value) for _, elem in ipairs(t) do if elem == value then @@ -84,8 +71,8 @@ portnumber = function(ports, protos, states) return function(host, port) return port_includes(ports, port.number) - and includes(protos, port.protocol) - and includes(states, port.state) + and tableaux.contains(protos, port.protocol, true) + and tableaux.contains(states, port.state, true) end end @@ -120,9 +107,9 @@ service = function(services, protos, states) end return function(host, port) - return includes(services, port.service) - and includes(protos, port.protocol) - and includes(states, port.state) + return tableaux.contains(services, port.service, true) + and tableaux.contains(protos, port.protocol, true) + and tableaux.contains(states, port.state, true) end end diff --git a/nselib/smb2.lua b/nselib/smb2.lua index 369d676a2..e84534b58 100644 --- a/nselib/smb2.lua +++ b/nselib/smb2.lua @@ -16,6 +16,7 @@ local string = require "string" local stdnse = require "stdnse" local nmap = require "nmap" local table = require "table" +local tableaux = require "tableaux" local match = require "match" _ENV = stdnse.module("smb2", stdnse.seeall) @@ -252,7 +253,7 @@ function negotiate_v2(smb, overrides) ) -- The next block gets interpreted in different ways depending on the dialect - if stdnse.contains(overrides['Dialects'], 0x0311) then + if tableaux.contains(overrides['Dialects'], 0x0311) then is_0311 = true end diff --git a/nselib/sslcert.lua b/nselib/sslcert.lua index 4a2e4aa3d..c6873c285 100644 --- a/nselib/sslcert.lua +++ b/nselib/sslcert.lua @@ -32,6 +32,7 @@ local smtp = require "smtp" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "tableaux" local tls = require "tls" local vnc = require "vnc" local xmpp = require "xmpp" @@ -637,7 +638,7 @@ StartTLS = { } local best for i=1, #auth_order do - if stdnse.contains(v.vencrypt.types, auth_order[i]) then + if tableaux.contains(v.vencrypt.types, auth_order[i]) then best = auth_order[i] break end diff --git a/nselib/sslv2.lua b/nselib/sslv2.lua index 2040aad38..31190bc48 100644 --- a/nselib/sslv2.lua +++ b/nselib/sslv2.lua @@ -7,6 +7,7 @@ local stdnse = require "stdnse" local table = require "table" +local tableaux = require "tableaux" local nmap = require "nmap" local sslcert = require "sslcert" local string = require "string" @@ -333,7 +334,7 @@ function test_sslv2 (host, port) socket:set_timeout(timeout) - local ssl_v2_hello = client_hello(stdnse.keys(SSL_CIPHER_CODES)) + local ssl_v2_hello = client_hello(tableaux.keys(SSL_CIPHER_CODES)) socket:send(ssl_v2_hello) diff --git a/nselib/stdnse.lua b/nselib/stdnse.lua index e8f5fc2d1..73670bd58 100644 --- a/nselib/stdnse.lua +++ b/nselib/stdnse.lua @@ -1106,20 +1106,6 @@ function filename_escape(s) end end ---- Check for the presence of a value in a table ---@param tab the table to search into ---@param item the searched value ---@return Boolean true if the item was found, false if not ---@return The index or key where the value was found, or nil -function contains(tab, item) - for k, val in pairs(tab) do - if val == item then - return true, k - end - end - return false, nil -end - --- Returns a conservative timeout for a host -- -- If the host parameter is a NSE host table with a times.timeout @@ -1156,19 +1142,6 @@ function get_timeout(host, max_timeout, min_timeout) return t end ---- Returns the keys of a table as an array --- @param t The table --- @return A table of keys -function keys(t) - local ret = {} - local k, v = next(t) - while k do - ret[#ret+1] = k - k, v = next(t, k) - end - return ret -end - -- Returns the case insensitive pattern of given parameter -- Useful while doing case insensitive pattern match using string library. -- https://stackoverflow.com/questions/11401890/case-insensitive-lua-pattern-matching/11402486#11402486 diff --git a/nselib/tableaux.lua b/nselib/tableaux.lua new file mode 100644 index 000000000..59fd7d40e --- /dev/null +++ b/nselib/tableaux.lua @@ -0,0 +1,91 @@ +--- Auxiliary functions for table manipulation +-- +-- @author Daniel Miller +-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html +-- @class module +-- @name tableaux + +local next = next +local pairs = pairs +local ipairs = ipairs +local type = type +local _ENV = {} + +local tcopy_local +--- Recursively copy a table. +-- +-- Uses simple assignment to copy keys and values from a table, recursing into +-- subtables as necessary. +-- @param t the table to copy +-- @return a deep copy of the table +function tcopy (t) + local tc = {}; + for k,v in pairs(t) do + if type(v) == "table" then + tc[k] = tcopy_local(v); + else + tc[k] = v; + end + end + return tc; +end +tcopy_local = tcopy + +--- Copy one level of a table. +-- +-- Iterates over the keys of a table and copies their values into a new table. +-- If any values are tables, they are copied by reference only, and modifying +-- the copy will modify the original table value as well. +-- @param t the table to copy +-- @return a shallow copy of the table +function shallow_tcopy(t) + local k = next(t) + local out = {} + while k do + out[k] = t[k] + k = next(t, k) + end + return out +end + +--- Invert a one-to-one mapping +-- @param t the table to invert +-- @return an inverted mapping +function invert(t) + local out = {} + for k, v in pairs(t) do + out[v] = k + end + return out +end + +--- Check for the presence of a value in a table +--@param t the table to search into +--@param item the searched value +--@array (optional) If true, then use ipairs to only search the array indices of the table. +--@return Boolean true if the item was found, false if not +--@return The index or key where the value was found, or nil +function contains(t, item, array) + local iter = array and ipairs or pairs + for k, val in iter(t) do + if val == item then + return true, k + end + end + return false, nil +end + +--- Returns the keys of a table as an array +-- @param t The table +-- @return A table of keys +function keys(t) + local ret = {} + local k, v = next(t) + while k do + ret[#ret+1] = k + k, v = next(t, k) + end + return ret +end + +return _ENV diff --git a/nselib/tls.lua b/nselib/tls.lua index 1f4b0a7e5..9c0124272 100644 --- a/nselib/tls.lua +++ b/nselib/tls.lua @@ -14,6 +14,7 @@ local string = require "string" local math = require "math" local os = require "os" local table = require "table" +local tableaux = require "tableaux" local rand = require "rand" _ENV = stdnse.module("tls", stdnse.seeall) @@ -676,15 +677,8 @@ DEFAULT_CIPHERS = { } local function find_key(t, value) - local k, v - - for k, v in pairs(t) do - if v == value then - return k - end - end - - return nil + local found, v = tableaux.contains(t, value) + return v end -- Keep this local to enforce use of the cipher_info function diff --git a/nselib/unicode.lua b/nselib/unicode.lua index f20894fe4..0bab5067e 100644 --- a/nselib/unicode.lua +++ b/nselib/unicode.lua @@ -9,6 +9,7 @@ local string = require "string" local table = require "table" local stdnse = require "stdnse" local unittest = require "unittest" +local tableaux = require "tableaux" _ENV = stdnse.module("unicode", stdnse.seeall) -- Localize a few functions for a tiny speed boost, since these will be looped @@ -291,15 +292,6 @@ function utf8_dec(buf, pos) return pos + 1 + n, cp end ---Invert a one-to-one mapping -local function invert(t) - local out = {} - for k, v in pairs(t) do - out[v] = k - end - return out -end - -- Code Page 437, native US-English Windows OEM code page local cp437_decode = { [0x80] = 0x00c7, @@ -431,7 +423,7 @@ local cp437_decode = { [0xfe] = 0x25a0, [0xff] = 0x00a0, } -local cp437_encode = invert(cp437_decode) +local cp437_encode = tableaux.invert(cp437_decode) ---Encode a Unicode code point to CP437 -- diff --git a/nselib/url.lua b/nselib/url.lua index 9f8bb181b..00dbe3aca 100644 --- a/nselib/url.lua +++ b/nselib/url.lua @@ -37,6 +37,7 @@ local stdnse = require "stdnse" local string = require "string" local table = require "table" local idna = require "idna" +local tableaux = require "tableaux" local unicode = require "unicode" local unittest = require "unittest" local base = _G @@ -419,15 +420,7 @@ function get_default_port (scheme) return get_default_port_ports[(scheme or ""):lower()] end -local function invert(t) - local out = {} - for k, v in pairs(t) do - out[v] = k - end - return out -end - -get_default_scheme_schemes = invert(get_default_port_ports) +get_default_scheme_schemes = tableaux.invert(get_default_port_ports) --- -- Provides the default URI scheme for a given port. diff --git a/nselib/vnc.lua b/nselib/vnc.lua index a4cf19e27..7b35bf563 100644 --- a/nselib/vnc.lua +++ b/nselib/vnc.lua @@ -30,6 +30,7 @@ local nmap = require "nmap" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "tableaux" _ENV = stdnse.module("vnc", stdnse.seeall) local HAVE_SSL, openssl = pcall(require,'openssl') @@ -72,7 +73,7 @@ end local function first_of (list, lookup) for i=1, #list do - if stdnse.contains(lookup, list[i]) then + if tableaux.contains(lookup, list[i]) then return list[i] end end diff --git a/scripts/ajp-methods.nse b/scripts/ajp-methods.nse index a65445957..703c32921 100644 --- a/scripts/ajp-methods.nse +++ b/scripts/ajp-methods.nse @@ -2,6 +2,7 @@ local ajp = require "ajp" local shortport = require "shortport" local stdnse = require "stdnse" local table = require "table" +local tableaux = require "table" description = [[ Discovers which options are supported by the AJP (Apache JServ @@ -44,7 +45,7 @@ local UNINTERESTING_METHODS = { "GET", "HEAD", "POST", "OPTIONS" } local function filter_out(t, filter) local result = {} for _, e in ipairs(t) do - if ( not(stdnse.contains(filter, e)) ) then + if ( not(tableaux.contains(filter, e)) ) then result[#result + 1] = e end end diff --git a/scripts/bitcoinrpc-info.nse b/scripts/bitcoinrpc-info.nse index 325c86344..d83a1393f 100644 --- a/scripts/bitcoinrpc-info.nse +++ b/scripts/bitcoinrpc-info.nse @@ -6,6 +6,7 @@ local shortport = require "shortport" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "table" description = [[ Obtains information from a Bitcoin server by calling getinfo on its JSON-RPC interface. @@ -124,7 +125,7 @@ end local function formatpairs(info) local result = stdnse.output_table() - local keys = stdnse.keys(info) + local keys = tableaux.keys(info) table.sort(keys) for _, k in ipairs(keys) do if info[k] ~= "" then diff --git a/scripts/dns-nsec-enum.nse b/scripts/dns-nsec-enum.nse index 2ef34ecf0..36ce39b28 100644 --- a/scripts/dns-nsec-enum.nse +++ b/scripts/dns-nsec-enum.nse @@ -4,6 +4,7 @@ local shortport = require "shortport" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "tableaux" description = [[ Enumerates DNS names using the DNSSEC NSEC-walking technique. @@ -119,16 +120,6 @@ local function guess_domain(host) end end -local function invert(t) - local result = {} - - for k, v in pairs(t) do - result[v] = k - end - - return result -end - -- RFC 952: "A 'name' is a text string up to 24 characters drawn from the -- alphabet (A-Z), digits (0-9), minus sign (-), and period (.). ... The first -- character must be an alpha character." @@ -138,7 +129,7 @@ end -- RFC 2782: An underscore (_) is prepended to the service identifier to avoid -- collisions with DNS labels that occur in nature. local DNS_CHARS = { string.byte("-0123456789_abcdefghijklmnopqrstuvwxyz", 1, -1) } -local DNS_CHARS_INV = invert(DNS_CHARS) +local DNS_CHARS_INV = tableaux.invert(DNS_CHARS) -- Return the lexicographically next component, or nil if component is the -- lexicographically last. diff --git a/scripts/dns-nsec3-enum.nse b/scripts/dns-nsec3-enum.nse index f74ac86fc..a13bc243a 100644 --- a/scripts/dns-nsec3-enum.nse +++ b/scripts/dns-nsec3-enum.nse @@ -5,6 +5,7 @@ local base32 = require "base32" local nmap = require "nmap" local string = require "string" local table = require "table" +local tableaux = require "table" local rand = require "rand" local openssl = stdnse.silent_require "openssl" @@ -217,7 +218,7 @@ local function query_for_hashes(host,subdomain,domain) for _, nsec3 in ipairs(auth_filter(result, "NSEC3")) do local h1 = string.lower(remove_suffix(nsec3.dname,domain)) local h2 = string.lower(nsec3.hash.base32) - if not stdnse.contains(all_results,"nexthash " .. h1 .. " " .. h2) then + if not tableaux.contains(all_results,"nexthash " .. h1 .. " " .. h2) then table.insert(all_results, "nexthash " .. h1 .. " " .. h2) stdnse.debug1("nexthash " .. h1 .. " " .. h2) end diff --git a/scripts/duplicates.nse b/scripts/duplicates.nse index 8c3b9f0d0..fcc4bc098 100644 --- a/scripts/duplicates.nse +++ b/scripts/duplicates.nse @@ -3,6 +3,7 @@ local nmap = require "nmap" local ssh1 = require "ssh1" local stdnse = require "stdnse" local table = require "table" +local tableaux = require "table" description = [[ Attempts to discover multihomed systems by analysing and comparing @@ -68,7 +69,7 @@ local function processSSLCerts(tab) for host, v in pairs(tab) do for port, sha1 in pairs(v) do ssl_certs[sha1] = ssl_certs[sha1] or {} - if ( not stdnse.contains(ssl_certs[sha1], host.ip) ) then + if ( not tableaux.contains(ssl_certs[sha1], host.ip) ) then table.insert(ssl_certs[sha1], host.ip) end end @@ -97,7 +98,7 @@ local function processSSHKeys(tab) hostkeys[fp] = {} end -- discard duplicate IPs - if not stdnse.contains(hostkeys[fp], ip) then + if not tableaux.contains(hostkeys[fp], ip) then table.insert(hostkeys[fp], ip) end end @@ -121,12 +122,12 @@ local function processNBStat(tab) local results, mac_table, name_table = {}, {}, {} for host, v in pairs(tab) do mac_table[v.mac] = mac_table[v.mac] or {} - if ( not(stdnse.contains(mac_table[v.mac], host.ip)) ) then + if ( not(tableaux.contains(mac_table[v.mac], host.ip)) ) then table.insert(mac_table[v.mac], host.ip) end name_table[v.server_name] = name_table[v.server_name] or {} - if ( not(stdnse.contains(name_table[v.server_name], host.ip)) ) then + if ( not(tableaux.contains(name_table[v.server_name], host.ip)) ) then table.insert(name_table[v.server_name], host.ip) end end @@ -157,7 +158,7 @@ local function processMAC(tab) if ( host.mac_addr ) then mac = stdnse.format_mac(host.mac_addr) mac_table[mac] = mac_table[mac] or {} - if ( not(stdnse.contains(mac_table[mac], host.ip)) ) then + if ( not(tableaux.contains(mac_table[mac], host.ip)) ) then table.insert(mac_table[mac], host.ip) end end diff --git a/scripts/fcrdns.nse b/scripts/fcrdns.nse index 0edb7c4d9..f94957e8c 100644 --- a/scripts/fcrdns.nse +++ b/scripts/fcrdns.nse @@ -4,6 +4,7 @@ local nmap = require "nmap" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "table" description = [[ Performs a Forward-confirmed Reverse DNS lookup and reports anomalous results. @@ -127,7 +128,7 @@ action = function(host) str_out = nil elseif str_out == nil then -- we failed, and need to format a short output string - fail_addrs = stdnse.keys(fail_addrs) + fail_addrs = tableaux.keys(fail_addrs) if #fail_addrs > 0 then table.sort(fail_addrs) str_out = string.format("FAIL (%s)", table.concat(fail_addrs, ", ")) diff --git a/scripts/fingerprint-strings.nse b/scripts/fingerprint-strings.nse index a1bd3496d..adc8c41a0 100644 --- a/scripts/fingerprint-strings.nse +++ b/scripts/fingerprint-strings.nse @@ -3,6 +3,7 @@ local nmap = require "nmap" local lpeg = require "lpeg" local U = require "lpeg-utility" local table = require "table" +local tableaux = require "table" description = [[ Prints the readable strings from service fingerprints of unknown services. @@ -87,7 +88,7 @@ action = function(host, port) -- Get the table of probe responses local responses = U.parse_fp(port.version.service_fp) -- extract the probe names - local probes = stdnse.keys(responses) + local probes = tableaux.keys(responses) -- If there were no probes (WEIRD!) we're done. if #probes <= 0 then return nil diff --git a/scripts/hostmap-crtsh.nse b/scripts/hostmap-crtsh.nse index 36978970e..d10ef92fb 100644 --- a/scripts/hostmap-crtsh.nse +++ b/scripts/hostmap-crtsh.nse @@ -50,6 +50,7 @@ local stdnse = require "stdnse" local string = require "string" local target = require "target" local table = require "table" +local tableaux = require "table" -- Different from stdnse.get_hostname -- this function returns nil if the host is only known by IP address @@ -69,7 +70,7 @@ local function query_ctlogs(host) return string.format("Error: could not GET http://%s%s", "crt.sh", query) end for domain in string.gmatch(response.body, "name_value\":\"(.-)\"") do - if not stdnse.contains(hostnames, domain) and domain ~= "" then + if not tableaux.contains(hostnames, domain) and domain ~= "" then if target.ALLOW_NEW_TARGETS then local status, err = target.add(domain) end diff --git a/scripts/http-affiliate-id.nse b/scripts/http-affiliate-id.nse index 4e5b36c7f..0f41ce1a2 100644 --- a/scripts/http-affiliate-id.nse +++ b/scripts/http-affiliate-id.nse @@ -4,6 +4,7 @@ local re = require "re" local shortport = require "shortport" local stdnse = require "stdnse" local table = require "table" +local tableaux = require "table" description = [[ Grabs affiliate network IDs (e.g. Google AdSense or Analytics, Amazon @@ -133,7 +134,7 @@ local function postaction() siteids[id] = {} end -- discard duplicate IPs - if not stdnse.contains(siteids[id], site) then + if not tableaux.contains(siteids[id], site) then table.insert(siteids[id], site) end end diff --git a/scripts/http-cross-domain-policy.nse b/scripts/http-cross-domain-policy.nse index c28a243df..8a9deac2c 100644 --- a/scripts/http-cross-domain-policy.nse +++ b/scripts/http-cross-domain-policy.nse @@ -4,6 +4,7 @@ local vulns = require "vulns" local nmap = require "nmap" local shortport = require "shortport" local table = require "table" +local tableaux = require "table" local string = require "string" local slaxml = require "slaxml" @@ -156,7 +157,7 @@ local tlds_instantdomainsearch = {".com", ".net", ".org", ".co", ".info", ".biz" --- local function check_domain (domain) local name, tld = domain:match("(%w*)%.*(%w*%.%w+)$") - if not(stdnse.contains(tlds_instantdomainsearch, tld)) then + if not(tableaux.contains(tlds_instantdomainsearch, tld)) then stdnse.debug(1, "TLD '%s' is not supported by instantdomainsearch.com. Check manually.", tld) return nil end @@ -227,11 +228,11 @@ function check_crossdomain(host, port, lookup) if domain ~= nil then --Deals with tlds with double extension local tld = domain:match("%w*(%.%w*)%.%w+$") - if tld ~= nil and not(stdnse.contains(tlds_instantdomainsearch, tld)) then + if tld ~= nil and not(tableaux.contains(tlds_instantdomainsearch, tld)) then domain = domain:match("%w*%.(.*)$") end --We add domains only once as they can appear multiple times - if not(stdnse.contains(trusted_domains, domain)) then + if not(tableaux.contains(trusted_domains, domain)) then stdnse.debug(1, "Added trusted domain:%s", domain) table.insert(trusted_domains, domain) --Lookup domains if script argument is set @@ -280,7 +281,7 @@ Forgery attacks, and may allow third parties to access sensitive data meant for local check, domains, domains_available, content = check_crossdomain(host, port, lookup) local mt = {__tostring=function(p) return ("%s:\n %s"):format(p.name, p.body:gsub("\n", "\n ")) end} if check then - if stdnse.contains(domains, "*") or stdnse.contains(domains, "https://") or stdnse.contains(domains, "http://") then + if tableaux.contains(domains, "*") or tableaux.contains(domains, "https://") or tableaux.contains(domains, "http://") then vuln.state = vulns.STATE.VULN else vuln.state = vulns.STATE.LIKELY_VULN diff --git a/scripts/http-form-brute.nse b/scripts/http-form-brute.nse index 3ea90039c..43645a1e3 100644 --- a/scripts/http-form-brute.nse +++ b/scripts/http-form-brute.nse @@ -6,6 +6,7 @@ local shortport = require "shortport" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "tableaux" local url = require "url" local rand = require "rand" @@ -310,20 +311,6 @@ local detect_form = function (host, port, path, hostname) return nil, string.format("Unable to detect a login form at path %q", path) end --- Recursively copy a table. --- Only recurs when a value is a table, other values are copied by assignment. -local function tcopy (t) - local tc = {}; - for k,v in pairs(t) do - if type(v) == "table" then - tc[k] = tcopy(v); - else - tc[k] = v; - end - end - return tc; -end - -- TODO: expire cookies local function update_cookies (old, new) for i, c in ipairs(new) do @@ -398,9 +385,9 @@ Driver = { if not thread then thread = { -- copy of form fields so we don't clobber another thread's passvar - params = tcopy(self.options.formfields), + params = tableaux.tcopy(self.options.formfields), -- copy of options so we don't clobber another thread's cookies - opts = tcopy(self.options.http_options), + opts = tableaux.tcopy(self.options.http_options), } self.options.threads[tid] = thread end diff --git a/scripts/http-grep.nse b/scripts/http-grep.nse index 84cb2308d..350f7c3b1 100644 --- a/scripts/http-grep.nse +++ b/scripts/http-grep.nse @@ -3,6 +3,7 @@ local httpspider = require "httpspider" local shortport = require "shortport" local stdnse = require "stdnse" local table = require "table" +local tableaux = require "table" description = [[ @@ -304,7 +305,7 @@ action = function(host, port) count = count + pattern_count for match in body:gmatch(pattern) do local validate = BUILT_IN_PATTERNS[pattern_name]and BUILT_IN_PATTERNS[pattern_name]['validate'] or default - if validate(match) and not stdnse.contains(all_match, match) then + if validate(match) and not tableaux.contains(all_match, match) then table.insert(pattern_type, "+ " .. shortenMatch(match)) table.insert(all_match, match) else diff --git a/scripts/http-methods.nse b/scripts/http-methods.nse index 6abb57575..55bd679ee 100644 --- a/scripts/http-methods.nse +++ b/scripts/http-methods.nse @@ -4,6 +4,7 @@ local shortport = require "shortport" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "table" local rand = require "rand" description = [[ @@ -80,7 +81,7 @@ local function filter_out(t, filter) local result = {} local _, e, f for _, e in ipairs(t) do - if not stdnse.contains(filter, e) then + if not tableaux.contains(filter, e) then result[#result + 1] = e end end @@ -159,14 +160,14 @@ action = function(host, port) local status_lines = {} for _, method in pairs(SAFE_METHODS) do - if not stdnse.contains(methods, method) then + if not tableaux.contains(methods, method) then table.insert(to_test, method) end end if test_all_unsafe then for _, method in pairs(UNSAFE_METHODS) do - if not stdnse.contains(methods, method) then + if not tableaux.contains(methods, method) then table.insert(to_test, method) end end @@ -212,7 +213,7 @@ action = function(host, port) if method == "OPTIONS" then -- Use the saved value. str = options_status_line - elseif stdnse.contains(to_test, method) then + elseif tableaux.contains(to_test, method) then -- use the value saved earlier. str = status_lines[method] -- this case arises when methods in the Public or Allow headers are retested. diff --git a/scripts/http-rfi-spider.nse b/scripts/http-rfi-spider.nse index 250667063..1d0504902 100644 --- a/scripts/http-rfi-spider.nse +++ b/scripts/http-rfi-spider.nse @@ -75,6 +75,7 @@ local url = require 'url' local httpspider = require 'httpspider' local string = require 'string' local table = require 'table' +local tableaux = require 'tableaux' -- this is a variable that will hold the function that checks if a pattern we are searching for is in -- response's body @@ -176,17 +177,6 @@ local function check_responses(urls, responses) return suspects end --- return a shallow copy of t -local function tcopy(t) - local k = next(t) - local out = {} - while k do - out[k] = t[k] - k = next(t, k) - end - return out -end - portrule = shortport.port_or_service( {80, 443}, {"http", "https"}, "tcp", "open") function action(host, port) @@ -268,7 +258,7 @@ function action(host, port) local rfi = { name = "Possible RFI in form fields" } for path, forms in pairs(output.Forms) do for fid, fobj in pairs(forms) do - local out = tcopy(fobj["Vulnerable fields"]) + local out = tableaux.shallow_tcopy(fobj["Vulnerable fields"]) out.name = string.format('Form "%s" at %s (action %s) with fields:', fid, path, fobj["Action"]) table.insert(rfi, out) @@ -279,7 +269,7 @@ function action(host, port) if #output.Queries > 0 then local rfi = { name = "Possible RFI in query parameters" } for path, queries in pairs(output.Queries) do - local out = tcopy(queries) + local out = tableaux.shallow_tcopy(queries) out.name = string.format('Path %s with queries:', path) table.insert(rfi, out) end diff --git a/scripts/http-webdav-scan.nse b/scripts/http-webdav-scan.nse index 2757fea30..75d056103 100644 --- a/scripts/http-webdav-scan.nse +++ b/scripts/http-webdav-scan.nse @@ -1,6 +1,7 @@ local http = require "http" local ipOps = require "ipOps" local table = require "table" +local tableaux = require "table" local shortport = require "shortport" local stdnse = require "stdnse" @@ -108,7 +109,7 @@ local function getIPs(body) end end end - return stdnse.keys(result) + return tableaux.keys(result) end -- a function to test the PROPFIND method. diff --git a/scripts/ms-sql-tables.nse b/scripts/ms-sql-tables.nse index 2a775efdc..cb2f08f7c 100644 --- a/scripts/ms-sql-tables.nse +++ b/scripts/ms-sql-tables.nse @@ -2,6 +2,7 @@ local mssql = require "mssql" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "table" -- -*- mode: lua -*- -- vim: set filetype=lua : @@ -177,7 +178,7 @@ local function process_instance( instance ) end for k, v in pairs(dbs.rows) do - if ( not( stdnse.contains( done_dbs, v[1] ) ) ) then + if ( not( tableaux.contains( done_dbs, v[1] ) ) ) then local query = [[ SELECT so.name 'table', sc.name 'column', st.name 'type', sc.length FROM %s..syscolumns sc, %s..sysobjects so, %s..systypes st WHERE so.id = sc.id AND sc.xtype=st.xtype AND diff --git a/scripts/nbd-info.nse b/scripts/nbd-info.nse index dfc505043..60a9aa99c 100644 --- a/scripts/nbd-info.nse +++ b/scripts/nbd-info.nse @@ -2,6 +2,7 @@ local nbd = require "nbd" local shortport = require "shortport" local stdnse = require "stdnse" local table = require "table" +local tableaux = require "table" description = [[ Displays protocol and block device information from NBD servers. @@ -160,7 +161,7 @@ action = function(host, port) -- Format exported block device information. local exports = stdnse.output_table() local no_shares = true - local names = stdnse.keys(comm.exports) + local names = tableaux.keys(comm.exports) -- keep exports in stable order table.sort(names) for _, name in ipairs(names) do diff --git a/scripts/reverse-index.nse b/scripts/reverse-index.nse index 269d0a0f7..715d0bfb3 100644 --- a/scripts/reverse-index.nse +++ b/scripts/reverse-index.nse @@ -2,6 +2,7 @@ local ipOps = require "ipOps" local nmap = require "nmap" local stdnse = require "stdnse" local table = require "table" +local tableaux = require "table" description = [[ Creates a reverse index at the end of scan output showing which hosts run a @@ -101,7 +102,7 @@ postaction = function() local results = stdnse.output_table() for proto, ports in pairs(db) do - local portnumbers = stdnse.keys(ports) + local portnumbers = tableaux.keys(ports) table.sort(portnumbers) for _, port in ipairs(portnumbers) do local result_entries = ports[port] diff --git a/scripts/smb-enum-groups.nse b/scripts/smb-enum-groups.nse index 78beec6ba..fd491960c 100644 --- a/scripts/smb-enum-groups.nse +++ b/scripts/smb-enum-groups.nse @@ -3,6 +3,7 @@ local smb = require "smb" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "table" description = [[ Obtains a list of groups from the remote Windows system, as well as a list of the group's users. @@ -148,14 +149,14 @@ action = function(host) local response = stdnse.output_table() local response_str = {} - local domains = stdnse.keys(groups) + local domains = tableaux.keys(groups) table.sort(domains) for _, domain_name in ipairs(domains) do local dom_groups = stdnse.output_table() response[domain_name] = dom_groups local domain_data = groups[domain_name] - local rids = stdnse.keys(domain_data) + local rids = tableaux.keys(domain_data) table.sort(rids) for _, rid in ipairs(rids) do local group_data = domain_data[rid] diff --git a/scripts/ssh-hostkey.nse b/scripts/ssh-hostkey.nse index dbf33647f..873abbaf2 100644 --- a/scripts/ssh-hostkey.nse +++ b/scripts/ssh-hostkey.nse @@ -6,6 +6,7 @@ local ssh2 = require "ssh2" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "table" local base64 = require "base64" local comm = require "comm" @@ -189,7 +190,7 @@ local function check_keys(host, keys, f) end end else - if stdnse.contains(possible_host_names, parts[1]) then + if tableaux.contains(possible_host_names, parts[1]) then stdnse.debug2("Found an entry that matches: %s", parts[1]) table.insert(keys_from_file, ("%s %s"):format(parts[2], parts[3])) else @@ -367,7 +368,7 @@ local function postaction() } end -- discard duplicate IPs - if not stdnse.contains(hostkeys[fp], ip) then + if not tableaux.contains(hostkeys[fp], ip) then table.insert(hostkeys[fp], ip) end end diff --git a/scripts/ssl-ccs-injection.nse b/scripts/ssl-ccs-injection.nse index a1fa03ee9..4be7d50dd 100644 --- a/scripts/ssl-ccs-injection.nse +++ b/scripts/ssl-ccs-injection.nse @@ -4,6 +4,7 @@ local sslcert = require('sslcert') local stdnse = require('stdnse') local vulns = require('vulns') local tls = require 'tls' +local tableaux = require "table" description = [[ Detects whether a server is vulnerable to the SSL/TLS "CCS Injection" @@ -143,7 +144,7 @@ local function test_ccs_injection(host, port, version) ["record_protocol"] = (version == "SSLv3") and "SSLv3" or "TLSv1.0", -- Claim to support every cipher -- Doesn't work with IIS, but IIS isn't vulnerable - ["ciphers"] = stdnse.keys(tls.CIPHERS), + ["ciphers"] = tableaux.keys(tls.CIPHERS), ["compressors"] = {"NULL"}, ["extensions"] = { -- Claim to support common elliptic curves diff --git a/scripts/ssl-heartbleed.nse b/scripts/ssl-heartbleed.nse index ce3deab57..586268f9c 100644 --- a/scripts/ssl-heartbleed.nse +++ b/scripts/ssl-heartbleed.nse @@ -4,6 +4,7 @@ local shortport = require('shortport') local sslcert = require('sslcert') local stdnse = require('stdnse') local string = require "string" +local tableaux = require "table" local vulns = require('vulns') local have_tls, tls = pcall(require,'tls') assert(have_tls, "This script requires the tls.lua library from https://nmap.org/nsedoc/lib/tls.html") @@ -73,7 +74,7 @@ local function testversion(host, port, version) ["protocol"] = version, -- Claim to support every cipher -- Doesn't work with IIS, but IIS isn't vulnerable - ["ciphers"] = stdnse.keys(tls.CIPHERS), + ["ciphers"] = tableaux.keys(tls.CIPHERS), ["compressors"] = {"NULL"}, ["extensions"] = { -- Claim to support common elliptic curves diff --git a/scripts/ssl-poodle.nse b/scripts/ssl-poodle.nse index 4f1c9a878..9b2b12149 100644 --- a/scripts/ssl-poodle.nse +++ b/scripts/ssl-poodle.nse @@ -4,6 +4,7 @@ local sslcert = require "sslcert" local stdnse = require "stdnse" local string = require "string" local table = require "table" +local tableaux = require "tableaux" local tls = require "tls" local listop = require "listop" local vulns = require "vulns" @@ -61,16 +62,6 @@ dependencies = {"ssl-enum-ciphers", "https-redirect"} -- http://seclists.org/nmap-dev/2010/q1/859 local CHUNK_SIZE = 64 -local function keys(t) - local ret = {} - local k, v = next(t) - while k do - ret[#ret+1] = k - k, v = next(t, k) - end - return ret -end - -- Add additional context (protocol) to debug output local function ctx_log(level, protocol, fmt, ...) return stdnse.print_debug(level, "(%s) " .. fmt, protocol, ...) @@ -184,20 +175,6 @@ local function base_extensions(host) } end --- Recursively copy a table. --- Only recurs when a value is a table, other values are copied by assignment. -local function tcopy (t) - local tc = {}; - for k,v in pairs(t) do - if type(v) == "table" then - tc[k] = tcopy(v); - else - tc[k] = v; - end - end - return tc; -end - -- Find which ciphers out of group are supported by the server. local function find_ciphers_group(host, port, protocol, group) local name, protocol_worked, record, results @@ -305,7 +282,7 @@ local function check_fallback_scsv(host, port, protocol, ciphers) ["extensions"] = base_extensions(host), } - t["ciphers"] = tcopy(ciphers) + t["ciphers"] = tableaux.tcopy(ciphers) t.ciphers[#t.ciphers+1] = "TLS_FALLBACK_SCSV" -- TODO: remove this check after the next release. diff --git a/scripts/sslv2-drown.nse b/scripts/sslv2-drown.nse index cb23f0b89..b725ff476 100644 --- a/scripts/sslv2-drown.nse +++ b/scripts/sslv2-drown.nse @@ -1,6 +1,7 @@ local nmap = require "nmap" local shortport = require "shortport" local table = require "table" +local tableaux = require "table" local stdnse = require "stdnse" local string = require "string" local sslcert = require "sslcert" @@ -132,7 +133,7 @@ local function do_setup(host, port) end end socket:set_timeout(timeout) - socket:send(sslv2.client_hello(stdnse.keys(sslv2.SSL_CIPHER_CODES))) + socket:send(sslv2.client_hello(tableaux.keys(sslv2.SSL_CIPHER_CODES))) local status, buffer = sslv2.record_buffer(socket) if not status then socket:close() diff --git a/scripts/targets-ipv6-multicast-mld.nse b/scripts/targets-ipv6-multicast-mld.nse index 3f127b528..6a48418bf 100644 --- a/scripts/targets-ipv6-multicast-mld.nse +++ b/scripts/targets-ipv6-multicast-mld.nse @@ -4,6 +4,7 @@ local nmap = require "nmap" local stdnse = require "stdnse" local tab = require "tab" local table = require "table" +local tableaux = require "table" local target = require "target" local multicast = require "multicast" @@ -103,7 +104,7 @@ end local function format_output(results) local output = tab.new() local xmlout = {} - local ips = stdnse.keys(results) + local ips = tableaux.keys(results) table.sort(ips) for i, ip in ipairs(ips) do diff --git a/scripts/tls-ticketbleed.nse b/scripts/tls-ticketbleed.nse index 9d81ef67a..f1188e981 100644 --- a/scripts/tls-ticketbleed.nse +++ b/scripts/tls-ticketbleed.nse @@ -4,6 +4,7 @@ local shortport = require("shortport") local sslcert = require("sslcert") local stdnse = require("stdnse") local table = require("table") +local tableaux = require "table" local tls = require "tls" local vulns = require("vulns") local rand = require "rand" @@ -213,7 +214,7 @@ local function is_vuln(host, port, version) ["session_id"] = sid_old, -- Claim to support every cipher -- Doesn't work with IIS, but only F5 products should be affected - ["ciphers"] = stdnse.keys(tls.CIPHERS), + ["ciphers"] = tableaux.keys(tls.CIPHERS), ["compressors"] = {"NULL"}, ["extensions"] = { -- Claim to support common elliptic curves diff --git a/scripts/xmlrpc-methods.nse b/scripts/xmlrpc-methods.nse index 1640ed078..94c7ac3c5 100644 --- a/scripts/xmlrpc-methods.nse +++ b/scripts/xmlrpc-methods.nse @@ -6,6 +6,7 @@ local stdnse = require "stdnse" local strbuf = require "strbuf" local string = require "string" local table = require "table" +local tableaux = require "table" description = [[ Performs XMLRPC Introspection via the system.listMethods method. @@ -86,7 +87,7 @@ action = function(host, port) } parser:parseSAX(response.body, {stripWhitespace=true}) - if nmap.verbosity() > 1 and stdnse.contains(output["Supported Methods"], "system.methodHelp") then + if nmap.verbosity() > 1 and tableaux.contains(output["Supported Methods"], "system.methodHelp") then for i, method in ipairs(output["Supported Methods"]) do data = ' system.methodHelp ' .. method .. ' ' response = http.post(host, port, url, {header = {["Content-Type"] = "application/x-www-form-urlencoded"}}, nil, data)