From 0d47952611198ef6b1163f366dc03922d20b1475 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:42:04 +0200 Subject: Adding upstream version 7.94+git20230807.3be01efb1+dfsg. Signed-off-by: Daniel Baumann --- scripts/pcworx-info.nse | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 scripts/pcworx-info.nse (limited to 'scripts/pcworx-info.nse') diff --git a/scripts/pcworx-info.nse b/scripts/pcworx-info.nse new file mode 100644 index 0000000..4b5f7ad --- /dev/null +++ b/scripts/pcworx-info.nse @@ -0,0 +1,111 @@ +local string = require "string" +local nmap = require "nmap" +local shortport = require "shortport" +local stdnse = require "stdnse" + +description = [[ +This NSE script will query and parse pcworx protocol to a remote PLC. +The script will send a initial request packets and once a response is received, +it validates that it was a proper response to the command that was sent, and then +will parse out the data. PCWorx is a protocol and Program by Phoenix Contact. + + +http://digitalbond.com +]] +--- +-- @usage +-- nmap --script pcworx-info -p 1962 +-- +-- +-- @output +--| pcworx-info: +--| PLC Type: ILC 330 ETH +--| Model Number: 2737193 +--| Firmware Version: 3.95T +--| Firmware Date: Mar 2 2012 +--|_ Firmware Time: 09:39:02 + +-- +-- +-- @xmloutput +--ILC 330 ETH +--2737193 +--3.95T +--Mar 2 2012 +--09:39:02 + +author = "Stephen Hilt (Digital Bond)" +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"discovery"} + +portrule = shortport.port_or_service(1962, "pcworx", "tcp") + +-- Safely extract a zero-terminated string if the blob is long enough +-- Returns nil if it is not. +local function get_string(blob, offset) + if #blob >= offset then + return string.unpack("z", blob, offset) + end +end +--- +-- Action Function that is used to run the NSE. This function will send the initial query to the +-- host and port that were passed in via nmap. The initial response is parsed to determine if host +-- is a pcworx Protocol device. If it is then more actions are taken to gather extra information. +-- +-- @param host Host that was scanned via nmap +-- @param port port that was scanned via nmap +action = function(host,port) + local init_comms = "\x01\x01\0\x1a\0\0\0\0x\x80\0\x03\0\x0cIBETH01N0_M\0" + + -- create table for output + local output = stdnse.output_table() + + -- create new socket + local socket = nmap.new_socket() + -- define the catch of the try statement + local catch = function() + socket:close() + end + local try = nmap.new_try(catch) + + try(socket:connect(host, port)) + try(socket:send(init_comms)) + local response = try(socket:receive()) + + if not response:match("^\x81") then + stdnse.debug1("Unexpected or unknown PCWorx message.") + return nil + end + -- pcworx has a session ID that is generated by the PLC + -- This will pull the SID so we can communicate further to the PLC + local sid = string.sub(response, 18, 18) + local init_comms2 = "\x01\x05\0\x16\0\x01\0\0\x78\x80\0" .. sid .. "\0\0\0\x06\0\x04\x02\x95\0\0" + try(socket:send(init_comms2)) + -- receive response + response = try(socket:receive()) + -- TODO: verify this + + -- this is the request that will pull all the information from the PLC + local req_info = "\x01\x06\0\x0e\0\x02\0\0\0\0\0" .. sid .. "\x04\0" + try(socket:send(req_info)) + -- receive response + response = try(socket:receive()) + + -- if the response starts with 0x81 then we will continue + if not response:match("^\x81") then + stdnse.debug1("Unexpected or unknown PCWorx message.") + socket:close() + return nil + end + + -- create output table with proper data + output["PLC Type"] = get_string(response, 31) + output["Model Number"] = get_string(response, 153) + output["Firmware Version"] = get_string(response, 67) + output["Firmware Date"] = get_string(response, 80) + output["Firmware Time"] = get_string(response, 92) + + -- close socket and return output table + socket:close() + return output +end -- cgit v1.2.3