| عنوان | davenardella snap7 1.4.3 Memory Corruption |
|---|
| الوصف | A vulnerability was found in davenardella snap7 up to and including 1.4.3, in the function
TSnap7MicroClient::opUpload() of the file src/core/s7_micro_client.cpp. The manipulation of the argument
DataLen leads to memory corruption. The affected code derives the length of a memcpy from this
server-supplied field of the S7 protocol response and never validates it.
SUMMARY LINE
Vulnerability class : Memory Corruption
Affected file : src/core/s7_micro_client.cpp
Affected function : TSnap7MicroClient::opUpload()
Affected parameter : DataLen (S7 response header field)
Affected version : up to and including 1.4.3
Vendor / product : https://github.com/davenardella/snap7
Upstream report : https://github.com/davenardella/snap7/issues/30
Proposed CVSS 3.1 : CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L (6.3)
Proposed CVSS 4.0 : CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N (5.3)
The proposed vectors deliberately match those already assigned to CVE-2026-16225, which covers the
equivalent client-side condition in the same library and the same attacker position, so that scoring stays
consistent across the product.
This submission describes ONE vulnerability: a single unvalidated length. The two behaviours shown below
are two ways of reaching the same defect, not two separate issues. A DataLen smaller than the header size
drives the length negative; a large DataLen drives it beyond the receive buffer. One bound closes both.
AFFECTED CODE
The function begins at line 997. Size is declared as a signed int at line 1073. In the first-slice branch
the value is taken directly from the peer:
Done = ResParams->EoU == 0;
if (Full)
Size = SwapWord(Answer->DataLen) - 4;
else
Size = SwapWord(Answer->DataLen) - sizeof(TResFunUploadDataHeaderFirst);
Target = pbyte(&opData) + Offset;
memcpy(Target, Source, Size);
Offset += Size;
The memcpy is line 1116. The next-slice branch repeats the same pattern at line 1164 using
sizeof(TResFunUploadDataHeaderNext), which is 4 bytes. TResFunUploadDataHeaderFirst is 40 bytes.
Three separate things are unchecked: the sign of Size, the value of Size against the number of bytes
actually received, and Offset plus Size against the capacity of the destination.
Relevant declarations, all in the same tree:
src/core/s7_micro_client.h line 294 TS7Buffer opData;
src/core/s7_types.h line 358 typedef byte TS7Buffer[65536];
src/core/s7_isotcp.h lines 38 and 189 IsoPayload_Size 4096, typedef u_char TIsoPayload[IsoPayload_Size]
The ISO transport layer does not mitigate this. isoRecvBuffer() validates only the TPKT length, computing
Size = PDUSize(&PDU) - DataHeaderSize. The DataLen field used above is a separate field carried inside the
S7 payload and is never cross-checked against the TPKT length.
IMPACT
This is a client-side flaw. It affects any application that calls Cli_Upload or TS7Client::Upload, which
in practice means SCADA software, HMIs, historians, engineering tools and protocol gateways that use snap7
to read blocks from a PLC. The attacker position is the server end: a malicious PLC, a rogue device on the
S7 network, or an attacker able to answer the upload sequence.
The condition is reached on the first Upload response. No multi-slice sequence and no prior state are
required beyond a normal connection and PDU negotiation.
PROOF OF CONCEPT
Confirmed dynamically against commit 30f37da built with clang 21.1.8 and AddressSanitizer on Linux x86_64,
using a minimal S7 server on loopback that completes COTP connection, Setup Communication and StartUpload
and then answers the first Upload request with a chosen DataLen.
Variant 1, DataLen set to 0. Size becomes 0 minus 40, that is -40, and reaches memcpy as a size_t:
ERROR: AddressSanitizer: negative-size-param: (size=-40)
#0 __asan_memcpy
#1 TSnap7MicroClient::opUpload() src/core/s7_micro_client.cpp:1116
#2 TSnap7MicroClient::PerformOperation() src/core/s7_micro_client.cpp:2566
#3 TSnap7MicroClient::Upload(int, int, void*, int&) src/core/s7_micro_client.cpp:2984
#4 Cli_Upload src/lib/snap7_libmain.cpp:318
Variant 2, DataLen set to 0xFFF0. Size becomes 65496 and is copied out of a 4096 byte PDU.Payload:
ERROR: AddressSanitizer: memcpy-param-overlap
0x...5a0c is located 4620 bytes inside of 70208-byte region
0x...49c1 is located 449 bytes inside of 70208-byte region
Source and destination both lie inside the same 70208 byte TSnap7MicroClient object, which is why the
sanitizer reports an overlap rather than a plain overflow.
A reproducer exists but has not been published, because there is no released fix and the upstream project
has had no commits since 14 July 2025. It can be provided privately to the maintainer or to the CNA.
SUGGESTED FIX
Bound the length before the copy, in both the first-slice and next-slice branches:
int Size = SwapWord(Answer->DataLen) - int(sizeof(TResFunUploadDataHeaderFirst));
if (Size < 0 ||
Size > int(IsoSize) - int(ResHeaderSize23 + sizeof(TResFunUploadParams)
+ sizeof(TResFunUploadDataHeaderFirst)) ||
uintptr_t(Size) > sizeof(opData) - Offset)
{
Result = errCliUploadSequenceFailed;
break;
}
Three conditions are needed because three separate things are unchecked: the sign, the bytes actually
received, which isoExchangeBuffer already places in IsoSize, and the room remaining in opData. Enforcing
BlockLength, taken from ResDataHeader->MC7Len, against Offset would be a reasonable fourth. The same bound
is required on the Full branch at line 1110, where the subtraction is 4 rather than 40.
PRIOR ART CHECKED
NVD keyword snap7, all nine results read in full. GitHub Advisory Database, both repository advisories and
a global search. CISA KEV. The SourceForge tracker, 34 tickets. The GitHub issue tracker, all 29 issues and
pull requests, searched by symptom and by function name rather than only by fix commits.
Existing memory-safety reports in the same project cover different functions: issue 11 the SZL TS7Buffer
path, issue 14 PerformFunctionWrite, issue 15 TSnap7Partner::PickData, issue 16 PerformFunctionRead,
issue 17 opWriteArea, and issue 20 an uninitialised BitIndex. CVE-2025-15247 covers
snap7_rs::client::S7Client::download in the Rust binding's client.rs, which is a different file and the
opposite direction of transfer. Nothing found covers opUpload.
Reported upstream as davenardella/snap7 issue 30 on 1 August 2026. The maintainer has not responded; the
project has had no commits since 14 July 2025 and carries several unfixed memory-safety reports.
|
|---|
| المصدر | ⚠️ https://github.com/davenardella/snap7/issues/30 |
|---|
| المستخدم | mayur021 (UID 27195) |
|---|
| ارسال | 01/08/2026 02:08 PM (1 شهر منذ) |
|---|
| الاعتدال | 12/09/2026 06:11 PM (1 month later) |
|---|
| الحالة | تمت الموافقة |
|---|
| إدخال VulDB | 403157 [davenardella snap7 حتى 1.4.3 s7_micro_client.cpp opUpload DataLen تلف الذاكرة] |
|---|
| النقاط | 20 |
|---|