diff --git a/CHANGELOG b/CHANGELOG index 518f762b0..e2ecc0fd7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,16 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE][GH#943] Added new SMB2/3 library and scripts: + + smb-protocols discovers if a server supports dialects + NT LM 0.12 (SMBv1), 2.02, 2.10, 3.00, 3.02 and 3.11. + + smb2-time determines the current date and boot date of SMB2 servers. + + smb2-capabilities lists the supported capabilities of SMB2/SMB3 servers. + + smb2-security-mode determines the message signing configuration of + SMB2/SMB3 servers. + + smb2-vuln-uptime attempts to discover missing critical + patches in Microsoft Windows systems based on the SMB2 + server uptime. [Paulino Calderon] + o [NSE][GH#950] Added wildcard detection to dns-brute. Only hostnames that resolve to unique addresses will be listed. [Aaron Heesakkers] diff --git a/nselib/smb.lua b/nselib/smb.lua index a2f3a6d2b..c87154fdd 100644 --- a/nselib/smb.lua +++ b/nselib/smb.lua @@ -136,6 +136,7 @@ local stdnse = require "stdnse" local string = require "string" local table = require "table" local unicode = require "unicode" +local smb2 = require "smb2" _ENV = stdnse.module("smb", stdnse.seeall) -- These arrays are filled in with constants at the bottom of this file @@ -942,69 +943,52 @@ function smb_read(smb, read_data) return true, header, parameters, data end ---- Sends out SMB_COM_NEGOTIATE, which is typically the first SMB packet sent out. --- +--- +-- Negotiates SMBv1 connections +-- -- Sends the following: -- * List of known protocols -- --- Receives: --- * The preferred dialect --- * The security mode --- * Max number of multiplexed connections, virtual circuits, and buffer sizes --- * The server's system time and timezone --- * The "encryption key" (aka, the server challenge) --- * The capabilities --- * The server and domain names +-- This function adds to smb: +-- * 'security_mode' Whether or not to use cleartext passwords, message signatures, etc. +-- * 'max_mpx' Maximum number of multiplexed connections +-- * 'max_vc' Maximum number of virtual circuits +-- * 'max_buffer' Maximum buffer size +-- * 'max_raw_buffer' Maximum buffer size for raw connections (considered obsolete) +-- * 'session_key' A value that's basically just echoed back +-- * 'capabilities' The server's capabilities +-- * 'time' The server's time (in UNIX-style seconds since 1970) +-- * 'date' The server's date in a user-readable format +-- * 'timezone' The server's timezone, in hours from UTC +-- * 'timezone_str' The server's timezone, as a string +-- * 'server_challenge' A random string used for challenge/response +-- * 'domain' The server's primary domain or workgroup +-- * 'server' The server's name -- ---@param smb The SMB object associated with the connection ---@param overrides [optional] Overrides for various fields ---@return (status, result) If status is false, result is an error message. Otherwise, result is --- nil and the following elements are added to smb: --- * 'security_mode' Whether or not to use cleartext passwords, message signatures, etc. --- * 'max_mpx' Maximum number of multiplexed connections --- * 'max_vc' Maximum number of virtual circuits --- * 'max_buffer' Maximum buffer size --- * 'max_raw_buffer' Maximum buffer size for raw connections (considered obsolete) --- * 'session_key' A value that's basically just echoed back --- * 'capabilities' The server's capabilities --- * 'time' The server's time (in UNIX-style seconds since 1970) --- * 'date' The server's date in a user-readable format --- * 'timezone' The server's timezone, in hours from UTC --- * 'timezone_str' The server's timezone, as a string --- * 'server_challenge' A random string used for challenge/response --- * 'domain' The server's primary domain or workgroup --- * 'server' The server's name -function negotiate_protocol(smb, overrides) +-- @param smb The SMB object associated with the connection. +-- @param overrides Overrides table. +-- @return Boolean status +-- @return The negotiated dialect in human readable form or an error message. +--- +function negotiate_v1(smb, overrides) local header, parameters, data - local pos - local header1, header2, header3, header4, command, status, flags, flags2, pid_high, signature, unused, pid, mid - - header = smb_encode_header(smb, command_codes['SMB_COM_NEGOTIATE'], overrides) + local result, err + local pos, header1, header2, header3, header4, command, status, flags, flags2, pid_high, signature, unused, pid, uid, tid, mid + header = smb_encode_header(smb, command_codes['SMB_COM_NEGOTIATE'], overrides) -- Make sure we have overrides overrides = overrides or {} -- Parameters are blank parameters = "" - - -- Data is a list of strings, terminated by a blank one. - if(overrides['dialects'] == nil) then - data = bin.pack(" +-- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html +--- + +local string = require "string" +local stdnse = require "stdnse" +local netbios = require "netbios" +local nmap = require "nmap" +local table = require "table" +local match = require "match" +local math = require "math" +local os = require "os" + +_ENV = stdnse.module("smb2", stdnse.seeall) + +local TIMEOUT = 10000 +local command_names = {} +local command_codes = +{ + SMB2_COM_NEGOTIATE = 0x0000, + SMB2_COM_SESSION_SETUP = 0x0001, + SMB2_COM_LOGOFF = 0x0002, + SMB2_COM_TREE_CONNECT = 0x0003, + SMB2_COM_TREE_DISCONNECT = 0x0004, + SMB2_COM_CREATE = 0x0005, + SMB2_COM_CLOSE = 0x0006, + SMB2_COM_FLUSH = 0x0007, + SMB2_COM_READ = 0x0008, + SMB2_COM_WRITE = 0x0009, + SMB2_COM_LOCK = 0x000A, + SMB2_COM_IOCTL = 0x000B, + SMB2_COM_CANCEL = 0x000C, + SMB2_COM_ECHO = 0x000D, + SMB2_COM_QUERY_DIRECTORY = 0x000E, + SMB2_COM_CHANGE_NOTIFY = 0x000F, + SMB2_COM_QUERY_INFO = 0x0010, + SMB2_COM_SET_INFO = 0x0011, + SMB2_COM_OPLOCK_BREAK = 0x0012 +} +local smb2_values_codes = {} +local smb2_values = { + -- Security Mode + SMB2_NEGOTIATE_SIGNING_ENABLED = 0x0001, + SMB2_NEGOTIATE_SIGNING_REQUIRED = 0x0002, + -- Capabilities + SMB2_GLOBAL_CAP_DFS = 0x00000001, + SMB2_GLOBAL_CAP_LEASING = 0x00000002, + SMB2_GLOBAL_CAP_LARGE_MTU = 0x00000004, + SMB2_GLOBAL_CAP_MULTI_CHANNEL = 0x00000008, + SMB2_GLOBAL_CAP_PERSISTENT_HANDLES = 0x00000010, + SMB2_GLOBAL_CAP_DIRECTORY_LEASING = 0x00000020, + SMB2_GLOBAL_CAP_ENCRYPTION = 0x00000040, + -- Context Types + SMB2_ENCRYPTION_CAPABILITIES = 0x0002, + SMB2_PREAUTH_INTEGRITY_CAPABILITIES = 0x0001 +} + +for i, v in pairs(command_codes) do + command_names[v] = i +end +for i, v in pairs(smb2_values) do + smb2_values_codes[v] = i +end + +--- +-- Creates a SMB2 SYNC header packet. +-- +-- SMB2 Packet Header - SYNC: +-- * https://msdn.microsoft.com/en-us/library/cc246529.aspx +-- +-- @param smb The SMB object associated with the connection. +-- @param command The SMB2 command to execute. +-- @param overrides Overrides table. +-- @return header The encoded SMB2 SYNC header. +--- +function smb2_encode_header_sync(smb, command, overrides) + overrides = overrides or {} + + local sig = "\xFESMB" -- SMB2 packet + local structureSize = 64 -- SYNC header structure size + local flags = 0 -- TODO: Set flags that will work for all dialects + + -- Increase the message id + if smb['MessageId'] then + smb['MessageId'] = smb['MessageId'] + 1 + end + + -- Header structure + local header = string.pack("smb_encode_sync_header. +-- @param data The data. +-- @param overrides Overrides table. +-- @return Boolean Status. +-- @return An error message if status is false. +--- +function smb2_send(smb, header, data, overrides) + overrides = overrides or {} + local body = header .. data + local attempts = 5 + local status, err + + local out = string.pack(">II", netbios_data) + if(netbios_length == nil) then + return false, "SMB2: ERROR:Server returned less data than it was supposed to" + end + -- Make the length 24 bits + netbios_length = netbios_length & 0x00FFFFFF + -- The total length is the netbios_length, plus 4 (for the length itself) + length = netbios_length + 4 + + local attempts = 5 + local smb_data + repeat + attempts = attempts - 1 + status, smb_data = smb['socket']:receive_buf(match.numbytes(netbios_length), true) + until(status or (attempts == 0)) + + -- Make sure the connection is still alive + if(status ~= true) then + return false, "SMB2: Failed to receive bytes after 5 attempts: " .. smb_data + end + + local result = netbios_data .. smb_data + if(#result ~= length) then + stdnse.debug1("SMB2: ERROR: Received wrong number of bytes, there will likely be issues (received %d, expected %d)", #result, length) + return false, string.format("SMB2: ERROR: Didn't receive the expected number of bytes; received %d, expected %d. This will almost certainly cause some errors.", #result, length) + end + + -- The header is 64 bytes. + if (pos + 64 > #result) then + stdnse.debug2("SMB2: SMB2 packet too small. Size needed to be at least '%d' but we got '%d' bytes", pos+64, #result) + return false, "SMB2: ERROR: Header packet too small." + end + header, pos = string.unpack(" 3.11 + local total_data = 0 -- Data counter + local padding_data = "" -- Padding string to align contexts + local context_data -- Holds Context data + local is_0311 = false -- Flag for SMB 3.11 + local status, err + + if not( overrides['Dialects'] ) then -- Set 2.02 as default dialect if user didn't select one + overrides['Dialects'] = {0x0202} + end + + header = smb2_encode_header_sync(smb, command_codes['SMB2_COM_NEGOTIATE'], overrides) + + -- We construct the first block that works for dialects 2.02 up to 3.11. + data = string.pack(" 3.x + GUID -- 16 bytes: ClientGuid + ) + + -- The next block gets interpreted in different ways depending on the dialect + if stdnse.contains(overrides['Dialects'], 0x0311) then + is_0311 = true + end + + -- If we are dealing with 3.11 we need to set the following fields: + -- NegotiateContextOffset, NegotiateContextCount, and Reserved2 + if is_0311 then + total_data = #header + #data + (DialectCount*2) + padding_data = string.rep("\0", (8 - total_data % 8) % 8) + total_data = total_data + #padding_data + data = data .. string.pack(" +-- @usage nmap -p139 --script smb-protocols +-- +-- @output +-- | smb-protocols: +-- | dialects: +-- | NT LM 0.12 (SMBv1) [dangerous, but default] +-- | 2.02 +-- | 2.10 +-- | 3.00 +-- | 3.02 +-- |_ 3.11 +-- +-- @xmloutput +-- +-- NT LM 0.12 (SMBv1) [dangerous, but default] +-- 2.02 +-- 2.10 +-- 3.00 +-- 3.02 +-- 3.11 +--
+--- + +author = "Paulino Calderon" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"safe", "discovery"} + +hostrule = function(host) + return smb.get_port(host) ~= nil +end + +action = function(host,port) + local status, supported_dialects, overrides + local output = stdnse.output_table() + overrides = {} + status, supported_dialects = smb.list_dialects(host, overrides) + if status then + for i, v in pairs(supported_dialects) do -- Mark SMBv1 as insecure + if v == "NT LM 0.12" then + supported_dialects[i] = v .. " (SMBv1) [dangerous, but default]" + end + end + output.dialects = supported_dialects + end + + if #output.dialects>0 then + return output + else + stdnse.debug1("No dialects were accepted") + if nmap.verbosity()>1 then + return "No dialects accepted. Something may be blocking the responses" + end + end +end diff --git a/scripts/smb2-capabilities.nse b/scripts/smb2-capabilities.nse new file mode 100644 index 000000000..d5dfe476b --- /dev/null +++ b/scripts/smb2-capabilities.nse @@ -0,0 +1,117 @@ +local smb = require "smb" +local smb2 = require "smb2" +local stdnse = require "stdnse" +local string = require "string" +local table = require "table" +local nmap = require "nmap" + +description = [[ +Attempts to list the supported capabilities in a SMBv2 server for each + enabled dialect. + +The script sends a SMB2_COM_NEGOTIATE command and parses the response + using the SMB dialects: +* 2.02 +* 2.10 +* 3.00 +* 3.02 +* 3.11 + +References: +* https://msdn.microsoft.com/en-us/library/cc246561.aspx +]] + +--- +-- @usage nmap -p 445 --script smb2-capabilities +-- @usage nmap -p 139 --script smb2-capabilities +-- +-- @output +-- | smb2-capabilities: +-- | 2.02: +-- | Distributed File System +-- | 2.10: +-- | Distributed File System +-- | Leasing +-- | Multi-credit operations +-- +-- @xmloutput +-- +-- Distributed File System +--
+-- +-- Distributed File System +-- Leasing +-- Multi-credit operations +--
+--- + +author = "Paulino Calderon" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"safe", "discovery"} + +hostrule = function(host) + return smb.get_port(host) ~= nil +end + +action = function(host,port) + local status, smbstate, overrides + local output = stdnse.output_table() + overrides = {} + + local smb2_dialects = {0x0202, 0x0210, 0x0300, 0x0302, 0x0311} + + for i, dialect in pairs(smb2_dialects) do + -- we need a clean connection for each negotiate request + status, smbstate = smb.start(host) + if(status == false) then + stdnse.debug1("Could not establish a connection.") + return nil + end + -- We set our overrides Dialects table with the dialect we are testing + overrides['Dialects'] = {dialect} + status = smb2.negotiate_v2(smbstate, overrides) + if status then + local capabilities = {} + stdnse.debug2("SMB2: Server capabilities: '%s'", smbstate['capabilities']) + + -- We check the capabilities flags. Not all of them are supported by + -- every dialect but we dumb check anyway. + if smbstate['capabilities'] & 0x01 == 0x01 then + table.insert(capabilities, "Distributed File System") + end + if smbstate['capabilities'] & 0x02 == 0x02 then + table.insert(capabilities, "Leasing") + end + if smbstate['capabilities'] & 0x04 == 0x04 then + table.insert(capabilities, "Multi-credit operations") + end + if smbstate['capabilities'] & 0x08 == 0x08 then + table.insert(capabilities, "Multiple Channel support") + end + if smbstate['capabilities'] & 0x10 == 0x10 then + table.insert(capabilities, "Persistent handles") + end + if smbstate['capabilities'] & 0x20 == 0x20 then + table.insert(capabilities, "Directory Leasing") + end + if smbstate['capabilities'] & 0x40 == 0x40 then + table.insert(capabilities, "Encryption") + end + if #capabilities<1 then + table.insert(capabilities, "All capabilities are disabled") + end + output[stdnse.tohex(dialect, {separator = ".", group = 2})] = capabilities + end + smb.stop(smbstate) + status = false + end + + if #output>0 then + return output + else + stdnse.debug1("No dialects were accepted.") + if nmap.verbosity()>1 then + return "Couldn't establish a SMBv2 connection." + end + end +end diff --git a/scripts/smb2-security-mode.nse b/scripts/smb2-security-mode.nse new file mode 100644 index 000000000..2bff35ea8 --- /dev/null +++ b/scripts/smb2-security-mode.nse @@ -0,0 +1,100 @@ +local smb = require "smb" +local smb2 = require "smb2" +local stdnse = require "stdnse" +local string = require "string" +local table = require "table" +local nmap = require "nmap" + +description = [[ +Determines the message signing configuration in SMBv2 servers + for all supported dialects. + +The script sends a SMB2_COM_NEGOTIATE request for each SMB2/SMB3 dialect + and parses the security mode field to determine the message signing + configuration of the SMB server. + +References: +* https://msdn.microsoft.com/en-us/library/cc246561.aspx +]] + +--- +-- @usage nmap -p 445 --script smb2-security-mode +-- @usage nmap -p 139 --script smb2-security-mode +-- +-- @output +-- | smb2-security-mode: +-- | 3.11: +-- |_ Message signing enabled but not required +-- +-- @xmloutput +-- +-- Message signing enabled but not required +--
+--- + +author = "Paulino Calderon" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"safe", "discovery", "default"} + +hostrule = function(host) + return smb.get_port(host) ~= nil +end + +action = function(host,port) + local status, smbstate, overrides + local output = stdnse.output_table() + overrides = overrides or {} + + local smb2_dialects = {0x0202, 0x0210, 0x0300, 0x0302, 0x0311} + + for i, dialect in pairs(smb2_dialects) do + -- we need a clean connection for each negotiate request + status, smbstate = smb.start(host) + if(status == false) then + return false, smbstate + end + overrides['Dialects'] = {dialect} + status, dialect = smb2.negotiate_v2(smbstate, overrides) + if status then + local message_signing = {} + + -- Signing configuration. SMBv2 servers support two flags: + -- * Message signing enabled + -- * Message signing required + local signing_enabled, signing_required + if smbstate['security_mode'] & 0x01 == 0x01 then + signing_enabled = true + end + if smbstate['security_mode'] & 0x02 == 0x02 then + signing_required = true + end + + if signing_enabled and signing_required then + table.insert(message_signing, "Message signing enabled and required") + elseif signing_enabled and not(signing_required) then + table.insert(message_signing, "Message signing enabled but not required") + elseif not(signing_enabled) and not(signing_required) then + table.insert(message_signing, "Message signing is disabled and not required!") + elseif not(signing_enabled) and signing_required then + table.insert(message_signing, "Message signing is disabled!") + end + output[stdnse.tohex(dialect[1], {separator = ".", group = 2})] = message_signing + -- We exit after first accepted dialect, + -- SMB signing configuration appears to be global so + -- there is no point of trying other dialects. + break + end + + smb.stop(smbstate) + status = false + end + + if #output>0 then + return output + else + stdnse.debug1("No SMB2/SMB3 dialects were accepted.") + if nmap.verbosity()>1 then + return "Couldn't establish a SMBv2 connection." + end + end +end diff --git a/scripts/smb2-time.nse b/scripts/smb2-time.nse new file mode 100644 index 000000000..274f1cdf2 --- /dev/null +++ b/scripts/smb2-time.nse @@ -0,0 +1,49 @@ +local smb = require "smb" +local stdnse = require "stdnse" +local smb2 = require "smb2" + +description = [[ +Attempts to obtain the current system date and the start date of a SMB2 server. +]] + +--- +-- @usage nmap -p445 --script smb2-time +-- +-- @output +-- Host script results: +-- | smb2-time: +-- | date: 2017-07-28 03:06:34 +-- |_ start_date: 2017-07-20 09:29:49 +-- +-- @xmloutput +-- 2017-07-28 03:07:57 +-- 2017-07-20 09:29:49 +--- + +author = "Paulino Calderon " +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"discovery", "safe", "default"} + +hostrule = function(host) + return smb.get_port(host) ~= nil +end + +action = function(host,port) + local smbstate, status, overrides + local output = stdnse.output_table() + overrides = {} + status, smbstate = smb.start(host) + status = smb2.negotiate_v2(smbstate, overrides) + + if status then + stdnse.debug2("SMB2: Date: %s (%s) Start date:%s (%s)", + smbstate['date'], smbstate['time'], + smbstate['start_date'], smbstate['start_time']) + output.date = smbstate['date'] + output.start_date = smbstate['start_date'] + return output + else + stdnse.debug2("Negotiation failed") + return "Protocol negotiation failed (SMB2)" + end +end diff --git a/scripts/smb2-vuln-uptime.nse b/scripts/smb2-vuln-uptime.nse new file mode 100644 index 000000000..2a3504458 --- /dev/null +++ b/scripts/smb2-vuln-uptime.nse @@ -0,0 +1,152 @@ +local smb = require "smb" +local vulns = require "vulns" +local stdnse = require "stdnse" +local string = require "string" +local smb2 = require "smb2" +local table = require "table" + +description = [[ +Attempts to detect missing patches in Windows systems by checking the +uptime returned during the SMB2 protocol negotiation. + +SMB2 protocol negotiation response returns the system boot time + pre-authentication. This information can be used to determine + if a system is missing critical patches without triggering IDS/IPS/AVs. + +Remember that a rebooted system may still be vulnerable. This check +only reveals unpatched systems based on the uptime, no additional probes are sent. + +References: +* https://twitter.com/breakersall/status/880496571581857793 +]] + +--- +-- @usage nmap -O --script smb2-vuln-uptime +-- @usage nmap -p445 --script smb2-vuln-uptime --script-args smb2-vuln-uptime.skip-os=true +-- +-- @output +-- | smb2-vuln-uptime: +-- | VULNERABLE: +-- | MS17-010: Security update for Windows SMB Server +-- | State: LIKELY VULNERABLE +-- | IDs: ms:ms17-010 CVE:2017-0147 +-- | This system is missing a security update that resolves vulnerabilities in +-- | Microsoft Windows SMB Server. +-- | +-- | References: +-- | https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-0147 +-- |_ https://technet.microsoft.com/en-us/library/security/ms17-010.aspx +-- +-- @xmloutput +-- +-- MS17-010: Security update for Windows SMB Server +-- LIKELY VULNERABLE +--
+-- CVE:2017-0147 +-- ms:ms17-010 +--
+-- +-- This system is missing a security update that resolves vulnerabilities in Microsoft Windows SMB Server. +--
+-- +-- https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-0147 +-- https://technet.microsoft.com/en-us/library/security/ms17-010.aspx +--
+-- +-- +-- @args smb2-vuln-uptime.skip-os Ignore OS detection results and show results +--- + +author = "Paulino Calderon " +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"vuln", "safe"} + +hostrule = function(host) + local ms = false + local os_detection = stdnse.get_script_args(SCRIPT_NAME .. ".skip-os") or false + if host.os then + for k, v in pairs(host.os) do -- Loop through OS matches + if string.match(v['name'], "Microsoft") then + ms = true + end + end + end + return (smb.get_port(host) ~= nil and ms) or (os_detection) +end + +local ms_vulns = { + { + title = 'MS17-010: Security update for Windows SMB Server', + ids = {ms = "ms17-010", CVE = "2017-0147"}, + desc = [[ +This system is missing a security update that resolves vulnerabilities in + Microsoft Windows SMB Server. +]], + disclosure_time = 1489471200, + disclosure_date = {year=2017, month=3, day=14}, + references = { + 'https://technet.microsoft.com/en-us/library/security/ms17-010.aspx', + }, + }, + { + title = 'Microsoft Kerberos Checksum Vulnerability', + ids = {ms = "ms14-068", CVE = "2014-6324"}, + desc = [[ +This security update resolves a privately reported vulnerability in Microsoft + Windows Kerberos KDC that could allow an attacker to elevate unprivileged + domain user account privileges to those of the domain administrator account. +]], + disclosure_time = 1416290400, + disclosure_date = {year=2014, month=11, day=18}, + references = { + 'https://technet.microsoft.com/en-us/library/security/ms14-068.aspx' + }, + }, +} + +local function check_vulns(host, port) + local smbstate, status, overrides + local vulns_detected = {} + + overrides = {} + overrides['Dialects'] = {0x0202} + status, smbstate = smb.start(host) + status, _ = smb2.negotiate_v2(smbstate, overrides) + + if status then + stdnse.debug2("SMB2: Date: %s (%s) Start date:%s (%s)", + smbstate['date'], smbstate['time'], + smbstate['start_date'], smbstate['start_time']) + + for _, vuln in pairs(ms_vulns) do + if smbstate['start_time'] < vuln['disclosure_time'] then + stdnse.debug2("Vulnerability detected") + vuln.extra_info = string.format("The system hasn't been rebooted since %s", smbstate['start_date']) + table.insert(vulns_detected, vuln) + end + end + + else + stdnse.debug2("Negotiation failed") + return nil, "Protocol negotiation failed (SMB2)" + end + return true, vulns_detected +end + +action = function(host,port) + local status, vulnerabilities + local report = vulns.Report:new(SCRIPT_NAME, host, port) + + status, vulnerabilities = check_vulns(host, port) + if status then + for i, v in pairs(vulnerabilities) do + local vuln = { title = v['title'], description = v['desc'], + references = v['references'], disclosure_date = v['disclosure_date'], + IDS = v['ids']} + vuln.state = vulns.STATE.LIKELY_VULN + vuln.extra_info = v['extra_info'] + report:add_vulns(SCRIPT_NAME, vuln) + end + end + return report:make_output() +end