Skip to content

Pre-auth NULL-pointer dereference in S7 Upload handler — snap7 server #15

Description

@entropy1337

[CWE-476] Pre-auth NULL-pointer dereference in S7 Upload handler — snap7 server

Finding ID: SNAP7-06 Severity: High (unauthenticated remote DoS)
Component: snap7 S7 server — TS7Worker::PerformFunctionUpload()

Summary

The S7 Upload handler resolves a block-container from an attacker-controlled
block-type byte via FServer->getArea(BlkType) and immediately calls ->Find()
on the result without a NULL check. TSnap7Server::getArea(int) returns NULL
for any value that is not one of {srvAreaDB, srvAreaOB, srvAreaFB, srvAreaFC, srvAreaSDB}. An attacker who sends an upload request with any other block-type
byte causes a NULL-pointer dereference and crashes the server thread/process —
an unauthenticated remote denial of service.

Affected Version

SCADACS/snap7 at commit f6ff90317ca5d54250f4dcd29209689a74e26d82
(src/core/s7_server.cpp, PerformFunctionUpload, and TSnap7Server::getArea).

Reachability

REACHABLE, unauthenticated. Opcodes pduStartUpload (0x1D), pduUpload (0x1E)
and pduEndUpload (0x1F) all dispatch to PerformFunctionUpload()
(s7_server.cpp:343-345), which unconditionally parses the PDU as a start-upload
request and reads BlkType.

Technical Details

// PerformFunctionUpload()
ReqStartParams = PReqFunStartUploadParams(pbyte(PDUH_in) + sizeof(TS7ReqHeader));
BlkType = ReqStartParams->BlkType;                       // attacker-controlled
area = FServer->getArea(BlkType)->Find(BlkNum);          // line 1034: no NULL check

// TSnap7Server::getArea(int srvArea)
switch (srvArea) { case srvAreaDB: return DBArea; ... case srvAreaSDB: return SDB; }
return NULL;                                              // for any other BlkType

Find()IndexOf() dereferences the NULL container → SEGV.

Data flow: TCP bytes → upload BlkType byte → getArea()==NULLNULL->Find()
→ read at ~offset 0x10 of a NULL object → crash.

Proof of Concept

Discovered automatically by the AFL harness (poc/fuzz_s7_pdu) within seconds.
Minimized crashing input: poc/corpus/seed_upload_nullderef.bin. ASan
(poc/crash/SNAP7-06_upload_nullderef_asan.txt):

ERROR: AddressSanitizer: SEGV on unknown address 0x000000000010
  #0 PS7AreaContainer::IndexOf(unsigned short)  s7_server.cpp:79
  #1 PS7AreaContainer::Find(unsigned short)     s7_server.cpp:65
  #2 TS7Worker::PerformFunctionUpload()         s7_server.cpp:1034
  #3 TS7Worker::PerformPDURequest(int&)         s7_server.cpp:345

Impact

CVSS v3.1: 7.5AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H. Unauthenticated
remote crash of an S7 server commonly deployed in OT/ICS environments.

Suggested Remediation

Check the container before use:

PS7AreaContainer* c = FServer->getArea(BlkType);
if (!c) return /* reply with an S7 error */ false;
area = c->Find(BlkNum);

The same getArea(...)->... pattern should be audited in the Download path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions