diff --git a/scripts/modbus-discover.nse b/scripts/modbus-discover.nse index d6b8ccb53..50cda07a8 100644 --- a/scripts/modbus-discover.nse +++ b/scripts/modbus-discover.nse @@ -30,10 +30,20 @@ Information about MODBUS protocol and security issues: -- PORT STATE SERVICE -- 502/tcp open modbus -- | modbus-discover: --- | Positive response for sid = 0x64 --- | SLAVE ID DATA: \xFA\xFFPM710PowerMeter --- | DEVICE IDENTIFICATION: Schneider Electric PM710 v03.110 --- |_ Positive error response for sid = 0x96 (GATEWAY TARGET DEVICE FAILED TO RESPONSE) +-- | sid 0x64: +-- | Slave ID data: \xFA\xFFPM710PowerMeter +-- | Device identification: Schneider Electric PM710 v03.110 +-- | sid 0x96: +-- |_ error: GATEWAY TARGET DEVICE FAILED TO RESPONSE +-- +-- @xmloutput +-- +-- \xFA\xFFPM710PowerMeter +-- Schneider Electric PM710 v03.110 +--
+-- +-- GATEWAY TARGET DEVICE FAILED TO RESPONSE +--
-- Version 0.2 - /12.12.10/ - script cleanup -- Version 0.3 - /13.12.10/ - several bugfixes @@ -43,18 +53,18 @@ license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"discovery", "intrusive"} -portrule = shortport.portnumber(502, "tcp") +portrule = shortport.port_or_service(502, "modbus") local form_rsid = function(sid, functionId, data) local payload_len = 2 if ( #data > 0 ) then payload_len = payload_len + #data end - return bin.pack('CCCCC', 0x00, 0x00, 0x00, 0x00, 0x00) .. bin.pack('C', payload_len) .. bin.pack('C', sid) .. bin.pack('C', functionId) .. data + return "\0\0\0\0\0" .. bin.pack('CCC', payload_len, sid, functionId) .. data end discover_device_id_recursive = function(host, port, sid, start_id) - local rsid = form_rsid(sid, 0x2B, bin.pack('H', "0E 01")..bin.pack('C', start_id)) + local rsid = form_rsid(sid, 0x2B, "\x0E\x01" .. bin.pack('C', start_id)) local status, result = comm.exchange(host, port, rsid) local objects_table = {} if ( status and (#result >= 8)) then @@ -91,17 +101,6 @@ local discover_device_id = function(host, port, sid) return discover_device_id_recursive(host, port, sid, 0x0) end -local form_device_id_string = function(device_table) - local ret_string = "DEVICE IDENTIFICATION: " - for i = 1, #device_table do - if ( device_table[i] ~= nil ) then - ret_string = ret_string..device_table[i] - if ( i < #device_table ) then ret_string = ret_string.." " end - end - end - return ret_string -end - local extract_slave_id = function(response) local byte_count = string.byte(response, 9) if ( byte_count == nil or byte_count == 0) then return nil end @@ -125,8 +124,8 @@ action = function(host, port) -- If false, stop after first sid. local aggressive = stdnse.get_script_args('modbus-discover.aggressive') - local opts = {timeout=2000} - local results = {} + local opts = {request_timeout=2000} + local results = stdnse.output_table() for sid = 1, 246 do stdnse.debug3("Sending command with sid = %d", sid) @@ -136,24 +135,25 @@ action = function(host, port) if ( status and (#result >= 8) ) then local ret_code = string.byte(result, 8) if ( ret_code == (0x11) or ret_code == (0x11 + 128) ) then - local sid_table = {} + local sid_table = stdnse.output_table() if ret_code == (0x11) then - table.insert(results, ("Positive response for sid = 0x%x"):format(sid)) local slave_id = extract_slave_id(result) - if ( slave_id ~= nil ) then table.insert(sid_table, "SLAVE ID DATA: "..slave_id) end + sid_table["Slave ID data"] = slave_id or "" elseif ret_code == (0x11 + 128) then local exception_code = string.byte(result, 9) local exception_string = modbus_exception_codes[exception_code] - if ( exception_string == nil ) then exception_string = "UNKNOWN EXCEPTION" end - table.insert(results, ("Positive error response for sid = 0x%x (%s)"):format(sid, exception_string)) + if ( exception_string == nil ) then + exception_string = ("Unknown exception (0x%x)"):format(exception_code) + end + sid_table["error"] = exception_string end local device_table = discover_device_id(host, port, sid) if ( #device_table > 0 ) then - table.insert(sid_table, form_device_id_string(device_table)) + sid_table["Device identification"] = table.concat(device_table, " ") end if ( #sid_table > 0 ) then - table.insert(results, sid_table) + results[("sid 0x%x"):format(sid)] = sid_table end if ( not aggressive ) then break end end @@ -164,7 +164,6 @@ action = function(host, port) port.state = "open" port.version.name = "modbus" nmap.set_port_version(host, port) + return results end - - return stdnse.format_output(true, results) end