CVE-2024-24947,CVE-2024-24946
A heap-based buffer overflow vulnerability exists in the Programming Software Connection CurrDir functionality of AutomationDirect P3-550E 1.2.10.9. A specially crafted network packet can lead to denial of service. An attacker can send an unauthenticated packet to trigger these 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
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.
These vulnerabilities arise 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. This vulnerability appears within the error-handling of features IMM[0] = 0xF, IMM[1] = 0x1 || 0x2
which appear to be used to modify a shared current working directory for future file-system requests. The switch case is shared, so both IMM[1] = 0x1 || 0x2
will trigger the same vulnerable code path.
These particular 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 |
+ .... +
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Path Length
is a 32-bit unsigned integer that describes the length of the following path. The function expects (and validates) the length of this field does not exceed 0xFF bytes.
The first vulnerability specifically appears when the length provided is excessively large. We have included below a simplified decompilation of this error-handling implementation. It is worth noting beforehand that the ‘response’ packet is constructed in-place, over top of the original ‘query’ packet, and that every packet is a fixed-size (0x5c0 bytes) heap-allocated buffer and cannot exceed this length.
0000b6784 int32_t _DISCOVERY_CALLBACK_F(struct sockaddr_in* client, struct generic_packet* pkt, int32_t len) {
0000b6784 ...
0000b6814 switch (IMM1) {
0000b6838 case 1:
0000b6838 case 2:
0000b683c int32_t content_len = pkt->content_len;
0000b6848 // [1] Verify the content length is not excessively large
0000b6848 if (content_len u> 0xff) {
0000b6858 // [2] In the case where the content is too large, print an error to the log
0000b6858 printf("IMM 0x0F: Directory name length (%i) exceeded the maximum\r\n", content_len)
0000b686c // [3] Finally, "reset" the directory field, so the response packet does not include it
0000b686c memset(&pkt->directory_name, 0, pkt->content_len)
0000b686c ...
0000b686c }
...
break
...
}
...
The vulnerability arises at [3]
, when the field is being reset using an untrusted and attacker-controlled length field. An attacker can corrupt the heap by providing an excessively large length field, such that the subsequent call to memset
will cause unafilliated heap data following this alloocation to be set to \0
. This could potentially corrupt an actively used object or free-chunk metadata, resulting in a system crash.
A similar vulnerability also appear at offset 0xb68c4
, which is the else
branch of the content_len
check above, at offset 0xb683c
- a decompilation of which is provided also. This code is executed when content_len
is not larger than 0xFF bytes, but also cannot be successfully allocated for some other reason.
0000b68a0 if (NU_Allocate_Memory(&SYSMEM_pool, &result, (pkt->path_len + 1), 0) != 0)
0000b689c {
0000b68ac printf("Memory allocation failed for CurDir in IMM_0F_Handler");
0000b68b0 result = NULL;
0000b68c4 memset(&pkt->path, 0, pkt->path_len);
0000b68cc *(response_pkt + 0x14) = 2;
0000b68d0 response_len = 0x18;
0000b68d4 *(response_pkt + 0x10) = 0;
0000b68d4 }
An attacker who can manipulate resource availability and limit heap allocations such that an allocation of size less than 0xFF still fails could also trigger this vulnerable code path, resulting in another denial of service method.
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.