OpENer DecodePaddedEPath EPATH path_size OOB read

Open
#592 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
58/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
c

Research direction

Start in source/src/cip/cipcommon.c at DecodePaddedEPath, then inspect its callers to understand how incoming_message bounds are available during CIP request decoding. Run poc/opener_epath_oob_read_repro.c with the documented ASan setup and review poc/OPENER-01-asan.txt. Done means malformed paths no longer read beyond the received buffer and the regression reproducer no longer reports an OOB read.

Written by the indexing model from the issue text.

Description

Target: OpENer (EIPStackGroup EtherNet/IP + CIP stack). source/src/cip/cipcommon.cDecodePaddedEPath.
Affected version: commit 36943e6 (HEAD at time of test); present at HEAD.

Summary

OpENer decodes a CIP EPATH (electronic path) by reading a path_size count byte from the request and then
walking that many path words — without a remaining-buffer-length argument or bound. A request whose EPATH
path_size is larger than the actual data walks off the end of the incoming_message receive buffer.

Technical details

/* source/src/cip/cipcommon.c : DecodePaddedEPath */
number_of_decoded_elements = *message;   /* :1397 path_size, one wire byte, 0..255 words — attacker-controlled */
++message;
while (number_of_decoded_elements < path_size) {     /* :1404 no check vs the received buffer end */
    ...
    case ...:                                        /* e.g. class/instance/attribute segments */
        /* reads *(message+1), message += 2  — walks 2+ bytes per iteration off the buffer */
}

DecodePaddedEPath receives only the message pointer, not the number of bytes remaining in incoming_message
(a fixed receive buffer, ~512 bytes on the stack/session). With path_size = 0xFF and segment bytes that keep
the loop consuming, the walk reads well past the buffer.

Proof of Concept

  • Faithful ASan model (poc/opener_epath_oob_read_repro.c): a 300-byte redzoned buffer models the tail of
    incoming_message; buf[0] = 255 (path_size = max), segment type bytes drive the 2-bytes/iteration walk with
    no end check. ASan (poc/OPENER-01-asan.txt): heap-buffer-overflow READ of size 1 past the 300-byte region.

Root cause

DecodePaddedEPath trusts the in-band path_size count and lacks a remaining-length parameter, so the segment
walk has no upper bound tied to the actual received size.

Impact / Exploitation

An unauthenticated remote attacker (ENIP is unauthenticated) makes an OpENer device read past its receive buffer
while decoding a CIP path — information disclosure of adjacent memory reflected into subsequent processing/
responses, or a crash (DoS) of the industrial device. OpENer is embedded in many EtherNet/IP field devices.

Suggested Remediation

Give DecodePaddedEPath the number of bytes remaining in incoming_message and check every segment read
against it (fail if path_size/segment reads would exceed the remaining length). This mirrors the bounded
decoding used elsewhere in the CIP request path.

Dominant language
C
Stars
858
Forks
314
Avg merge
18d 2h
Merged PRs (30d)
1

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from EIPStackGroup/OpENer

All issues in EIPStackGroup/OpENer

Similar issues

More C issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.