EIPStackGroup / EIPStackGroup/OpENer

Integer Overflow and Truncation Leading to Stack Buffer Overflow in CIP Message Router

Open
#563 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
857
Forks
314
Avg merge
18d 2h
Merged PRs (30d)
1

Description

## Vulnerability Description
OpENer 2.3.0 (commit 76b95cf) 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`:
1. **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.
2. **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.
3. **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.
4. **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
1. The target device is running OpENer and listening on the default ENIP TCP port (44818).
2. The attacker establishes a standard TCP connection and registers a session.
3. The attacker establishes a CIP connection (e.g., via `ForwardOpen`).
4. 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](https://github.com/user-attachments/files/27008509/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:
```bash
-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:
```bash
cd bin/posix
./setup_posix.sh
make
```

**2) Run target:**
Start the OpENer service, listening on the loopback interface:
```bash
./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:
```bash
python3 attacker.py
```

**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:**
```text
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.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.