Advisories | 1898 & Co.

Threat Hunt Plan: Siemens S7 Series PLCs — AI-Assisted S7comm Exploitation, snap7 Masquerading Tools, and Internet Exposure

Written by The 1898 & Co. Team | August 19, 2026

Date: August 19, 2026 | Revision 1.0

Hunt Objective and Scope

This hunt seeks evidence that threat actors have located, enumerated, or manipulated Siemens S7 Series programmable logic controllers in the environment, using the tradecraft described in the joint advisory published on August 19, 2026 by NSA, CISA, FBI, DOE and EPA. That tradecraft has four defining characteristics, and the hunt is built around each in turn: targets are located through third-party Internet scanning services rather than by scanning the actors perform themselves; exploitation scripts are generated with AI assistance, compressing the interval between a publicly documented weakness and a working tool; the tooling is built on the legitimate open source snap7.dll and python-snap7 libraries and deliberately masqueraded as ordinary OT monitoring software; and access frequently requires no exploitation at all, because the controllers are reachable and their authentication is unconfigured or minimally configured.

The advisory names no CVE, attributes the activity to no named actor, and publishes no IP addresses, domains or file hashes. This shapes the hunt decisively. There is no indicator list to sweep and no patch level that resolves the question. Every hypothesis below is therefore behavioral, and the two highest-value legs are the ones that need no adversary telemetry at all: an inventory of what the Internet can see of the estate, and a baseline of which hosts legitimately speak S7comm to which controllers. A hunt that waits for a signature here will find nothing.

Environment in scope: every Siemens S7 Series controller — S7-200 across all CPU variants, S7-300 including the 314, 315 and 317 models, S7-400 across all variants, S7-1200 covering the CPU 1211C, 1212C, 1214C, 1215C and 1217C, and S7-1500 across all variants including the F-series safety controllers; every engineering workstation carrying TIA Portal, STEP 7 or any S7 programming capability; the Level 3 and Level 3.5 hosts, jump hosts, historians and vendor remote-access paths with a route to TCP port 102; and the organization's public IP space, ASN allocations and cloud estate for the external-exposure leg. Third-party systems integrators and managed service providers with remote access to controllers are explicitly in scope — the advisory identifies that relationship as the reason asset owners are frequently unaware their systems are exposed, so a hunt that stops at the organizational boundary will miss the most likely path.

Time window: 12 months of retained telemetry where available, with a mandatory minimum of 90 days. The activity described is persistent reconnaissance and capability development conducted over an extended period, not a single intrusion event, so a short window characterizes noise rather than the pattern. Note also that a controller reachable from the Internet has been enumerable for as long as it has been reachable, independent of any telemetry the organization holds.

Two scoping notes on protocol coverage. First, TCP port 102 carries both S7comm and IEC 61850 MMS; the two are distinguished by the protocol-ID byte at the start of the COTP payload — 0x32 for classic S7comm, 0x72 for S7CommPlus, and neither for MMS — so a port-based query alone will conflate them at a site running both. Second, S7-1200 and S7-1500 controllers programmed through TIA Portal use S7CommPlus, whose body is obscured by session-keyed integrity material on modern firmware. Semantic function-code analysis is therefore available for classic S7comm but not for S7CommPlus; on those controllers, treat the volume of 0x72 data frames to a CPU as a programming-session indicator and fall back to connection-level and endpoint evidence. Stating this limit up front prevents a clean-looking negative from being read as an absence of activity.

Out of scope: any active interrogation of a controller. No port scanning, no S7comm probing, no COTP connection requests, no active-query module pointed at an S7 device, and no authentication attempts. Active queries against S7 controllers carry genuine process risk and are prohibited for the duration of this hunt. The external-exposure leg reads third-party scan indices only and never touches target infrastructure.

Hypotheses and Hunt Procedures

Hypothesis 1: an external actor can identify an Internet-exposed or insufficiently segmented Siemens S7 Series PLC belonging to the organization through a third-party Internet scanning index, observable as an exposed TCP 102 service in those indices. Execute FIRST; its output scopes every internal hypothesis.

MITRE ATT&CK: Reconnaissance | T1596.005 Search Open Technical Databases: Scan Databases | this is the advisory's own first technique — the actors query scanning services rather than scanning themselves, so the defender's only view of this phase is the same index the actor reads. Initial Access | T1133 External Remote Services. ICS | T0883 Internet Accessible Device | an Internet-reachable PLC is a finding independent of any observed exploitation. ICS | T0846 Remote System Discovery.

Collection Queries — passive external indices (STRICTLY passive; never probe target infrastructure):

Shodan — run unscoped first to confirm the filter matches the product, then scoped to your estate:

port:102

 

port:102 "Siemens"

 

product:"Siemens S7"

 

port:102 net:<your_public_CIDR>

 

product:"Siemens S7" org:"<Your Org Name>"

 

port:102 asn:AS<your_ASN>

 

ssl.cert.subject.CN:"<your_domain>"

 

shodan count 'port:102 net:<your_public_CIDR>'

 

shodan search --fields ip_str,port,org,hostnames,product,version 'port:102 net:<your_public_CIDR>'

 

Censys CenQL — author the CenQL form (host.services.*), never the deprecated legacy CSL form. The nested parenthesized form is required so the criteria hold on the same service object:

host.services.port = "102"

 

host.services: (port = "102" and software.vendor: "Siemens")

 

host.services: (port = "102" and banner: "Siemens")

 

