--- -- A module implementing IPMI protocol (the code is a porting of the Metasploit ipmi scanner: -- https://github.com/rapid7/metasploit-framework/tree/master/modules/auxiliary/scanner/ipmi) -- -- @class module -- @name ipmi -- @author "Claudiu Perta " local bin = require "bin" local stdnse = require "stdnse" local string = require "string" local rand = require "rand" _ENV = stdnse.module("ipmi", stdnse.seeall) local HAVE_SSL, openssl = pcall(require,"openssl") PAYLOADS = { ["IPMI"] = 0, ["PAYLOAD_SOL"] = 1, ["RMCPPLUSOPEN_REQ"] = 0x10, ["RMCPPLUSOPEN_REP"] = 0x11, ["RAKP1"] = 0x12, ["RAKP2"] = 0x13, ["RAKP3"] = 0x14, ["RAKP4"] = 0x15, } RMCP_ERRORS = { [1] = "Insufficient resources to create new session \ (wait for existing sessions to timeout)", -- Shouldn't occur. [2] = "Invalid Session ID", -- Shouldn't occur. [3] = "Invalid payload type", -- If these happen, we need to enhance our mechanism for detecting -- supported auth algorithms. [4] = "Invalid authentication algorithm", [5] = "Invalid integrity algorithm", [6] = "No matching authentication payload", [7] = "No matching integrity payload", -- This suggests the session was timed out while trying to negotiate, -- shouldn't happen. [8] = "Inactive Session ID", [9] = "Invalid role", [0xa] = "Unauthorised role or privilege level requested", [0xb] = "Insufficient resources to create a session at the requested role", [0xc] = "Invalid username length", [0xd] = "Unauthorized name", [0xe] = "Unauthorized GUID", [0xf] = "Invalid integrity check value", [0x10] = "Invalid confidentiality algorithm", [0x11] = "No cipher suite match with proposed security algorithms", -- Never observed, most likely a bug in xCAT or IPMI device. [0x12] = "Illegal or unrecognized parameter", } channel_auth_request = function() return ( "\x06\x00\xff\x07" .. -- Header "\x00\x00\x00\x00" .. "\x00\x00\x00\x00\x00\x09\x20\x18" .. "\xc8\x81\x00\x38\x8e\x04\xb5" ) end rmcpplus_header = function (payload_type) return ( "\x06\x00\xff\x07" .. -- RMCP Header "\x06" .. -- RMCP+ Authentication Type string.char(PAYLOADS[payload_type]) .. -- Payload Type "\x00\x00\x00\x00" .. -- Session ID "\x00\x00\x00\x00" -- Sequence Number ) end -- Open rmcpplus_request session_open_request = function(console_session_id) local data = ( "\x00\x00" .. -- Maximum Access "\x00\x00" .. -- Reserved console_session_id .. "\x00\x00\x00\x08" .. "\x01\x00\x00\x00" .. "\x01\x00\x00\x08" .. "\x01\x00\x00\x00" .. -- HMAC-SHA1 "\x02\x00\x00\x08" .. "\x01\x00\x00\x00" -- AES Encryption ) return bin.pack("> 6) & 0x03) data["ipmi_user_kg"] = ((value & 0x20) ~= 0) data["ipmi_user_disable_message_auth"] = ((value & 0x10) ~= 0) data["ipmi_user_disable_user_auth"] = ((value & 0x08) ~= 0) data["ipmi_user_non_null"] = ((value & 0x04) ~= 0) data["ipmi_user_null"] = ((value & 0x02) ~= 0) data["ipmi_user_anonymous"] = ((value & 0x01) ~= 0) pos, value = bin.unpack("C", reply, pos) data["ipmi_conn_reserved1"] = ((value >> 2) & 0x3F) data["ipmi_conn_20"] = ((value & 0x02) ~= 0) data["ipmi_conn_15"] = ((value & 0x01) ~= 0) -- 24 bits OEMID, unpack an int and shift 1 byte to the right pos, value = bin.unpack("> 8 -- restore one byte position pos = pos - 1 pos, data["ipmi_oem_data"] = bin.unpack("A", reply, pos) return data end parse_open_session_reply = function(reply) local data = {} local pos = 0 local value -- 4 bytes Header pos, data["rmcp_version"] = bin.unpack("C", reply, pos) pos, data["rmcp_padding"] = bin.unpack("C", reply, pos) pos, data["rmcp_sequence"] = bin.unpack("C", reply, pos) pos, value = bin.unpack("C", reply, pos) -- bit 1 data["rmcp_mtype"] = ((value & 0x80) ~= 0) -- bit [2:8] data["rmcp_class"] = (value & 0x7F) pos, data["session_auth_type"] = bin.unpack("C", reply, pos) pos, value = bin.unpack("C", reply, pos) -- bit 1 data["session_payload_encrypted"] = ((value & 0x80) ~= 0) -- bit 2 data["session_payload_authenticated"] = ((value & 0x40) ~= 0) -- bit [3:8] data["session_payload_type"] = (value & 0x3F) pos, data["session_id"] = bin.unpack("