diff --git a/nse_libssh2.h b/nse_libssh2.h index a749fa5e0..1a284f3ea 100644 --- a/nse_libssh2.h +++ b/nse_libssh2.h @@ -1,8 +1,8 @@ -#ifndef LIBSSH2 - -#define LIBSSH2 -#define LIBSSH2LIBNAME "libssh2" - -int luaopen_libssh2 (lua_State *L); - -#endif +#ifndef LIBSSH2 + +#define LIBSSH2 +#define LIBSSH2LIBNAME "libssh2" + +int luaopen_libssh2 (lua_State *L); + +#endif diff --git a/scripts/openwebnet-discovery.nse b/scripts/openwebnet-discovery.nse index e57866b01..477b924e1 100755 --- a/scripts/openwebnet-discovery.nse +++ b/scripts/openwebnet-discovery.nse @@ -1,289 +1,289 @@ -local stdnse = require "stdnse" -local shortport = require "shortport" -local comm = require "comm" -local string = require "string" -local table = require "table" - -description = [[ -OpenWebNet is a communications protocol developed by Bticino since 2000. -Retrieves device identifying information and number of connected devices. - -References: -* https://www.myopen-legrandgroup.com/solution-gallery/openwebnet/ -* http://www.pimyhome.org/wiki/index.php/OWN_OpenWebNet_Language_Reference -]] - ---- --- @usage --- nmap --script openwebnet-discovery --- --- @output --- | openwebnet-discover: --- | IP Address: 192.168.200.35 --- | Net Mask: 255.255.255.0 --- | MAC Address: 00:03:50:01:d3:11 --- | Device Type: F453AV --- | Firmware Version: 3.0.14 --- | Uptime: 12d9h42m1s --- | Date and Time: 4-07-2017T19:17:27 --- | Kernel Version: 2.3.8 --- | Distribution Version: 3.0.1 --- | Lighting: 115 --- | Automation: 15 --- |_ Burglar Alarm: 12 --- --- @xmloutput --- 192.168.200.35 --- 255.255.255.0 --- 00:03:50:01:d3:11 --- F453AV --- 3.0.14 --- 12d9h42m1s --- 4-07-2017T19:17:27 --- 2.3.8 --- 3.0.1 --- 115 --- 15 --- 12 - -author = "Rewanth Cool" -license = "Same as Nmap--See https://nmap.org/book/man-legal.html" -categories = {"discovery", "safe"} - -portrule = shortport.port_or_service(20000, "openwebnet") - -local device = { - [2] = "MHServer", - [4] = "MH200", - [6] = "F452", - [7] = "F452V", - [11] = "MHServer2", - [12] = "F453AV", - [13] = "H4684", - [15] = "F427 (Gateway Open-KNX)", - [16] = "F453", - [23] = "H4684", - [27] = "L4686SDK", - [44] = "MH200N", - [51] = "F454", - [200] = "F454 (new?)" -} - -local who = { - [0] = "Scenarios", - [1] = "Lighting", - [2] = "Automation", - [3] = "Power Management", - [4] = "Heating", - [5] = "Burglar Alarm", - [6] = "Door Entry System", - [7] = "Multimedia", - [9] = "Auxiliary", - [13] = "Device Communication", - [14] = "Light+shutters actuators lock", - [15] = "CEN", - [16] = "Sound System", - [17] = "Scenario Programming", - [18] = "Energy Management", - [24] = "Lighting Management", - [25] = "CEN plus", - [1000] = "Diagnostic", - [1001] = "Automation Diagnostic", - [1004] = "Heating Diagnostic", - [1008] = "Door Entry System Diagnostic", - [1013] = "Device Diagnostic" -} - -local device_dimension = { - ["Time"] = "0", - ["Date"] = "1", - ["IP Address"] = "10", - ["Net Mask"] = "11", - ["MAC Address"] = "12", - ["Device Type"] = "15", - ["Firmware Version"] = "16", - ["Hardware Version"] = "17", - ["Uptime"] = "19", - ["Micro Version"] = "20", - ["Date and Time"] = "22", - ["Kernel Version"] = "23", - ["Distribution Version"] = "24", - ["Gateway IP address"] = "50", - ["DNS IP address 1"] = "51", - ["DNS IP address 2"] = "52" -} - -local ACK = "*#*1##" -local NACK = "*#*0##" - --- Initiates a socket connection --- Returns the socket and error message -local function get_socket(host, port, request) - - local sd, response, early_resp = comm.opencon(host, port, request, {recv_before=true, request_timeout=10000}) - - if sd == nil then - stdnse.debug("Socket connection error.") - return nil, response - end - - if not response then - stdnse.debug("Poor internet connection or no response.") - return nil, response - end - - if response == NACK then - stdnse.debug("Received a negative ACK as response.") - return nil, response - end - - return sd, nil -end - -local function get_response(sd, request) - - local res = {} - local status, data - - sd:send(request) - - repeat - status, data = sd:receive_buf("##", true) - - if status == nil then - stdnse.debug("Error: " .. data) - if data == "TIMEOUT" then - -- Avoids false results by capturing NACK after TIMEOUT occured. - status, data = sd:receive_buf("##", true) - break - else - -- Captures other kind of errors like EOF - sd:close() - return res - end - end - - if status and data ~= ACK then - table.insert(res, data) - end - if data == ACK then - break - end - - -- If response is NACK, it means the request method is not supported - if data == NACK then - res = nil - break - end - until not status - - return res -end - -local function format_dimensions(res) - - if res["Date and Time"] then - local params = { - "hour", "min", "sec", "msec", "dayOfWeek", "year", "month", "day" - } - - local values = {} - for counter, val in ipairs(stdnse.strsplit("%.%s*", res["Date and Time"])) do - values[ params[counter] ] = val - end - - res["Date and Time"] = stdnse.format_timestamp(values) - end - - if res["Device Type"] then - res["Device Type"] = device[ tonumber( res["Device Type"] ) ] - end - - if res["MAC Address"] then - res["MAC Address"] = string.gsub(res["MAC Address"], "(%d+)(%.?)", function(num, separator) - if separator == "." then - return string.format("%02x:", num) - else - return string.format("%02x", num) - end - end - ) - end - - if res["Uptime"] then - local t = {} - local units = { - "d", "h", "m", "s" - } - - for counter, v in ipairs(stdnse.strsplit("%.%s*", res["Uptime"])) do - table.insert(t, v .. units[counter]) - end - - res["Uptime"] = table.concat(t, "") - end - - return res - -end - -action = function(host, port) - - local output = stdnse.output_table() - - local sd, err = get_socket(host, port, nil) - - -- Socket connection creation failed - if sd == nil then - return err - end - - -- Fetching list of dimensions of a device - for _, device in ipairs({"IP Address", "Net Mask", "MAC Address", "Device Type", "Firmware Version", "Uptime", "Date and Time", "Kernel Version", "Distribution Version"}) do - - local head = "*#13**" - local tail = "##" - - stdnse.debug("Fetching " .. device) - - local res = get_response(sd, head .. device_dimension[device] .. tail) - - -- Extracts substring from the result - -- Ex: - -- Request - *#13**16## - -- Response - *#13**16*3*0*14## - -- Trimmed Output - 3*0*14 - - if res and next(res) then - local regex = string.gsub(head, "*", "%%*") .. device_dimension[device] .. "%*" .."(.+)" .. tail - local tempRes = string.match(res[1], regex) - - if tempRes then - output[device] = string.gsub(tempRes, "*", ".") - end - end - - end - - -- Format the output based on dimension - output = format_dimensions(output) - - -- Fetching list of each device - for i = 1, 6 do - - stdnse.debug("Fetching the list of " .. who[i] .. " devices.") - - local res = get_response(sd, "*#" .. i .. "*0##") - if res and #res > 0 then - output[who[i]] = #res - end - - end - - if #output > 0 then - return output - else - return nil - end -end - +local stdnse = require "stdnse" +local shortport = require "shortport" +local comm = require "comm" +local string = require "string" +local table = require "table" + +description = [[ +OpenWebNet is a communications protocol developed by Bticino since 2000. +Retrieves device identifying information and number of connected devices. + +References: +* https://www.myopen-legrandgroup.com/solution-gallery/openwebnet/ +* http://www.pimyhome.org/wiki/index.php/OWN_OpenWebNet_Language_Reference +]] + +--- +-- @usage +-- nmap --script openwebnet-discovery +-- +-- @output +-- | openwebnet-discover: +-- | IP Address: 192.168.200.35 +-- | Net Mask: 255.255.255.0 +-- | MAC Address: 00:03:50:01:d3:11 +-- | Device Type: F453AV +-- | Firmware Version: 3.0.14 +-- | Uptime: 12d9h42m1s +-- | Date and Time: 4-07-2017T19:17:27 +-- | Kernel Version: 2.3.8 +-- | Distribution Version: 3.0.1 +-- | Lighting: 115 +-- | Automation: 15 +-- |_ Burglar Alarm: 12 +-- +-- @xmloutput +-- 192.168.200.35 +-- 255.255.255.0 +-- 00:03:50:01:d3:11 +-- F453AV +-- 3.0.14 +-- 12d9h42m1s +-- 4-07-2017T19:17:27 +-- 2.3.8 +-- 3.0.1 +-- 115 +-- 15 +-- 12 + +author = "Rewanth Cool" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"discovery", "safe"} + +portrule = shortport.port_or_service(20000, "openwebnet") + +local device = { + [2] = "MHServer", + [4] = "MH200", + [6] = "F452", + [7] = "F452V", + [11] = "MHServer2", + [12] = "F453AV", + [13] = "H4684", + [15] = "F427 (Gateway Open-KNX)", + [16] = "F453", + [23] = "H4684", + [27] = "L4686SDK", + [44] = "MH200N", + [51] = "F454", + [200] = "F454 (new?)" +} + +local who = { + [0] = "Scenarios", + [1] = "Lighting", + [2] = "Automation", + [3] = "Power Management", + [4] = "Heating", + [5] = "Burglar Alarm", + [6] = "Door Entry System", + [7] = "Multimedia", + [9] = "Auxiliary", + [13] = "Device Communication", + [14] = "Light+shutters actuators lock", + [15] = "CEN", + [16] = "Sound System", + [17] = "Scenario Programming", + [18] = "Energy Management", + [24] = "Lighting Management", + [25] = "CEN plus", + [1000] = "Diagnostic", + [1001] = "Automation Diagnostic", + [1004] = "Heating Diagnostic", + [1008] = "Door Entry System Diagnostic", + [1013] = "Device Diagnostic" +} + +local device_dimension = { + ["Time"] = "0", + ["Date"] = "1", + ["IP Address"] = "10", + ["Net Mask"] = "11", + ["MAC Address"] = "12", + ["Device Type"] = "15", + ["Firmware Version"] = "16", + ["Hardware Version"] = "17", + ["Uptime"] = "19", + ["Micro Version"] = "20", + ["Date and Time"] = "22", + ["Kernel Version"] = "23", + ["Distribution Version"] = "24", + ["Gateway IP address"] = "50", + ["DNS IP address 1"] = "51", + ["DNS IP address 2"] = "52" +} + +local ACK = "*#*1##" +local NACK = "*#*0##" + +-- Initiates a socket connection +-- Returns the socket and error message +local function get_socket(host, port, request) + + local sd, response, early_resp = comm.opencon(host, port, request, {recv_before=true, request_timeout=10000}) + + if sd == nil then + stdnse.debug("Socket connection error.") + return nil, response + end + + if not response then + stdnse.debug("Poor internet connection or no response.") + return nil, response + end + + if response == NACK then + stdnse.debug("Received a negative ACK as response.") + return nil, response + end + + return sd, nil +end + +local function get_response(sd, request) + + local res = {} + local status, data + + sd:send(request) + + repeat + status, data = sd:receive_buf("##", true) + + if status == nil then + stdnse.debug("Error: " .. data) + if data == "TIMEOUT" then + -- Avoids false results by capturing NACK after TIMEOUT occured. + status, data = sd:receive_buf("##", true) + break + else + -- Captures other kind of errors like EOF + sd:close() + return res + end + end + + if status and data ~= ACK then + table.insert(res, data) + end + if data == ACK then + break + end + + -- If response is NACK, it means the request method is not supported + if data == NACK then + res = nil + break + end + until not status + + return res +end + +local function format_dimensions(res) + + if res["Date and Time"] then + local params = { + "hour", "min", "sec", "msec", "dayOfWeek", "year", "month", "day" + } + + local values = {} + for counter, val in ipairs(stdnse.strsplit("%.%s*", res["Date and Time"])) do + values[ params[counter] ] = val + end + + res["Date and Time"] = stdnse.format_timestamp(values) + end + + if res["Device Type"] then + res["Device Type"] = device[ tonumber( res["Device Type"] ) ] + end + + if res["MAC Address"] then + res["MAC Address"] = string.gsub(res["MAC Address"], "(%d+)(%.?)", function(num, separator) + if separator == "." then + return string.format("%02x:", num) + else + return string.format("%02x", num) + end + end + ) + end + + if res["Uptime"] then + local t = {} + local units = { + "d", "h", "m", "s" + } + + for counter, v in ipairs(stdnse.strsplit("%.%s*", res["Uptime"])) do + table.insert(t, v .. units[counter]) + end + + res["Uptime"] = table.concat(t, "") + end + + return res + +end + +action = function(host, port) + + local output = stdnse.output_table() + + local sd, err = get_socket(host, port, nil) + + -- Socket connection creation failed + if sd == nil then + return err + end + + -- Fetching list of dimensions of a device + for _, device in ipairs({"IP Address", "Net Mask", "MAC Address", "Device Type", "Firmware Version", "Uptime", "Date and Time", "Kernel Version", "Distribution Version"}) do + + local head = "*#13**" + local tail = "##" + + stdnse.debug("Fetching " .. device) + + local res = get_response(sd, head .. device_dimension[device] .. tail) + + -- Extracts substring from the result + -- Ex: + -- Request - *#13**16## + -- Response - *#13**16*3*0*14## + -- Trimmed Output - 3*0*14 + + if res and next(res) then + local regex = string.gsub(head, "*", "%%*") .. device_dimension[device] .. "%*" .."(.+)" .. tail + local tempRes = string.match(res[1], regex) + + if tempRes then + output[device] = string.gsub(tempRes, "*", ".") + end + end + + end + + -- Format the output based on dimension + output = format_dimensions(output) + + -- Fetching list of each device + for i = 1, 6 do + + stdnse.debug("Fetching the list of " .. who[i] .. " devices.") + + local res = get_response(sd, "*#" .. i .. "*0##") + if res and #res > 0 then + output[who[i]] = #res + end + + end + + if #output > 0 then + return output + else + return nil + end +end +