LoFP LoFP / requests to `gw/run` or randomly named `dpr_<8 hex>.jsp` files with `c=` or `p=` parameters should not be expected during normal windchill operation. validate whether red-team testing, vulnerability scanning, or incident response replay generated the activity before closing as benign.

Techniques

Sample rules

PTC Windchill Gateway Command Execution

Description

This analytic detects Windchill MethodServer log4j events showing suspicious c= command execution or p= file read parameters sent to Windchill gateway paths associated with CVE-2026-4681 exploitation. PTC identifies run?c=, run?p=, .jsp?c=, and .jsp?p= request patterns as indicators to monitor during Windchill and FlexPLM exploitation response. Successful activity may allow an unauthenticated attacker to execute operating system commands or read files through a weaponized gateway or JSP component.

Detection logic

`windchill_log4j`
("WindchillGW/GW/run" OR "WindchillAuthGW/GW/run" OR "/GW/run?" OR "run?c=" OR "run?p=" OR ".jsp?c=" OR ".jsp?p=" OR "dpr_")

| rex field=_raw "^(?:[^:\r\n]+:)?(?<log_ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d{3})\s+(?<log_level>\w+)\s+\[(?<thread>[^\]]+)\]\s+(?<logger>\S+)\s+-\s+(?<payload>.*)$"

| search logger IN ("wt.servlet.ServletRequestMonitor.request", "wt.method.MethodContextMonitor.contexts.servletRequest")

| rex field=payload "^(?<event_ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3})\s+(?<event_tz>[+\-]\d{4}),\s+(?<rest>.*)$"

| eval parts=split(rest,", ")

| eval event_type=case(logger="wt.servlet.ServletRequestMonitor.request","servlet_request",logger="wt.method.MethodContextMonitor.contexts.servletRequest","method_context_servlet_request",true(),"other")

| eval src_ip=case(event_type="servlet_request",mvindex(parts,2),event_type="method_context_servlet_request",mvindex(parts,5))

| eval uri_path=case(event_type="servlet_request",mvindex(parts,3),event_type="method_context_servlet_request",mvindex(parts,8))

| eval query_string=if(event_type="servlet_request",mvindex(parts,4),null())

| eval http_method=if(event_type="servlet_request",mvindex(parts,5),null())

| eval status=if(event_type="servlet_request",tonumber(mvindex(parts,6)),null())

| rex field=uri_path "^(?<uri_only>[^\?]+)(?:\?(?<uri_query>.*))?$"

| eval query_string=if(query_string="-",null(),query_string)

| eval query_string=coalesce(query_string,uri_query)

| rex field=query_string "(?i)(?:^
|&)(?<query_param>[cp])=(?<query_value>[^&]*)"

| eval query_param=lower(query_param), query_value=urldecode(replace(query_value,"\+","%20"))

| where isnotnull(uri_only) AND isnotnull(query_param)

| where (match(uri_only,"(?i)(^
|/)GW/run$") OR match(uri_only,"(?i)/servlet/(WindchillGW
|WindchillAuthGW)/GW/run$") OR match(uri_only,"(?i)(^
|/)dpr_[0-9a-f]{8}\.jsp$")) AND (query_param="c" OR query_param="p")

| where NOT (query_param="c" AND match(query_value,"(?i)^echo(\s
|20)+GW_READY_OK$"))

| eval activity=case(query_param="c","command_execution_parameter",query_param="p","file_read_parameter",true(),"unknown")

| eval src=src_ip


| stats count min(_time) as firstTime
              max(_time) as lastTime
              values(log_level) as log_level
              values(logger) as logger
              values(http_method) as http_method
              values(status) as status
              values(uri_only) as uri_path
              values(query_string) as query_string
  by src activity query_param query_value


| `security_content_ctime(firstTime)`

| `security_content_ctime(lastTime)`

| `ptc_windchill_gateway_command_execution_filter`