While researching Rockwell Automation RSLinx Classic, Tenable found a couple of buffer overflow issues in RSLinx Classic Lite 4.0.1.2. The vulnerabilities may allow an unauthenticated remote attacker to achieve remote code execution or denial of service.
RSLinx Classic Lite (RSLINX.exe) implements the EtherNet/IP protocol which encapsulates Common Industrial Protocol (CIP) messages. An EtherNet/IP packet consists of a 24-byte header followed by command specific data:
struct hdr
{
uint16 command;
uint16 length; // length of the command excluding the header
uint32 SessionHandle;
uint32 status;
octet SenderContext[8];
unit32 options
};
Inside the command specific data block, various CIP-specific length fields can be specified. These include the length of a type ID (a 2-byte field), the length of a connection path (a 1-byte field), and the length of an extended link address in the port path segment in the connection path.
uint16 TypeLength; // length of a Type ID
octet ConnectionPathLength; // number of 16-bit items
octet LinkAddressSize; // length of an Extended Link Address
Although RSLINX.exe limits the command specific data block to 4500 bytes:
.text:5878CEDF movzx edx, [ecx+CLinxServer.hdr_in.len]
.text:5878CEE6 mov [ebp+var_BodyLen], edx
.text:5878CEE9 cmp [ebp+var_BodyLen], 0
.text:5878CEED jl short invalid_len
.text:5878CEEF cmp [ebp+var_BodyLen], 4500 ; command specific block max length
.text:5878CEF6 jle short read_body
It does not check various CIP-specific length fields against the number of received network data in many code paths. An unauthenticated remote attacker can exploit this to cause memory corruption issues.
CVE-2018-14829: Stack Buffer Overflow
There is a function in ENGINE.dll that parses a connection path to extract a port path segment and stores it in a stack buffer. The attacker can specify a large port path segment to overflow the stack buffer:
.text:6950B0E4 movzx eax, [ebp+var_sizeFromPortSeg] ; size from input port path segment; attacker-controlled
.text:6950B0E8 push eax ; size_t
.text:6950B0E9 mov ecx, [ebp+var_pConnPath]
.text:6950B0EC push ecx ; void *
.text:6950B0ED mov edx, [ebp+arg_pOut_PortSegLen] ; set to 0 on function entry
.text:6950B0F0 movzx eax, word ptr [edx]
.text:6950B0F3 add eax, [ebp+arg_pOut_PortSeg] ; buffer on the stack; 128ish bytes
.text:6950B0F6 push eax ; void *
.text:6950B0F7 call memcpy
The attacker can specify up to 255 bytes of port path segment as the length field for the segment is 1-byte wide. On a 32-bit Windows 7 SP1 with ENGINE.dll version 4.0.1.2, the stack buffer is about 0xD4 bytes from the function return address. So the local variables after stack buffer and data after the return address can be overwritten. The following WinDbg output shows 0x102 bytes of attacker-controlled data is being copied to a 128-byte stack buffer:
0:018> r
eax=07faf988 ebx=0015f328 ecx=012d2dba edx=07fafa0a esi=012e9508 edi=00000674
eip=6950b0f7 esp=07faf6ec ebp=07faf738 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
ENGINE!ReleaseASADispatcherPathHandle+0x93a7:
6950b0f7 e8869f0700 call ENGINE!VLink_FindFirstLinkID+0xaac2 (69585082)
0:018> dd esp L3
07faf6ec 07faf988 012d2dba 00000102
0:018> db 012d2dba L102
012d2dba 10 ff 41 41 41 41 41 41-41 41 41 41 41 41 41 41 ..AAAAAAAAAAAAAA
012d2dca 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2dda 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2dea 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2dfa 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e0a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e1a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e2a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e3a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e4a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e5a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e6a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e7a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e8a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2e9a 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2eaa 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
012d2eba 41 01
CVE-2018-14821 - Heap Buffer Overflow
When type ID 0xb2 is specified in command 0x6f (send RR data), the type's data is copied to a heap buffer within a CPacket object. If the attacker specifies a large type length, they can overflow the heap buffer in the CPacket object:
.text:5F6421B3 jle short loc_5F6421D3
.text:5F6421B5 movzx ecx, [ebp+arg_TypeDataLen] ; attacker-controlled len up to 0xffff
.text:5F6421B5 ; heap overflow!
.text:5F6421B9 push ecx ; size_t
.text:5F6421BA mov edx, [ebp+arg_pTypeData] ; attacker-controlled data
.text:5F6421BD push edx ; void *
.text:5F6421BE mov eax, [ebp+var_pCPacket]
.text:5F6421C1 mov ecx, [eax+CPacket.pAppData]
.text:5F6421C7 add ecx, TYPE.data
.text:5F6421CA push ecx ; heap buffer of 0x1330ish bytes
.text:5F6421CB call _memcpy
The vulnerable function attempts to copy 0x1fff bytes from the source buffer to a heap buffer. However, the destination heap buffer has less than that. An exception is thrown when attempting to copy 0x1fff bytes of data to a heap buffer of less than 0x1336 bytes:
0:017> g
(80c.f38): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000071 ebx=0027f488 ecx=00000000 edx=00000000 esi=016e9418 edi=000006a8
eip=69364e8e esp=08e5f6e4 ebp=08e5f750 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
ENGINE!CProtocolASA::OnRequestMsg+0xee:
69364e8e 668901 mov word ptr [ecx],ax ds:0023:00000000=????