-- -- (C) 2013-23 - ntop.org -- -- -- This file implements some utility functions used by the REST API -- in the vulnerability pages -- -- -- https://geekflare.com/nmap-vulnerability-scan/ -- cd /usr/share/nmap/scripts/ -- git clone https://github.com/scipag/vulscan.git -- ln -s `pwd`/scipag_vulscan /usr/share/nmap/scripts/vulscan -- cd vulscan/utilities/updater/ -- chmod +x updateFiles.sh -- ./updateFiles.sh -- -- Example: -- nmap -sV --script vulscan --script-args vulscandb=openvas.csv -p 80,233 -- -- -- exploitdb.csv -- osvdb.csv -- securitytracker.csv -- openvas.csv -- scipvuldb.csv -- xforce.csv -- securityfocus.csv -- cve.csv -- -- ********************************************************** local dirs = ntop.getDirs() package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path package.path = dirs.installdir .. "/scripts/lua/pro/modules/?.lua;" .. package.path package.path = dirs.installdir .. "/scripts/lua/modules/vulnerability_scan/?.lua;" .. package.path require "lua_utils" -- used by tprint (debug) local host_to_scan_key = "ntopng.prefs.host_to_scan" local host_scan_queue_key = "ntopng.vs_scan_queue" local json = require("dkjson") local format_utils = require("format_utils") local vs_utils = {} -- ********************************************************** local function get_report_path(scan_type, ip) local base_dir = dirs.workingdir .. "/-1/vulnerability_scan" ntop.mkdir(base_dir) local ret = base_dir .. "/"..ip.."_"..scan_type..".txt" return(ret) end -- ############################################## local function lines(str) local result = {} for line in str:gmatch '[^\n]+' do table.insert(result, line) end return result end -- ############################################## -- remove the first/last few lines that contain nmap information that change at each scan function vs_utils.cleanup_nmap_result(scan_result) scan_result = scan_result:gsub("|", "") scan_result = lines(scan_result) for i=1,4 do table.remove(scan_result, 1) end for i=1,3 do table.remove(scan_result, #scan_result) end scan_result = table.concat(scan_result, "\n") return(scan_result) end -- ********************************************************** -- Function to save host configuration function vs_utils.save_host_to_scan(scan_type, host, scan_result, last_scan_time, last_duration, is_ok_last_scan, ports) local saved_hosts_string = ntop.getCache(host_to_scan_key) local saved_hosts = {} if not isEmptyString(saved_hosts_string) then saved_hosts = json.decode(saved_hosts_string) local index_to_remove = 0 for index,value in ipairs(saved_hosts) do if value.host == host and value.scan_type == scan_type then index_to_remove = index end end if index_to_remove ~= 0 then table.remove(saved_hosts, index_to_remove) end end local new_item = { host=host, scan_type=scan_type, ports=ports } if last_scan_time or last_duration then local time_formatted = format_utils.formatPastEpochShort(last_scan_time) if last_duration <= 0 then last_duration = 1 end last_duration = secondsToTime(last_duration) new_item.last_scan = { epoch = last_scan_time, time = time_formatted, duration = last_duration } if is_ok_last_scan then new_item.is_ok_last_scan = is_ok_last_scan end end if(scan_result ~= nil) then local handle = io.open(get_report_path(scan_type, host), "w") local result = handle:write(scan_result) handle:close() end saved_hosts[#saved_hosts+1] = new_item ntop.setCache(host_to_scan_key, json.encode(saved_hosts)) return 1 end -- ********************************************************** -- Function to retrieve hosts list to scan function vs_utils.retrieve_hosts_to_scan() local res_string = ntop.getCache(host_to_scan_key) if not isEmptyString(res_string) and res_string ~= "[[]]" and res_string ~= "[]" then return json.decode(res_string) else return {} end end -- ********************************************************** -- Function to retrieve last host scan result function vs_utils.retrieve_hosts_scan_result(scan_type, host) local path = get_report_path(scan_type, host) if(ntop.exists(path)) then local handle = io.open(path, "r") local result = handle:read("*a") handle:close() return result else return "" end end -- ********************************************************** -- Function to delete host to scan function vs_utils.delete_host_to_scan(host, scan_type, all) local saved_hosts_string = ntop.getCache(host_to_scan_key) local saved_hosts = {} if all then ntop.delCache(host_to_scan_key) else if not isEmptyString(saved_hosts_string) then saved_hosts = json.decode(saved_hosts_string) local index_to_remove = 0 for index,value in ipairs(saved_hosts) do if value.host == host and value.scan_type == scan_type then index_to_remove = index end end if index_to_remove ~= 0 then table.remove(saved_hosts, index_to_remove) end end ntop.setCache(host_to_scan_key, json.encode(saved_hosts)) end return 1 end -- ********************************************************** -- Function to retrieve scan types list function vs_utils.retrieve_scan_types() local scan_types = vs_utils.list_scan_modules() local ret = {} for _,scan_type in ipairs(scan_types) do table.insert(ret, { id = scan_type, label = i18n("hosts_stats.page_scan_hosts.scan_type_list."..scan_type) }) end return ret end -- ********************************************************** function vs_utils.list_scan_modules() local dirs = ntop.getDirs() local basedir = dirs.scriptdir .. "/lua/modules/vulnerability_scan/modules" local modules = {} for name in pairs(ntop.readdir(basedir)) do if(ends(name, ".lua")) then name = string.sub(name, 1, string.len(name)-4) -- remove .lua trailer local m = vs_utils.load_module(name) if(m:is_enabled()) then table.insert(modules, name) end end end return(modules) end -- ********************************************************** function vs_utils.load_module(name) package.path = dirs.installdir .. "/scripts/lua/modules/vulnerability_scan/modules/?.lua;".. package.path return(require(name):new()) end -- ********************************************************** -- Function to exec single host scan function vs_utils.scan_host(scan_type, host, ports) local scan_module = vs_utils.load_module(scan_type) local result,duration,scan_result = scan_module:scan_host(host, ports) vs_utils.save_host_to_scan(scan_type, host, result, now, duration, scan_result, ports) return true end -- ********************************************************** -- Function to update single host status function vs_utils.set_status_scan(scan_type, host, ports) local saved_hosts_string = ntop.getCache(host_to_scan_key) local saved_hosts = {} if not isEmptyString(saved_hosts_string) then saved_hosts = json.decode(saved_hosts_string) local index_to_update = 0 local value_to_update = {} for index,value in ipairs(saved_hosts) do if value.host == host and value.scan_type == scan_type then index_to_update = index value.is_ok_last_scan = 4 value_to_update = value end end if index_to_remove ~= 0 then table.remove(saved_hosts, index_to_update) table.insert(saved_hosts, index_to_update, value_to_update) end end ntop.setCache(host_to_scan_key, json.encode(saved_hosts)) return true end -- ********************************************************** function vs_utils.schedule_host_scan(scan_type, host, ports) local scan = { scan_type = scan_type, host = host, ports = ports } vs_utils.set_status_scan(scan_type, host, ports) ntop.rpushCache(host_scan_queue_key, json.encode(scan)) return true end -- ********************************************************** function vs_utils.schedule_all_hosts_scan(scan_type, host, ports) local host_to_scan_list = vs_utils.retrieve_hosts_to_scan() if #host_to_scan_list > 0 then for _,scan_info in ipairs(host_to_scan_list) do local scan_type = scan_info.scan_type local host = scan_info.host local scan = { scan_type = scan_type, host = host, ports = ports } ntop.rpushCache(host_scan_queue_key, json.encode(scan)) end end return true end -- ********************************************************** -- Process a single host scan request that has been queued function vs_utils.process_oldest_scheduled_scan() local elem = ntop.lpopCache(host_scan_queue_key) if((elem ~= nil) and (elem ~= "")) then local elem = json.decode(elem) tprint(elem) vs_utils.scan_host(elem.scan_type, elem.host, elem.ports) return true else return false end end -- ********************************************************** -- Process a single host scan request that has been queued function vs_utils.process_all_scheduled_scans(max_num_scans) local num = 0 if(max_num_scans == nil) then max_num_scans = 9999 end while(max_num_scans > 0) do local res = vs_utils.process_oldest_scheduled_scan() if(res == false) then break else max_num_scans = max_num_scans - 1 num = num + 1 end end return num end -- ********************************************************** -- Process to retrieve list of ports using nmap function vs_utils.get_ports(host) -- FIXME -- must returns array of object {key: port_id} local result = {} result[#result+1] = { key = 22 } return result end -- ********************************************************** return vs_utils