Where CVE-2026-12569 code actually executes, and what telemetry sees it
The Clop campaign against PTC Windchill produced two structurally different implants. Most coverage treats them as one thing. They are not, they do not generate the same telemetry, and a detection built for one will not fire on the other. This writeup covers the exploit chain, the Windchill process model that determines where your parent-process anchor belongs, the split between the two shells, and how to instrument both platforms with Sysmon.
The exploit chain
CVE-2026-12569 is a deserialization of untrusted data flaw in the Windchill login servlet, affecting PTC Windchill PDMLink and FlexPLM prior to 11.0 M030. NVD scores it 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H); ReliaQuest and SecurityWeek cite 9.3. Same defect, different scoring sources.
It is not exploited alone. Operators chain a pre-authentication information disclosure in the FlexPLM WSDL endpoint (CVSS 7.5) to enumerate the target first. That reconnaissance step has a distinctive fingerprint:
GET /Windchill/rfa/jsp/login/*.jsp?wsdl response_bytes = 4045
A 4045-byte response to that path is the pre-exploitation probe. It is cheap to hunt retroactively and it predates the actual compromise, which makes it the earliest signal available in the entire chain.
Patches shipped June 17, 2026. Ransom-ISAC assesses exploitation began as a zero-day in early June. Scope any hunt to June 1 at the latest.

Where the code executes
This determines your parent anchor, and getting it wrong produces a rule that never fires.
Since Windchill 10.0, Tomcat runs embedded inside the Method Server process. Each Method Server carries its own Tomcat instance, and Windchill always installs the Embedded Servlet Engine regardless of which front-end web server is deployed. Apache sits in front as a reverse proxy over AJP and never executes attacker code.
systemd / services.exe
│
├─ java (Server Manager) wt.server.ServerManager
│ └─ java (Method Server) wt.method.MethodServerMain
│ └─ [embedded Tomcat] ← JSP web shell compiles and runs HERE
│ └─ child process ← anomaly, if one appears at all
│
└─ httpd (Apache) ──AJP──> Method Server
Two consequences. First, monitoring httpd for anomalous children watches the wrong process. Second, on Linux the executing account is not www-data or apache, it is the Windchill installation account (commonly wcadmin or a site-specific name). That account already owns the file vaults and holds the database and keystore credentials, which is why this kill chain contains no privilege escalation stage.
Identifying the Method Server on the command line requires more than Image matching, since java alone is meaningless in an enterprise:
| Anchor | Value |
|---|---|
| Main class | wt.method.MethodServerMain |
| System properties | -Dwt.home=, -Dwt.codebase= |
| Tomcat instance path | catalina.base=.../Windchill/tomcat/instances/instance-<port> |
| Classpath | contains /Windchill/codebase |
| Binary | bundled JRE under the install root, e.g. /opt/ptc/Windchill_XX/Java/bin/java |
The Server Manager (wt.server.ServerManager) is the parent of every Method Server, so any rule keyed on "java spawns java" will fire continuously. Exclude it explicitly. Background Method Servers are Method Server variants and remain valid landing zones, so they stay in scope.
The two web shells
| Custom implant | Generic command shell | |
|---|---|---|
| Filename pattern | /Windchill/login/[0-9a-f]{16}.jsp | /Windchill/login/[0-9a-f]{6}.jsp |
| Also observed | dpr_<8 hex>.jsp (family unconfirmed) | |
| Control channel | X-windchill-req HTTP header | URL query parameter |
| Command format | 8 chars: 1 command + 7 fixed | ?cmd=whoami, ?cmd=id |
| Response encoding | GZIP | plaintext |
| Execution model | in-process, Windchill classes | Runtime.exec() |
| Spawns children | no | yes |
| Endpoint telemetry | one file write, then silence | full process tree |
| Web log visibility | header only, usually unlogged | request line, logged by default |
| Attribution weight | high, Clop-specific | low, anyone |
The custom implant imports MethodContext, WTConnection, and WTKeyStoreUtil, and queries the vault tables ApplicationData, FVITEM, FVMOUNT, and MasteredOnReplicaItem, referencing internal identifiers such as IDA3A4. Its command set:
| Cmd | Function |
|---|---|
S | Read ieStructProperties.txt, decrypt LDAP manager password and all keystore properties via WTKeyStoreUtil.decryptProperty() |
L | Enumerate file vault, write results to flst.txt |
D | Enumerate directories, partial file read |
G | Read file |
R | Delete file |
J | Load and execute Base64 ZIP of Java bytecode in memory |
O | Return operating system name |
E | Echo X-windchill-prm header contents |
Every one of those executes inside the JVM. No fork(), no /bin/sh, no curl. Database queries run through the application's own connection, so database telemetry attributes them to the normal service identity.
The generic shell is the opposite in every respect. It is a stock JSP command shell driven by a query parameter, and it forks children on the operator's first interaction.
One Java behavior matters for the child selector. Runtime.getRuntime().exec(String) does not invoke a shell, it tokenizes and execs the binary directly:
java (Method Server) → whoami # direct exec
java (Method Server) → sh -c "whoami" → whoami # array form with shell
java.exe → cmd.exe /c whoami # Windows
Do not require an intermediate shell. A rule written as "Windchill JVM spawns /bin/sh" misses the direct-exec variant entirely.
The whoami and id pair is a landing check, run to confirm execution and establish context. id does not exist on Windows while whoami exists on both, so an operator trying both is fingerprinting by trial. The custom implant's O command does the same job for the same reason: Windchill runs on Windows Server and Linux, and the operators did not know which they had landed on.
Layer 1: the web tier
Apache's default combined log format does not log arbitrary request headers, which means the highest-fidelity artifact in this campaign is invisible on a stock install. Fix that first:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \
\"%{X-windchill-req}i\" \"%{X-windchill-prm}i\"" windchill_hunt
CustomLog logs/windchill_access.log windchill_hunt
The generic shell needs no config change, because its command rides the query string that stock logging already captures. That makes this hunt free against existing retention:
grep -E '/Windchill/login/[0-9a-f]{6,16}\.jsp' access_log
grep -E '\.jsp\?cmd=' access_log
grep -E '/Windchill/rfa/jsp/login/.*\?wsdl' access_log | awk '$10==4045'
Full coverage of the custom implant requires three things together: header logging, response decompression, and TLS inspection. Any two of the three leaves a gap.
Layer 2: Sysmon for Linux
The implant touches disk exactly once, when the JSP is written into the Windchill codebase. That single event is the highest-value endpoint detection in the entire chain, and Sysmon for Linux EVID 11 captures it.
Install per the Sysinternals guide, then load a hunting config:
sysmon -i /opt/ft-sysmonconfig-linux-export.xml
The config I maintain for this is here:
https://github.com/fluffybunnies-h4x/FT-Linux-Sysmon-Config
Relevant event coverage for this campaign:
| EVID | Event | What it catches |
|---|---|---|
| 11 | File create | JSP written to Windchill codebase, flst.txt creation |
| 1 | Process create | Generic shell children, second-stage tooling |
| 3 | Network connect | Egress from the Method Server JVM |
| 23 | File delete | Operator cleanup via the R command |
A scoped file-create rule for Windchill hosts:
<RuleGroup name="Windchill JSP drop" groupRelation="or">
<FileCreate onmatch="include">
<TargetFilename condition="contains all">/Windchill/codebase/;.jsp</TargetFilename>
</FileCreate>
</RuleGroup>
Adjust the path to your install root. Legitimate JSP writes into that tree happen during patching and deployment only, so the baseline is close to zero outside change windows.
For process creation, anchor on the JVM and cast the child net wider than shells alone:
| Category | Binaries |
|---|---|
| Discovery | whoami, id, uname, hostname, pwd, env, ps, w, ip, ss |
| Shells | bash, sh, dash, ksh, zsh |
| Interpreters | python, python3, perl, ruby, php |
| Network | curl, wget, nc, ncat, socat |
| Staging | tar, zip, gzip, 7z |
Rank confidence within that set. whoami, id, uname, and hostname from a Method Server parent are close to zero false positive. Be more cautious with ls, cat, ps, and env, since Windchill customization code and publishing adapters can plausibly touch them.
Staging utilities deserve more attention than they usually get. This is a data theft campaign, and moving vault contents out means somebody eventually archives them. A Method Server forking tar against a vault path is a better signal for the actor's actual objective than a reverse shell would be.
Legitimate Method Server children do exist, primarily publishing and Creo View Adapter invocation, plus site-specific customization code. Baseline before deploying and filter on your own install paths, the same way you would exclude a daemon's known helper scripts.
Layer 3: Sysmon on Windows
Windchill on Windows Server runs the same architecture with java.exe as the Method Server, typically launched as a service, so the grandparent chain runs back to services.exe.
sysmon.exe -accepteula -i ft-sysmonconfig-export.xml # install
sysmon.exe -c ft-sysmonconfig-export.xml # update existing
The config I maintain, forked from SwiftOnSecurity and tuned against live malware TTPs:
https://github.com/fluffybunnies-h4x/FT-Sysmon-Config
That config already includes asp and aspx in its EVENT ID 11 file-create rules, which is exactly the right instinct: web shell drops are caught at file creation, by extension, in web-accessible directories. This campaign is the argument for extending the same coverage to .jsp. If you run Windchill, WebLogic, Tomcat, JBoss, or any other Java application server on Windows, add the extension and scope it to your application codebase paths. Contributions welcome if you build a good scoped ruleset for it.
Relevant Windows event coverage:
| EVID | Event | What it catches |
|---|---|---|
| 11 | File create | JSP drop into the Windchill codebase |
| 1 | Process create | java.exe forking cmd.exe, whoami.exe, discovery binaries |
| 3 | Network connect | JVM egress |
| 26 | File delete detected | Operator cleanup |
| 7 | Image load | Second-stage DLL side-loading, if the J loader delivers it |
Hunt artifacts
On-host:
# Suspicious JSPs in the codebase, written since the exploitation window opened
find /opt/ptc -path '*Windchill/codebase*' -name '*.jsp' -newermt '2026-06-01'
# Content markers unique to the custom implant
grep -rlE 'X-windchill-req|WTKeyStoreUtil|MethodContext|WTConnection' \
/opt/ptc/*/Windchill/codebase/
# Enumeration artifact
find / -name 'flst.txt' 2>/dev/null
flst.txt is worth more than an IOC hit. It contains vault stream IDs, filenames, storage paths, and file sizes, which makes it a direct record of what the operator inventoried and a far better scoping input than anything in an extortion email.
Network and file indicators:
| Type | Value |
|---|---|
| SHA-256 | 321e1fb01eb3462b48ff6ccdef132acc1182e3f7456548439f0d4ead12fd98bf (ReliaQuest, custom shell) |
| SHA-256 | 55a1eb4c2d3da04376df39d7ba832569c6af1a37a0cf2b95f754ac898023a30c (Ransom-ISAC) |
| C2, priority | 5.180.41.35, 79.141.160.78 |
| C2 | 216.152.148.54, 216.152.151.204, 104.243.35.63, 78.128.113.10, 104.194.9.14, 185.227.83.236, 209.222.98.44 |
| Range | 104.243.35.0/24 |
PTC advisory CS473270 carries the full set, including 44 MD5s and 2 SHA-1s. Validate network indicators against your environment before blocking, since some correspond to shared hosting.
Observed shell filenames: 46b158b8607a4c00.jsp, 4b57d0652345d383.jsp, 56c9be44a436c4a2.jsp, 64652883d9de3299.jsp, 7c0a0a34c9d8d53b.jsp, ec6ba805a076e709.jsp. Hunt the pattern, not the list, since new shells appear under new names.
Detection priority
Rank by what each layer actually sees.
The web-tier path rule catches the generic shell and any copycat, works on default logging, and supports a free retroactive hunt. Deploy first. The header rule catches the custom implant at every operator interaction, but requires the LogFormat change to be in place, so it protects you going forward rather than backward. Sysmon EVID 11 catches both families at the single moment either touches disk, and is the only endpoint detection that fires against the custom implant at all. Sysmon EVID 1 with a JVM parent anchor catches the generic shell immediately and the custom implant only if the operator uses the J class loader to deliver tooling that shells out.
That last point is the one to sit with. Against the custom implant, process-creation telemetry is silent by design. If your Windchill hosts are quiet, that is not evidence of anything. Go look at the codebase directory.
References
Primary threat intelligence
- ReliaQuest Threat Research Team, Clop Returns with Custom Implant in Mass-Extortion Campaign, 18 August 2026. https://reliaquest.com/blog/clop-returns-with-custom-implant-in-mass-extortion-campaign/ Source for the implant's imported Windchill classes, the
gscredential function, theFlst1vault enumeration class, theCldrclass loader, GZIP response encoding, and the campaign IOC set. - Lawrence Abrams, Clop created custom web shell for Windchill data theft attacks, BleepingComputer, 18 August 2026. https://www.bleepingcomputer.com/news/security/clop-created-custom-web-shell-for-windchill-data-theft-attacks/ Source for the eight-character
X-windchill-reqcommand protocol, the full command table, and the vault tablesApplicationData,FVITEM,FVMOUNT, andMasteredOnReplicaItem. - Brandon Parsons et al., Cl0p Exploitation of PTC Windchill & FlexPLM (CVE-2026-12569), Ransom-ISAC in collaboration with eCrime.ch and DEFUSED, 22 July 2026, updated 14 August 2026. https://ransom-isac.org/blog/clop-windchill-flexplm-exploitation/ Source for the exploit chain description, the
[0-9a-f]{16}.jspand[0-9a-f]{6}.jspnaming patterns, thedpr_<8 hex>.jspconvention, the?cmd=invocation, the WSDL recon fingerprint with 4045-byte response, observed shell filenames,flst.txt, and the network and hash indicators. - Sergiu Gatlan, Clop ransomware targets Windchill, FlexPLM in data theft attacks, BleepingComputer, July 2026. https://www.bleepingcomputer.com/news/security/clop-ransomware-targets-windchill-flexplm-in-data-theft-attacks/
- Ionut Arghire, PTC Windchill Vulnerability Exploited in Ransomware Campaign, SecurityWeek, July 2026. https://www.securityweek.com/ptc-windchill-vulnerability-exploited-in-ransomware-campaign/ Source for the CVSS 9.3 scoring and the patch-to-exploitation timeline.
- Zeljka Zorz, JSP webshells being dropped on unpatched PTC Windchill instances, Help Net Security, 29 June 2026. https://www.helpnetsecurity.com/2026/06/29/ptc-windchill-cve-2026-12569-exploited/ Source for the German BSI notification campaign and the prior CVE-2026-4681 Windchill flaw.
- Cl0p Affiliates Target Internet-Exposed PTC Windchill and FlexPLM with Unauthenticated RCE, The Hacker News, July 2026. https://thehackernews.com/2026/07/cl0p-affiliates-target-internet-exposed.html Source for Censys internet exposure figures.
Vendor advisories and vulnerability data
- PTC, Remote Code Execution Vulnerability in PTC's Windchill and FlexPLM Solutions. https://www.ptc.com/en/about/trust-center/advisory-center/active-advisories/windchill-flexplm-rce-vulnerability
- PTC Support Article CS473270 (remediation steps and full indicator set, including 44 MD5 and 2 SHA-1 hashes). https://www.ptc.com/en/support/article/CS473270
- NVD, CVE-2026-12569. https://nvd.nist.gov/vuln/detail/CVE-2026-12569
- CISA Known Exploited Vulnerabilities Catalog. https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-12569
Windchill architecture
- PTC, Windchill Runtime Architectural Overview. https://support.ptc.com/help/windchill/plus/r12.0.2.0/en/Windchill_Help_Center/WCArchOview.html Source for the statement that Windchill always installs and uses the Embedded Servlet Engine regardless of front-end web server.
- PTC, Server Software Components. https://support.ptc.com/help/windchill/cloud/r12.0.2.0/en/Windchill_Help_Center/WCRuntimeEnvironment_ServerSoftwareComponent.html Source for the Server Manager and Method Server process relationship, including the single-server-manager-per-host model.
- PTC Support Article CS101232 (Tomcat embedded in the Method Server as of Windchill 10.0, AJP load balancing from Apache). https://www.ptc.com/en/support/article/CS101232
- PTC Support Article CS109967 (
catalina.baseinstance path format). https://www.ptc.com/en/support/article/CS109967 - PTC Support Article CS17799 (running Apache, Tomcat, WindchillDS, and Windchill as Windows services). https://www.ptc.com/en/support/article/CS17799
- PTC Support Article CS196783 (software matrices, supported operating systems). https://www.ptc.com/en/support/article/CS196783
Tooling and configuration
- Microsoft Sysinternals, Sysmon. https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon
- Microsoft Sysinternals, Sysmon for Linux. https://github.com/Sysinternals/SysmonForLinux
- Sysmon for Linux installation guide. https://github.com/Sysinternals/SysmonForLinux/blob/main/INSTALL.md
- FT-Sysmon-Config (Windows). https://github.com/fluffybunnies-h4x/FT-Sysmon-Config
- FT-Linux-Sysmon-Config. https://github.com/fluffybunnies-h4x/FT-Linux-Sysmon-Config
- SwiftOnSecurity, sysmon-config (upstream of the Windows config above). https://github.com/SwiftOnSecurity/sysmon-config
- Apache HTTP Server, mod_log_config. https://httpd.apache.org/docs/2.4/mod/mod_log_config.html Reference for the
%{Header}irequest header logging syntax used in theLogFormatdirective above.
MITRE ATT&CK
| Technique | ID |
|---|---|
| Exploit Public-Facing Application | T1190 |
| Server Software Component: Web Shell | T1505/003 |
| Credentials from Password Stores | T1555 |
| Unsecured Credentials: Credentials in Files | T1552/001 |
| System Owner/User Discovery | T1033 |
| System Information Discovery | T1082 |
| File and Directory Discovery | T1083 |
| Archive Collected Data | T1560 |
| Exfiltration Over Web Service | T1567 |
| Reflective Code Loading | T1620 |
| Indicator Removal: File Deletion | T1070/004 |
Sysmon configs referenced above are maintained at FT-Sysmon-Config and FT-Linux-Sysmon-Config.
