CVE-2024-24851
A heap-based buffer overflow vulnerability exists in the Programming Software Connection FiBurn functionality of AutomationDirect P3-550E 1.2.10.9. A specially crafted network packet can lead to a buffer overflow. An attacker can send an unauthenticated packet to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
AutomationDirect P3-550E 1.2.10.9
7.5 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
CWE-805 - Buffer Access with Incorrect Length Value
The P3-550E is the most recent CPU module released in the Productivity3000 line of Programmable Automation Controllers from AutomationDirect. It is an affordable control CPU which communicates remotely via ethernet, serial, and USB and exposes a variety of control services, including MQTT, Modbus, ENIP, and an unnamed programming/control protocol.
The P3-550E exposes a “Programming Software Connection” service over UDP port 9999 that is used by the engineering workstation software to program and otherwise configure the device. The protocol is not well documented and what information we do have is pieced together from reverse engineering efforts.
Each message of the protocol is prefixed with a 12-byte header containing the requesting client’s IP address and originating port, two 16-bit fields only referred to as ‘GBS’ and ‘IMM’, a 16-bit field of unknown value, followed by a payload which varies by the type of request.
0 1
0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| GBS | Client Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Client IP |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IMM | UNKNOWN |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The first byte of the IMM field acts as a function code, dictating which high-level feature set is being requested, and the second byte dictates the exact functionality expected. The protocol format for the remainder of the message is dependent on the IMM
value.
These vulnerabiliies arise in the file-system related feature set, reachable when the first byte of IMM
is 0xD
. The function responsible for implementing these features is located at offset 0xb5430
and we refer to it as _DISCOVERY_CALLBACK_D
. Within this function, the second byte of IMM
is used in a switch-case to identify the exact feature being requested. We are most interested in the implementation of the handler associated with IMM[1] = 0x12
. This sub-function expect a payload which contains two fields of interest - a payload and its length. It appears that the contents of the payload are file contents to be burned to local memory upon completion of the file transfer.
0 1
0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| UNK | UNK |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| LEN |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| PAYLOAD |
| ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Within the switch-case associated with IMM[1] = 0x12
a function we refer to as IMM_0D_FIBurn_Handler
(located at offset 0xb5d04
) is called, receiving the pkt
variable as its only parameter. The standard code flow within this function will ultimately call into the vulnerable function, sub_dff18
, which takes as its parameters the payload length recovered from offset 0x10 of the packet, and a pointer to the start of the payload which begins at offset 0x14 of the packet. This function begins at offset 0xdff18
of the firmware, and an annotated decompilation is included below.
0000dff18 int32_t sub_dff18(int32_t payload_len, void* payload)
0000dff18 {
0000dff38 data_17fdc1 = 0;
0000dff48 int32_t r30_1 = 0xa;
0000dff60 while (true)
0000dff60 {
// Wait on a global flag to be set, or until we've unsuccessfully waited 10 times
0000dff68 if (r30_1-- == 0)
0000dff68 {
0000dff68 break;
0000dff68 }
0000dff74 if (CHUNK_RX_structure.field_18 != 0)
0000dff70 {
0000dff74 break;
0000dff74 }
0000dff5c NU_Task_Sleep(2);
0000dff58 }
0000dff84 if (data_1fcae0 != 3)
0000dff80 {
0000dff9c void* dest;
// [1] Allocate heap memory based on attacker controlled `payload_len`
// Observe that `payload_len + 0x14` can overflow, resulting in a smaller than expected allocation
0000dff9c NU_STATUS status = NU_Allocate_Memory(&SYSMEM_pool, &ret_ptr, (payload_len + 0x14), 0);
0000dffa8 if (status == NU_SUCCESS)
0000dffa0 {
// [2] Copy an attacker controlled number of bytes from `payload` to `dest`, which will
// crash when `payload_len` is large enough to overflow, due to the null-byte padding of `strncpy`
0000dffb8 strncpy(dest, payload, payload_len);
// [3] Note that if somehow this call to `strncpy` were not to crash, then this following line would
// result in an arbitrary null-byte overwrite, letting an attacker manipulate heap chunk metadata
0000dffbc dest[payload_len] = 0;
0000dffbc ...
The intent of this function is to prepare a structure which contains the information necessary to burn the payload into a target file on the system’s local memory and then spawning a new task which takes the structure as its parameter. It does this by first attempting to allocate this structure, which varies in length based on the size of the attacker-controlled payload. The non-varying size of the structure is 0x14 bytes, as evidenced by the the allocation requesting payload_len + 0x14
bytes of memory. If payload_len
is sufficiently large, this calculation can overflow and an unexpectedly small heap allocation might be made. After the allocation, a call to strncpy
is made, which will begin to copy the packet’s payload, but ultimately crash on a memory access violation while trying to pad null-bytes. An unauthenticated attacker who submits an appropriately formatted packet to this service can cause the device to crash due to memory access violations during the null-byte padding phase of strncpy
.
A CISA advisory can be found here: https://www.cisa.gov/news-events/ics-advisories/icsa-24-144-01
2024-02-14 - Initial Vendor Contact
2024-02-15 - Vendor Disclosure
2024-05-23 - Vendor Patch Release
2024-05-28 - Public Release
Discovered by Matt Wiseman of Cisco Talos.