diff --git a/modicon-info.nse b/modicon-info.nse new file mode 100644 index 0000000..a3cc729 --- /dev/null +++ b/modicon-info.nse @@ -0,0 +1,333 @@ +local bin = require "bin" +local nmap = require "nmap" +local shortport = require "shortport" +local stdnse = require "stdnse" +local string = require "string" +local table = require "table" + +description = [[ +Modicon is a brand of Programmable Logic Controller (PLC) that is put out by +Schneider Electric. This NSE is designed to use Modbus to communicate to the +PLC via Normal queries that are performed via engineering software. The information +that is collected via Modbus is done in two separate function codes. First, Function +Code 43 is utilized to pull the Vendor Name, Network Module, and the Firmware Version. +Second, Schneider uses function code 90 for communications as well. Via Function Code 90 +it is possible to pull information such as the CPU Module, Memory Card Model, and some +information about the project that is loaded into the PLC. + + +http://digitalbond.com +]] +--- +-- @usage +-- nmap --script modicon-info -p 502 +-- +-- +-- @output +--502/tcp open Modbus +--| modicon-info: +--| Vendor Name: Schneider Electric +--| Network Module: BMX NOE 0100 +--| CPU Module: BMX P34 2000 +--| Firmware: V2.60 +--| Memory Card: BMXRMS008MP +--| Project Information: Project - V4.0 +--| Project File Name: Project.STU +--| Project Revision: 0.0.9 +--|_ Project Last Modified: 7/11/2013 5:55:33 +-- @xmloutput +--Schneider Electric +--BMX NOE 0100 +--BMX P34 2000 +--V2.60 +--BMXRMS008MP +--Project - V4.0 +--Project.STU +--0.0.9 +--7/11/2013 5:55:33 + +author = "Stephen Hilt (Digital Bond)" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"discovery", "intrusive","digitalbond"} + +-- +-- Function to define the portrule as per nmap standards +-- +-- +-- +portrule = shortport.portnumber(502, "tcp") + +--- +-- Function to trim white space off the beginning and ending of a string +-- +-- @param s a string passed in that needs white space trimmed off +function trim(s) + -- remove white spaces from beginning and ending of the string + return (s:gsub("^%s*(.-)%s*$", "%1")) +end +--- +-- Function to set the nmap output for the host, if a valid Modbus packet +-- is received then the output will show that the port as Modbus. +-- +-- @param host Host that was passed in via nmap +-- @param port port that Modbus is running on (Default TCP/502) +function set_nmap(host, port) + + --set port Open + port.state = "open" + -- set version name to Modbus + port.version.name = "Modbus" + nmap.set_port_version(host, port) + nmap.set_port_state(host, port, "open") + +end +--- +-- Function to setup the communications to the Modicon. This is where alot +-- of the function code 90 information is sent and parsed for information +-- about the Modicon itself. +-- +-- @param socket Socket passed in via Action to communicate to remote device +-- @param output The output table to add information that is collected +--- +function init_comms(socket, output) + + -- decelerations + local pos + local payload = bin.pack("H","000100000004005a0002") + socket:send(payload) + -- recv packet, however not going to do anything with it + local rcvstatus, response = socket:receive() + -- send and receive, not going to do anything with this packet. + payload = bin.pack("H","000200000005005a000100") + socket:send(payload) + local rcvstatus, response = socket:receive() + -- create a string with 249 T (0x54) + local count = 0 + local ice = "54" + while (count < 248) do + ice = ice .. "54" + count = count + 1 + end + -- send packet with 249 T's (0x54), recv packet and do nothing as well + payload = bin.pack("H","0003000000fe005a00fe00" .. ice) + socket:send(payload) + local rcvstatus, response = socket:receive() + -- send packet that request the project information + payload = bin.pack("H","000400000005005a000300") + socket:send(payload) + local rcvstatus, response = socket:receive() + -- unpack the Project Name, this is configured by the engineers + local pos, project_name = bin.unpack("z", response, 50) + -- unpack the year that the project was last modified + -- define the next sections we are going to unpack + -- Each one is to support time stamp + local project_hour + local project_min + local project_sec + local project_month + local project_day + -- define the 3 vars for the project revision number + local project_rev_1 + local project_rev_2 + local project_rev_3 + -- unpack the time stamp, as well as the revision numbers + -- unpack the seconds + pos, project_sec = bin.unpack("C", response, 38) + -- unpack the min + pos, project_min = bin.unpack("C", response, pos) + -- unpack the hour + pos, project_hour = bin.unpack("C", response, pos) + -- unpack the day + pos, project_day = bin.unpack("C", response, pos) + -- unpack the month + pos, project_month = bin.unpack("C", response, pos) + pos, project_year = bin.unpack("