Vulnerability Description
OpENer is vulnerable to a severe memory corruption issue caused by integer overflow and signedness truncation. When parsing incoming CIP (Common Industrial Protocol) network packets, the length parameter is inconsistently typed across the call stack. Specifically, an upstream length calculated as an int is passed to a downstream function that expects an EipInt16 (a 16-bit signed integer).
If a maliciously crafted packet with specific length fields is processed, the length parameter can overflow or be truncated into a negative value. This negative length bypasses subsequent bounds checking (due to signed/unsigned comparison issues) and is ultimately used in memory operations, leading to a Stack Buffer Overflow when reading data in DecodePaddedEPath.
Root Cause
The root cause lies in inconsistent integer types and missing bounds checks in source/src/cip/cipmessagerouter.c:
- Type Truncation:
NotifyMessageRouter(EipUint8 *data, int data_length, ...) receives data_length as a 32-bit int. It then calls CreateMessageRouterRequestStructure(const EipUint8 *data, EipInt16 data_length, ...). If data_length is greater than 32767, it is truncated to a negative EipInt16 value.
- Integer Overflow: In
endianconv.c, there are unsafe shift operations (e.g., left shift of 128 by 24 places) that cause Undefined Behavior (UBSan trigger) when processing malicious length fields, contributing to the corrupted length value.
- Bypassed Bounds Check: Inside
CreateMessageRouterRequestStructure(), there is a check: if(number_of_decoded_bytes > data_length). Since number_of_decoded_bytes is a size_t (unsigned), the negative data_length is implicitly cast to a massive unsigned value, bypassing the check.
- Underflow to Massive Size: The remaining data size is calculated as
request_data_size = data_length - number_of_decoded_bytes. Since request_data_size is size_t, subtracting from a negative value results in an enormous unsigned size. This corrupted size is passed to DecodePaddedEPath, causing a stack buffer overflow when it reads past the bounds of the incoming_message buffer.
Trigger Conditions
- The target device is running OpENer and listening on the default ENIP TCP port (44818).
- The attacker establishes a standard TCP connection and registers a session.
- The attacker establishes a CIP connection (e.g., via
ForwardOpen).
- The attacker sends a
SendUnitData request where the ConnectedDataItem.length is intentionally set to 1 (which becomes negative after subtracting header lengths) and appends a large amount of forged path words.
Reproduction (Validated)
PoC.zip
1) Build:
Compile the OpENer project on a POSIX environment (e.g., Ubuntu). Enable OpENer_TRACES and ASan/UBSan to observe the crash.
Edit bin/posix/setup_posix.sh to ensure the following flags are set:
-DOpENer_TRACES:BOOL=ON \
-DOpENer_TRACE_LEVEL_ERROR:BOOL=ON \
-DCMAKE_C_FLAGS:STRING="-fsanitize=address,undefined -fno-omit-frame-pointer -DOPENER_TCPIP_IFACE_CFG_SETTABLE=1" \
Then build the project:
cd bin/posix
./setup_posix.sh
make
2) Run target:
Start the OpENer service, listening on the loopback interface:
./src/ports/POSIX/OpENer lo
3) Send attack traffic:
In a new terminal, execute the attacker script to establish a connection and send the payload that triggers the integer truncation and overflow:
4) Observe Phenomena:
The OpENer server will immediately crash. The logs will first show a UBSan runtime error regarding an invalid left shift, followed immediately by a massive ASan stack-buffer-overflow trace originating from DecodePaddedEPath.
Server Log Output:
networkhandler: opened new TCP connection on fd 22
/home/user/OpENer/source/src/enet_encap/endianconv.c:101:76: runtime error: left shift of 128 by 24 places cannot be represented in type 'int'
something is wrong with the length in Message Router @ CreateCommonPacketFormatStructure
=================================================================
==522093==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc44fc2890 at pc 0x55b1462f26ae bp 0x7ffc44fc1be0 sp 0x7ffc44fc1bd0
READ of size 1 at 0x7ffc44fc2890 thread T0
#0 0x55b1462f26ad in DecodePaddedEPath /home/user/OpENer/source/src/cip/cipcommon.c:1403
#1 0x55b146310bbe in CreateMessageRouterRequestStructure /home/user/OpENer/source/src/cip/cipmessagerouter.c:254
#2 0x55b14631017c in NotifyMessageRouter /home/user/OpENer/source/src/cip/cipmessagerouter.c:188
#3 0x55b146323142 in NotifyConnectedCommonPacketFormat /home/user/OpENer/source/src/enet_encap/cpf.c:173
#4 0x55b14632a555 in HandleReceivedSendUnitDataCommand /home/user/OpENer/source/src/enet_encap/encap.c:526
#5 0x55b146327865 in HandleReceivedExplictTcpData /home/user/OpENer/source/src/enet_encap/encap.c:191
#6 0x55b1462debe6 in HandleDataOnTcpSocket /home/user/OpENer/source/src/ports/generic_networkhandler.c:864
#7 0x55b1462dcd8a in NetworkHandlerProcessCyclic /home/user/OpENer/source/src/ports/generic_networkhandler.c:497
#8 0x55b1462da513 in executeEventLoop /home/user/OpENer/source/src/ports/POSIX/main.c:261
#9 0x55b1462da3bd in main /home/user/OpENer/source/src/ports/POSIX/main.c:229
#10 0x7f4ba2672082 in __libc_start_main ../csu/libc-start.c:308
#11 0x55b1462d9bed in _start (/home/user/OpENer/bin/posix/src/ports/POSIX/OpENer+0x89bed)
Address 0x7ffc44fc2890 is located in stack of thread T0 at offset 1312 in frame
#0 0x55b1462de27b in HandleDataOnTcpSocket /home/user/OpENer/source/src/ports/generic_networkhandler.c:720
This frame has 6 object(s):
[48, 52) 'remaining_bytes' (line 722)
[64, 68) 'fromlen' (line 852)
[80, 88) 'read_buffer' (line 760)
[112, 128) 'sender_address' (line 850)
[144, 672) 'outgoing_message' (line 862)
[800, 1312) 'incoming_message' (line 732) <== Memory access at offset 1312 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/user/OpENer/source/src/cip/cipcommon.c:1403 in DecodePaddedEPath
Shadow bytes around the buggy address:
0x1000089f04c0: 00 00 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
0x1000089f04d0: f2 f2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000089f04e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000089f04f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000089f0500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1000089f0510: 00 00[f3]f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00
0x1000089f0520: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000089f0530: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 06 f3 f3 f3
0x1000089f0540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000089f0550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x1000089f0560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==522093==ABORTING
Impact Assessment
This is a High severity memory corruption vulnerability. Because OpENer processes network packets without proper length validation and type safety, an unauthenticated attacker can remotely trigger a stack buffer overflow. While this PoC demonstrates a reliable DoS by crashing the service, stack buffer overflows can potentially be leveraged for Remote Code Execution (RCE) depending on the target architecture's memory protections (like Stack Canaries and ASLR). Given its use in Industrial Control Systems, a crash leads to an immediate loss of communication and control capability.
Vulnerability Description
OpENer is vulnerable to a severe memory corruption issue caused by integer overflow and signedness truncation. When parsing incoming CIP (Common Industrial Protocol) network packets, the length parameter is inconsistently typed across the call stack. Specifically, an upstream length calculated as an
intis passed to a downstream function that expects anEipInt16(a 16-bit signed integer).If a maliciously crafted packet with specific length fields is processed, the length parameter can overflow or be truncated into a negative value. This negative length bypasses subsequent bounds checking (due to signed/unsigned comparison issues) and is ultimately used in memory operations, leading to a Stack Buffer Overflow when reading data in
DecodePaddedEPath.Root Cause
The root cause lies in inconsistent integer types and missing bounds checks in
source/src/cip/cipmessagerouter.c:NotifyMessageRouter(EipUint8 *data, int data_length, ...)receivesdata_lengthas a 32-bitint. It then callsCreateMessageRouterRequestStructure(const EipUint8 *data, EipInt16 data_length, ...). Ifdata_lengthis greater than 32767, it is truncated to a negativeEipInt16value.endianconv.c, there are unsafe shift operations (e.g.,left shift of 128 by 24 places) that cause Undefined Behavior (UBSan trigger) when processing malicious length fields, contributing to the corrupted length value.CreateMessageRouterRequestStructure(), there is a check:if(number_of_decoded_bytes > data_length). Sincenumber_of_decoded_bytesis asize_t(unsigned), the negativedata_lengthis implicitly cast to a massive unsigned value, bypassing the check.request_data_size = data_length - number_of_decoded_bytes. Sincerequest_data_sizeissize_t, subtracting from a negative value results in an enormous unsigned size. This corrupted size is passed toDecodePaddedEPath, causing a stack buffer overflow when it reads past the bounds of theincoming_messagebuffer.Trigger Conditions
ForwardOpen).SendUnitDatarequest where theConnectedDataItem.lengthis intentionally set to1(which becomes negative after subtracting header lengths) and appends a large amount of forged path words.Reproduction (Validated)
PoC.zip
1) Build:
Compile the OpENer project on a POSIX environment (e.g., Ubuntu). Enable
OpENer_TRACESand ASan/UBSan to observe the crash.Edit
bin/posix/setup_posix.shto ensure the following flags are set:-DOpENer_TRACES:BOOL=ON \ -DOpENer_TRACE_LEVEL_ERROR:BOOL=ON \ -DCMAKE_C_FLAGS:STRING="-fsanitize=address,undefined -fno-omit-frame-pointer -DOPENER_TCPIP_IFACE_CFG_SETTABLE=1" \Then build the project:
cd bin/posix ./setup_posix.sh make2) Run target:
Start the OpENer service, listening on the loopback interface:
3) Send attack traffic:
In a new terminal, execute the attacker script to establish a connection and send the payload that triggers the integer truncation and overflow:
4) Observe Phenomena:
The OpENer server will immediately crash. The logs will first show a UBSan runtime error regarding an invalid left shift, followed immediately by a massive ASan
stack-buffer-overflowtrace originating fromDecodePaddedEPath.Server Log Output:
Impact Assessment
This is a High severity memory corruption vulnerability. Because OpENer processes network packets without proper length validation and type safety, an unauthenticated attacker can remotely trigger a stack buffer overflow. While this PoC demonstrates a reliable DoS by crashing the service, stack buffer overflows can potentially be leveraged for Remote Code Execution (RCE) depending on the target architecture's memory protections (like Stack Canaries and ASLR). Given its use in Industrial Control Systems, a crash leads to an immediate loss of communication and control capability.