CVE-2024-24956,CVE-2024-24957,CVE-2024-24959,CVE-2024-24958,CVE-2024-24955,CVE-2024-24954
Several out-of-bounds write vulnerabilities exist in the Programming Software Connection FileSystem API functionality of AutomationDirect P3-550E 1.2.10.9. Specially crafted network packets can lead to heap-based memory corruption. An attacker can send malicious packets to trigger these vulnerabilities.
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
8.2 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H
CWE-787 - Out-of-bounds Write
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 the engineering workstation protocol DirectNET.
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 overarching feature 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.
This set of vulnerabilities arises in the file-system related feature set, reachable when the first byte of IMM
is 0xF
. The function responsible for implementing these features is located at offset 0xb6784
and we refer to it as _DISCOVERY_CALLBACK_F
. Within this function, the second byte of IMM
is used in a switch-case to identify the exact feature being requested. These vulnerabilities appear quite often throughout the file-system features, effectively occuring in any feature that expects to receive a path argument in the payload. These vulnerable sub-functions expect a very simple payload.
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Path Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Path |
+ .... +
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The first of these vulnerabilities appears within the ‘Delete File’ feature at offset 0xb69c8
, but the flaw is generally the same across all instances. Below, we include the vulnerable portion of the Delete File
handler, accessed via IMM[0] = 0xF, IMM[1] = 0x3
.
0000b69c8 case 0x3:
// [1] Attempt to null-terminate the path, using the attacker-controlled path_len value
0000b69c8 pkt->path[pkt->path_len] = '\0';
0000b69cc int32_t success = FS_DEL(&pkt->path);
0000b69d4 if (success)
0000b69e4 pkt->success_flag = 1;
0000b69d8 else
0000b69d8 pkt->success_flag = 0;
The implementation is rather straightforward - the path
provided in the request is passed to a function we refer to as FS_DEL
and the success of that operation is returned to the client. This vulnerability arises from the null-termination step occuring at 0xb69c8
, where the attacker-controlled path_len
field is used to calculate a pointer to the end of the path and guarantee the path is null-terminated. An attacker can craft a request whose path_len
value would cause this calculation to land outside the bounds of the path
parameter, and write a null-byte to an arbitrary address. Given that the pkt
variable is allocated on the heap, accurately controlling the destination of the null-byte overwrite is difficult without an info-leak, unless the attacker targets structures relative to the object itself, such as heap metadata which immediately precedes every heap allocation.
The next instance of this vulnerability arises for case IMM[0] = 0x0F && IMM[1] = 0x04
which implements the mkdir
operation. It expects the same structure of packet as described above.
0000b6a00 case 4:
0000b6a00 {
// [1] Similarly, attempt to null-terminate using attacker-controlled path_len field
0000b69fc pkt->path[pkt->path_len] = 0;
0000b6a04 PCMON > FI > MKDIR handler(&pkt->path);
0000b6a10 if (true)
0000b6a0c {
0000b6a20 pkt->path_len = 1;
0000b6a20 }
0000b6a14 else
0000b6a14 {
0000b6a14 pkt->path_len = 0;
0000b6a14 }
0000b6a24 response_length = 0x14;
0000b6a24 break;
0000b6a24 }
The next instance of this vulnerability arises for case IMM[0] = 0x0F && IMM[1] = 0x06
which implements the rmdir
operation. It expects the same structure of packet as described above.
0000b6a3c case 6:
0000b6a3c {
// [1] Similarly, attempt to null-terminate using attacker-controlled path_len field
0000b6a38 pkt->path[pkt->path_len] = 0;
0000b6a48 if (rmdir(&pkt->path))
0000b6a44 {
0000b6a58 pkt->response = 1;
0000b6a58 }
0000b6a4c else
0000b6a4c {
0000b6a4c pkt->response = 0;
0000b6a4c }
0000b6a5c response_length = 0x14;
0000b6a5c break;
0000b6a5c }
The next instance of this vulnerability arises for case IMM[0] = 0x0F && IMM[1] = 0x0E
which destroys a timer object used during file transfer operations. It expects the same structure of packet as described above. While it is likely that the actual names of the fields for this packet are not ‘path’ and ‘path_len’ they are treated the same and the same style of vulnerability arises.
0000b6a74 case 0xe:
0000b6a74 {
0000b6a74 if (D11TMR_Created != 0)
0000b6a70 {
0000b6a80 NU_Control_Timer(&D11TMR_Timer, NU_DISABLE_TIMER);
0000b6a88 NU_Destroy_Timer(&D11TMR_Timer);
0000b6a90 D11TMR_Created = 0;
0000b6a90 }
// [1] Similarly, attempt to null-terminate using attacker-controlled path_len field
0000b6aa4 pkt->path[pkt->path_len] = 0;
0000b6ab4 if (data_1d7adc != 0)
0000b6ab0 {
0000b6abc pkt->path[0] = 1;
0000b6abc }
For the remaining two instances of these vulnerabilities, the vulnerable fields of the packet payload differ slightly. Instead of an invalid index caused by pkt->path[pkt->path_len]
the invalid index is caused by fields we believe represent directory
and directory_len
which occur at offsets 0x138 and 0x134 respectively.
This instance arises when IMM[0] = 0x0F && IMM[1] = 0x14
and it is still unclear what functionality this exposes.
0000b6be0 case 0x14:
0000b6be0 {
// [1] Similarly, attempt to null-terminate using attacker-controlled directory_len field
0000b6bdc pkt->directory[pkt->directory_len] = 0;
0000b6bf0 if (sub_b8070(pkt) != 1)
0000b6bec {
0000b6c00 pkt->response_field = 1;
0000b6c00 }
0000b6bf4 else
0000b6bf4 {
0000b6bf4 pkt->response_field = 0;
0000b6bf4 }
0000b6c04 response_length = 0x138;
0000b6c04 break;
0000b6c04 }
The final instance of this vulnerability arises for case IMM[0] = 0x0F && IMM[1] = 0x16
which implements an unknown operation. It expects the same structure of packet as described in the previous vulnerability.
0000b6c1c case 0x16:
0000b6c1c {
// [1] Similarly, attempt to null-terminate using attacker-controlled directory_len field
0000b6c18 pkt->directory[pkt->directory_len] = 0;
0000b6c2c if (sub_b80f4(pkt) != 1)
0000b6c28 {
0000b6c3c pkt->response_field = 1;
0000b6c3c }
0000b6c30 else
0000b6c30 {
0000b6c30 pkt->response_field = 0;
0000b6c30 }
0000b6c40 response_length = 0x138;
0000b6c40 break;
0000b6c40 }
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.