host.services: (port = "102") and (host.autonomous_system.asn = <your_ASN> or host.ip: "<your_public_CIDR>")

 

host.services.software.product: "S7" and host.dns.names: "<your_domain>"

 

Netlas — tie-breaker only, when Shodan and Censys disagree:

port:102

 

host:<your_public_CIDR> AND port:102

 

certificate.subject.common_name:"<your_domain>"

 

Cross-reference every exposed service and version banner against the CISA Known Exploited Vulnerabilities catalog (https://www.cisa.gov/known-exploited-vulnerabilities-catalog). A KEV match on the controller or on any co-resident service converts an exposure finding into a presumptive initial-access risk; rank by ransomware ratio, not by entry count.

Analysis Queries:

  • Attribute every hit with at least two independent ownership signals — PTR record, ASN, certificate CN or SAN, WHOIS/RDAP, and your own cloud and public-IP inventory — before reporting it. Shared hosting, cellular carrier NAT and integrator-owned address space break attribution in both directions, and an unattributable hit is inconclusive rather than negative. Integrator-owned space deserves specific attention here: a controller exposed on a service provider's address range is still your controller.
  • Version-triage each banner against the targeted model list and record the index scan timestamp with every hit. Siemens equipment order numbers of the 6ES7 form frequently appear in S7 banners and identify the exact CPU variant; capture them where present.
  • Corroborate in at least two of Shodan, Censys and Netlas before escalating. Absence from an index is evidence only that the index did not observe the host.
  • Historical pivot — establish how far back the exposure extends. Because target selection is performed by reading a scan index, continuous exposure means the asset has been on a published target list for the whole of that period and should be treated as presumptively enumerated.
  • Pivot into the internal hypotheses — every confirmed-owned exposed controller becomes a priority target hunted exhaustively under Hypotheses 2, 3 and 4 rather than sampled, and its full S7comm conversation history for the retained window is reviewed rather than summarized.

Favicon-hash pivoting is available for stripped banners and non-standard ports, but the hash is deployment-specific and the engines hash differently (Shodan MurmurHash3 versus Censys sha256/md5). Derive it passively from an index-computed hash on an instance you own — never by fetching /favicon.ico from a target, and never by copying a hash from a third-party write-up, which silently hunts an unrelated population.

API keys are referenced by environment-variable name only — SHODAN_API_KEY, CENSYS_API_SECRET, CENSYS_ORG_ID, NETLAS_API_KEY. A missing key is non-blocking: skip that engine and record the coverage gap in the report.

Hypothesis 2: an actor has conducted reconnaissance against S7 controllers from inside the environment, observable as sequential connection attempts to TCP port 102 across multiple addresses, COTP connection requests presenting a programming-device role, and S7comm enumeration functions issued from hosts that are not sanctioned engineering workstations.

MITRE ATT&CK: Discovery | ICS T0846 Remote System Discovery | BlockList, GetBlockInfo and GetDiagData calls plus ReadVar sweeps and COTP connection-request probing are the advisory's enumeration of CPU properties. Collection | ICS T0893 Data from Local System | read operations on data blocks, which the agencies assess as reconnaissance. Lateral Movement | T1694 Insecure Credentials | reaching devices whose authentication is unconfigured or minimally configured.

Collection Queries:

CrowdStrike Falcon LogScale (CQL) — every endpoint-observed connection to an S7 controller. This is the baseline query; the sanctioned engineering set falls out of it and everything else is the hunt:

#event_simpleName = NetworkConnectIP4
| RemotePort = 102
| groupBy([aid, ComputerName, LocalAddressIP4, RemoteAddressIP4], function=count(as=cnt), limit=max)
| sort(cnt, order=desc, limit=max)

 

CrowdStrike Falcon LogScale (CQL) — sequential scanning, expressed as one source reaching many distinct controllers on port 102. A legitimate engineering workstation talks to a small, stable set of CPUs; a scanner talks to many:

#event_simpleName = NetworkConnectIP4
| RemotePort = 102
| groupBy([aid, ComputerName], function=count(RemoteAddressIP4, distinct=true, as=UniqueTargets), limit=max)
| UniqueTargets > 5
| sort(UniqueTargets, order=desc, limit=max)

 

CrowdStrike Falcon LogScale (CQL) — process attribution for port 102 connections. NetworkConnectIP4 does not carry ImageFileName, and the reverse-direction join keeps the subquery well under the 100,000-row cap. Run at Last 90d or longer, because long-running SCADA and historian daemons may have started before a shorter window opens:

#event_simpleName = ProcessRollup2
| join({
#event_simpleName = NetworkConnectIP4
| RemotePort = 102
},
field=[aid, TargetProcessId], key=[aid, ContextProcessId], mode=inner)
| groupBy([ComputerName, UserName, ImageFileName, CommandLine], function=count(as=cnt), limit=max)
| sort(cnt, order=desc, limit=max)

 

CrowdStrike Falcon LogScale (CQL) — controllers or soft-PLC instances accepting inbound connections on 102, which enumerates the listener population from the endpoint side:

#event_simpleName = NetworkReceiveAcceptIP4
| LocalPort = 102
| groupBy([aid, ComputerName, RemoteAddressIP4], function=count(as=cnt), limit=max)
| sort(cnt, order=desc, limit=max)

 

CrowdStrike Falcon LogScale (CQL) — hosts resolving Internet scanning services, which would indicate someone inside the environment consulting the same indices the actors use:

#event_simpleName = DnsRequest
| DomainName = /(censys|zoomeye|shodan)/i
| join(