PivotC2 — FortiGate CAPWAP RCE (CVE-2025-25249) Node.js RAT
cw_acd CAPWAP control daemon, deploying the custom PivotC2 Node.js post-exploitation framework.Executive Summary
Threat actors — assessed with high confidence by SOCRadar's Threat Research Unit (STRU) to be a Russian-speaking, financially motivated cybercrime group — are actively exploiting CVE-2025-25249, a CVSS 9.8 heap-based buffer overflow in the cw_acd daemon that implements the CAPWAP wireless-controller protocol on FortiOS and FortiSwitchManager. The flaw lets an unauthenticated remote attacker send a malformed CAPWAP packet to UDP port 5246 (observed up to 5249) and obtain arbitrary code execution on the appliance. The campaign has scanned more than 30,000 internet-exposed FortiGate IPs and confirmed 178 successful compromises since at least July 2026, concentrated in the United States, followed by Chile, Colombia, and the United Kingdom. Two confirmed full-network intrusions against U.S. organizations involved lateral movement, Active Directory enumeration, browser credential theft, RDP abuse, and exfiltration of Microsoft Exchange mailbox data to Wasabi cloud object storage.
Post-exploitation, attackers use a custom exploit binary (fortirun.bin) to open a reverse shell, execute a Base64-encoded JavaScript stager through FortiGate's embedded Node.js runtime, retrieve and XOR-decrypt (key "pivot") a second-stage payload, and persist it at /tmp/.i.js as a detached background process. The resulting implant — PivotC2, observed at version 0.2.3 — is a purpose-built, SSH-like remote access framework with interactive shell access, file transfer, SOCKS5/HTTP proxying, port forwarding, DNS lookups, process enumeration, CIDR-based internal network scanning ("auto-mode"), and automated decryption of FortiGate's AES-256-CBC / AES-128-GCM encrypted credential store — yielding VPN pre-shared keys, SSL-VPN credentials, wireless passwords, LDAP bind secrets, and local admin passwords in plaintext. Command and control runs over outbound TLS to 146.103.99.177:8443 and a second address, 46.151.29.58.
/tmp/.i.js process — is invisible to Falcon by design. This pack, consistent with the team's existing FortiBleed-CVE-2026-24858-Hunt.html pattern for appliance-only threats, does not claim on-appliance detection coverage. Its entire detective value is downstream: credentials harvested from a compromised FortiGate being reused elsewhere in the environment, lateral movement and internal scanning as observed from the other Falcon-covered endpoints PivotC2 probes, outbound connections from Falcon-covered hosts to the named C2 infrastructure, and identity/AD telemetry for suspicious use of admin/LDAP credentials. See §15 for the full honesty accounting of what is and is not covered.
Source Review & Web Hunter Notes
| Tier | Source | Key Finding | Carry Forward |
|---|---|---|---|
| Tier 2 | CyberSecurityNews — "Hackers Actively Exploiting FortiGate Firewalls to Deploy Custom Node.js Malware" (Sep 8, 2026) | Full attack chain, PivotC2 v0.2.3, 30k scanned / 178 compromised, attribution, patch guidance, /tmp/.i.js, fortirun.bin | Yes |
| Tier 2 | GBHackers — "Hackers Exploit Critical FortiGate Flaw to Deploy AI-Assisted PivotC2 RAT" (Sep 9, 2026) | C2 IPs (146.103.99.177:8443, 46.151.29.58), XOR key "pivot", fsv_sync.dat, credential types harvested, AD enumeration/RDP/Tor/Wasabi detail | Yes |
| Tier 1 | CISA Known Exploited Vulnerabilities catalog (live JSON feed) | Confirms CVE-2025-25249 KEV listing, official dateAdded, CWE-122/CWE-787, FortiSASE also listed as affected product, BOD 26-04 due date | Yes |
| — unreachable — | SOCRadar — "CVE-2025-25249 (PivotC2): FortiGate RAT Exploited in the Wild" (primary research) | Origin report cited by both saved sources; not independently fetchable (see below) | Partial — via citing outlets only |
PivotC2-FortiGate-CVE-2025-25249-Hunt-sources/00-fetch-notes.txt.
Date discrepancy flagged for provenance gate. The task brief stated CVE-2025-25249 was added to KEV "in the 2026-09-02 batch." The live CISA KEV JSON feed (saved as source 03) records dateAdded: 2026-09-09 for this CVE. This pack uses the verified date (2026-09-09) throughout, since only that value has a traceable saved snapshot.
Confidence assessment: High confidence in the attack chain, C2 infrastructure, and credential-harvesting mechanics — corroborated across two independent outlets both citing the same primary researcher, plus an independently verified KEV listing. Medium confidence in exact scope numbers (178 devices, 30,000 scanned) — single-sourced to SOCRadar via citation, not independently corroborated. No file hashes for fortirun.bin, the PivotC2 implant, or /tmp/.i.js were published in any reachable source; none are shipped as IOCs in this pack. Intel is perishable — this is an active, still-scanning campaign as of the source publish dates (Sep 8–9, 2026); C2 infrastructure should be expected to rotate.
Hunt Brief & Attack Chain
| # | Step | Detail | Falcon-Visible? | Hunt Angle |
|---|---|---|---|---|
| 1 | Exploitation | Malformed CAPWAP packets to UDP 5246 (–5249) trigger the cw_acd heap overflow; fortirun.bin (Bash/Python-orchestrated) opens a reverse shell. | No — appliance-only | None (Falcon); see §7 native FortiOS CLI checks |
| 2 | Stager | Reverse shell runs a Base64-encoded JavaScript stager via FortiGate's embedded Node.js runtime. | No — appliance-only | None (Falcon) |
| 3 | Payload retrieval & persistence | Stager fetches an encrypted 2nd-stage payload from C2, XOR-decrypts with key "pivot", writes it to /tmp/.i.js, runs it detached (survives parent process exit). fsv_sync.dat referenced as a harvested device-secret file. | No — appliance-only | None (Falcon); §7 CLI file check; §8 Q9 opportunistic net-catch |
| 4 | C2 & credential harvest | PivotC2 v0.2.3 opens outbound TLS to 146.103.99.177:8443 / 46.151.29.58; decrypts FortiGate's AES-256-CBC/AES-128-GCM credential store (VPN PSK, SSL-VPN, wireless, LDAP bind, admin). | No — appliance-only | None (Falcon) |
| 5 | Internal recon / auto-mode | Five-stage auto-mode: harvest config → decrypt creds → extract subnets → CIDR port-scan → stage for lateral movement. | Partial — via targets | §8 Q4 (auth fan-out proxy for scan activity) |
| 6 | Credential reuse / lateral movement | Confirmed intrusions show AD enumeration, browser credential theft, RDP enablement, reverse SSH relays, Tor-based proxying. | Yes — downstream | §8 Q2, Q3, Q4, Q5, Q7, Q8 |
| 7 | Exfiltration | Exchange mailbox (.pst) and harvested configuration data exfiltrated to Wasabi cloud object storage. | Partial — generic signal | §8 Q6 |
Consolidated IOC Table
| Type | Value | Confidence | Action | Context | Source |
|---|---|---|---|---|---|
| C2 IP:Port | 146.103.99.177:8443 | High | Block / Alert | PivotC2 C2; observed path /0c5b76709523 | GBHackers |
| C2 IP | 46.151.29.58 | High | Block / Alert | Secondary PivotC2 C2 (no port published) | GBHackers |
| File path (appliance) | /tmp/.i.js | High | Hunt (FortiOS CLI) / opportunistic Falcon net-catch | Persisted, decrypted 2nd-stage implant | CyberSecurityNews, GBHackers |
| File path (appliance) | fsv_sync.dat | Medium | Hunt (FortiOS CLI) | Device-specific harvested secret/config artifact | GBHackers |
| Binary name (appliance) | fortirun.bin | High | Hunt (FortiOS CLI) | Exploit/orchestration binary used against the CAPWAP overflow | CyberSecurityNews, GBHackers |
| Crypto material | XOR key "pivot" | High | Reference only (decryption aid for IR/forensics) | Decrypts the 2nd-stage payload in transit | GBHackers |
| Malware version | PivotC2 v0.2.3 | High | Reference | Version string recovered from analyzed samples | CyberSecurityNews |
| Exfil destination (generic) | *.wasabisys.com | Medium | Investigate (context-dependent) | Legitimate cloud storage service abused for exfil — not a PivotC2-exclusive indicator | CyberSecurityNews, GBHackers |
| CVE | CVE-2025-25249 | High | Patch | CVSS 9.8, CWE-122/CWE-787, cw_acd CAPWAP heap overflow | CISA KEV, CyberSecurityNews, GBHackers |
| Protocol/Port | UDP 5246 (–5249) | High | Restrict exposure | CAPWAP Control service | CyberSecurityNews, GBHackers |
fortirun.bin, the PivotC2 implant, or /tmp/.i.js. None are shipped here. If a hash later surfaces (e.g., from an incident where the implant is recovered off-box), add it to this table and to §10 before using it in a detection — do not fabricate a placeholder hash.
Affected Surface & Telemetry Matrix
| Platform / Surface | Required Telemetry | Priority | Gap Risk |
|---|---|---|---|
| FortiOS / FortiSwitchManager appliance | None available to Falcon (no sensor on locked firmware) | Critical (patch/config only) | High — zero EDR visibility |
| Falcon-covered endpoints/servers — network telemetry | NetworkConnectIP4, DnsRequest | High | Low — standard sensor coverage |
| Falcon-covered endpoints/servers — identity/AD telemetry | UserLogon, ActiveDirectoryAuthentication-family Identity Protection events | High | Medium — depends on Identity Protection module + AD integration |
| Falcon-covered endpoints — registry/process (RDP enablement, browser cred access) | RegGenericValueUpdate, FileOpenInfo, ProcessRollup2 | Medium | Low |
| FortiGate SSL-VPN / VPN auth logs (native) | FortiOS syslog → SIEM (not a Falcon-native event type) | High | High — only covered if Fortinet syslog is separately ingested into Falcon Next-Gen SIEM; not assumed present in this pack's CQL |
ATT&CK Mapping
| Tactic | Technique ID | Technique Name | Observed Behavior | Falcon-Visible |
|---|---|---|---|---|
| Initial Access | T1190 | Exploit Public-Facing Application | CAPWAP heap overflow against cw_acd via fortirun.bin | Gap |
| Execution | T1059.007 | Command & Scripting Interpreter: JavaScript | Base64 JS stager executed through embedded Node.js | Gap |
| Defense Evasion | T1027 | Obfuscated Files or Information | Base64 + XOR ("pivot") encoded/encrypted 2nd-stage payload | Gap |
| Command & Control | T1071.001 | Application Layer Protocol: Web Protocols | Outbound TLS to 146.103.99.177:8443 / 46.151.29.58 | Yes (Q1) |
| Command & Control | T1090 | Proxy (SOCKS5/HTTP tunneling) | PivotC2 SOCKS5/HTTP proxy + port-forwarding channels | Gap — no reliable EDR signal |
| Credential Access | T1552.001 | Unsecured Credentials: Credentials In Files | Decryption of FortiGate ENC credential fields (AES-256-CBC/AES-128-GCM) | Gap — appliance-only |
| Credential Access | T1555.003 | Credentials from Web Browsers | Browser credential theft during confirmed intrusions | Partial (Q8, generic/low-conf) |
| Discovery | T1046 | Network Service Scanning | Auto-mode CIDR-based internal port scanning | Partial — via auth fan-out proxy (Q4) |
| Discovery | T1087.002 / T1069.002 | Account / Permission Groups Discovery: Domain | Active Directory enumeration observed in confirmed intrusions | Partial (Q7, low-med conf) |
| Lateral Movement | T1021.001 | Remote Services: RDP | RDP enablement / abuse observed in confirmed intrusions | Yes (Q5) |
| Lateral Movement / Persistence | T1078.002 | Valid Accounts: Domain Accounts | Reuse of harvested VPN/SSL-VPN/LDAP/admin credentials | Yes (Q2, Q3, Q4) |
| Exfiltration | T1567.002 | Exfiltration to Cloud Storage | Exchange mailbox / config data exfil to Wasabi | Partial (Q6, generic) |
Native Audit-Log Hunts (Non-CQL, FortiOS CLI)
These checks run directly on the FortiGate appliance via the CLI or a documented diagnose command — they are the only way to confirm on-appliance compromise, since Falcon has no visibility here. Run against any FortiOS 6.4–7.6.3 / FortiSwitchManager 7.0.x–7.2.x device with CAPWAP-management exposure until patched.
! 1. Check firmware version against fixed releases (7.6.4 / 7.4.9 / 7.2.12 / 7.0.18+) get system status ! 2. Look for the persisted PivotC2 implant and companion artifact diagnose debug shell ls -la /tmp/.i.js ls -la /tmp/fsv_sync.dat ! 3. Check for the exploit/orchestration binary anywhere it may have been staged find / -iname "fortirun.bin" 2>/dev/null ! 4. Enumerate running Node.js processes (legitimate FortiGate management ! features also use Node.js — flag anything NOT tied to expected GUI/API use) diagnose sys process list | grep -i node ! 5. Check active/recent sessions for connections to the known C2 addresses diagnose sys session list | grep -E "146\.103\.99\.177|46\.151\.29\.58" ! 6. Confirm current CAPWAP/wireless-controller exposure on WAN-facing interfaces show system interface diagnose sys tcp/udp | grep 5246
CrowdStrike LogScale CQL Hunt Queries
// HUNT: Outbound Connection to Named PivotC2 C2 Infrastructure // MITRE: T1071.001 (Application Layer Protocol: Web Protocols) // CONF: high // FP: low // COST: low // REQUIRES: NetworkConnectIP4 (Falcon sensor on any endpoint/server reachable to the internet) // FALSE POSITIVES: none expected -- these are attacker-controlled IPs cited by CyberSecurityNews/GBHackers reporting on this campaign; any hit is a true positive requiring immediate triage. // TUNING: if either IP is later reused by a shared hosting provider for unrelated traffic, pin the match to RemotePort=8443 for 146.103.99.177 only, or expire this row per the IOC table review date. #event_simpleName=/^NetworkConnectIP4$/ | RemoteAddressIP4=in(["146.103.99.177", "46.151.29.58"]) | table([@timestamp, aid, ComputerName, LocalAddressIP4, RemoteAddressIP4, RemotePort, ContextProcessId]) | sort(@timestamp, order=desc)
// HUNT: Admin / Service / LDAP-Bind Account Logons, Grouped by Distinct Source IP for Analyst Review // MITRE: T1078.002 (Valid Accounts: Domain Accounts), T1133 (External Remote Services) // CONF: medium // FP: medium // COST: medium // REQUIRES: UserLogon (Falcon Identity Protection / AD-integrated telemetry) for accounts matching admin/svc/ldap naming // FALSE POSITIVES: legitimate travel, new VPN/NAT egress IP, freshly onboarded admin, PAM credential rotation immediately followed by first login. // TUNING: narrow UserName to your actual FortiGate LDAP-bind and local-admin account names once identified from the compromised device's config; exclude known corporate VPN/NAT/PAM egress CIDRs. // WARNING Field unverified -- UserLogon field coverage and RemoteAddressIP4 population for domain logons varies by Falcon Identity Protection deployment; validate in tenant before promoting to IOA. #event_simpleName=/^UserLogon$/ | UserName=/(adm|admin|svc|ldap|bind)/i | groupBy([UserName], function=([collect([RemoteAddressIP4], limit=50), collect([@timestamp], limit=50), count(as=LogonCount)])) | sort(LogonCount, order=desc)
// HUNT: Same Privileged Account Authenticating From Multiple Distinct Source IPs Within a Short Window // MITRE: T1078.002 (Valid Accounts: Domain Accounts) // CONF: medium // FP: medium // COST: medium // REQUIRES: UserLogon (AD/Identity Protection telemetry) for privileged/admin/LDAP-bind accounts // FALSE POSITIVES: split-tunnel VPN clients hopping egress IPs, mobile carrier IP rotation, load-balanced SSO front-ends. // TUNING: pair with geo-IP or Falcon Identity Protection risk-score enrichment to turn "distinct IP count" into true impossible-travel (incompatible geolocations, sub-hour delta); this query surfaces the raw candidate set for that enrichment step. // WARNING Field unverified -- validate UserLogon field coverage for your identity sources in tenant. #event_simpleName=/^UserLogon$/ | UserName=/(adm|admin|svc|ldap|bind)/i | bucket(span=1h, field=@timestamp, as=hour) | groupBy([UserName, hour], function=([collect([RemoteAddressIP4], limit=20), countDistinct(RemoteAddressIP4, as=DistinctIPs)])) | DistinctIPs>=2 | sort(DistinctIPs, order=desc)
// HUNT: Single Internal Source IP Authenticating to an Unusually High Number of Distinct Falcon-Covered Hosts // MITRE: T1078 (Valid Accounts), T1021 (Remote Services), T1046 (Network Service Scanning -- adjacent) // CONF: medium-high // FP: medium // COST: medium // REQUIRES: UserLogon (network/interactive logon telemetry) on Falcon-covered endpoints/servers // FALSE POSITIVES: patch/deployment tooling (SCCM, Ansible, Intune), IT admin mass maintenance, jump-box/bastion hosts by design. // TUNING: exclude known management/deployment/bastion source IPs; if a specific FortiGate's internal interface IP is confirmed compromised (via the appliance-side checks in Section 7), pin this query to that exact source IP for high-confidence lateral-movement confirmation. // NOTE: this is the practical stand-in for detecting PivotC2's internal "auto-mode" CIDR scan. Raw port-scan telemetry from EDR alone is a known blind spot for inbound connection attempts (see Section 15); authenticated-access fan-out is the more reliably instrumented downstream signal. #event_simpleName=/^UserLogon$/ | LogonType=in(["3","10"]) | groupBy([RemoteAddressIP4], function=([countDistinct(aid, as=DistinctHostsTargeted), collect([ComputerName, UserName], limit=50)])) | DistinctHostsTargeted>=8 | sort(DistinctHostsTargeted, order=desc)
// HUNT: Terminal Services (RDP) Enabled or Used Shortly After Suspected Credential-Reuse Logon // MITRE: T1021.001 (Remote Desktop Protocol), T1112 (Modify Registry) // CONF: medium // FP: medium // COST: low // REQUIRES: RegGenericValueUpdate (registry writes) on Falcon-covered endpoints/servers // FALSE POSITIVES: legitimate IT enabling RDP for support, RMM tooling, approved change requests. // TUNING: correlate hits against Q2/Q4 output (same source IP / same recently-first-seen account) before triage; exclude your RMM/helpdesk service accounts. #event_simpleName=/^RegGenericValueUpdate$/ | RegObjectName=/Terminal Server.*fDenyTSConnections/i | RegValueName=/fDenyTSConnections/i | table([@timestamp, aid, ComputerName, RegObjectName, RegValueName, UserName]) | sort(@timestamp, order=desc)
// HUNT: Outbound DNS Resolution of Wasabi Cloud Object Storage From Falcon-Covered Hosts // MITRE: T1567.002 (Exfiltration to Cloud Storage) // CONF: medium // FP: high // COST: low // REQUIRES: DnsRequest on Falcon-covered endpoints/servers // FALSE POSITIVES: organizations that legitimately use Wasabi for backup/archival -- if Wasabi is an approved vendor, scope this query to hosts/accounts NOT on the approved backup-server allowlist. // TUNING: exclude your sanctioned backup/archival server(s). This is a GENERIC cloud-storage-abuse detector, not a PivotC2-specific IOC -- no PivotC2-attributed Wasabi bucket/endpoint was published in the sourced reporting (see Section 4), so treat any hit as "investigate for data staging/exfil," not a confirmed PivotC2 hit. #event_simpleName=/^DnsRequest$/ | DomainName=/\.wasabisys\.com$/i | table([@timestamp, aid, ComputerName, DomainName, ContextProcessId]) | sort(@timestamp, order=desc)
// HUNT: High-Volume AD Authentication / Bind Activity From a Non-Standard Source Following Suspected FortiGate Compromise // MITRE: T1087.002 (Account Discovery: Domain Account), T1069.002 (Permission Groups Discovery: Domain Groups) // CONF: low-medium // FP: high // COST: medium // REQUIRES: ActiveDirectoryAuthentication (Falcon Identity Protection AD authentication/bind telemetry; module-dependent -- not all tenants ingest this) // FALSE POSITIVES: legitimate directory-aware applications (SSO, MDM, PAM, monitoring) performing normal AD authentication/bind activity -- this event type is naturally high-volume/noisy. // TUNING: scope to accounts matching the LDAP-bind naming pattern harvested by PivotC2, or to source IPs already flagged by Q2/Q4; do not run unscoped in production without an allowlist of known directory-consuming applications. // NOTE: corrected from an earlier draft that referenced non-existent event names (AuthActivityAuditData, LdapSearch) -- ActiveDirectoryAuthentication is a real Falcon Identity Protection event; confirm it is licensed/ingested in your tenant before relying on this query. #event_simpleName=/^ActiveDirectoryAuthentication$/ | SamAccountName=/(ldap|bind|svc)/i | groupBy([SamAccountName, SourceEndpointHostName], function=([count(as=QueryCount)])) | QueryCount>=50 | sort(QueryCount, order=desc)
// HUNT: Process Access to Browser Credential Stores (Chrome/Edge Login Data, Firefox logins.json) // MITRE: T1555.003 (Credentials from Web Browsers) // CONF: low // FP: high // COST: low // REQUIRES: FileOpenInfo / ProcessRollup2 on Falcon-covered endpoints // FALSE POSITIVES: password managers, browser sync/backup tools, forensic/IT tooling, the browser itself operating normally. // TUNING: this is a GENERIC credential-theft behavioral hunt, not unique to PivotC2 -- CyberSecurityNews/GBHackers describe "browser credential theft" as part of the confirmed full-network-intrusion cases but do not name a specific stealer tool or technique. Use as a low-priority investigate-only supplement, not a promoted detection. #event_simpleName=/^FileOpenInfo$/ | TargetFileName=/(Login Data|logins\.json|Cookies)$/i | ImageFileName!=/\\(chrome|msedge|firefox|brave|opera)\.exe$/i | table([@timestamp, aid, ComputerName, ImageFileName, TargetFileName, UserName]) | sort(@timestamp, order=desc)
// HUNT: PivotC2 Implant Filename Observed on Any Falcon-Covered Host (Forensic Copy / Analyst Workstation / Jump Box) // MITRE: T1105 (Ingress Tool Transfer) -- adjacent, opportunistic // CONF: low // FP: low // COST: low // REQUIRES: PeFileWritten / NewExecutableWritten on Falcon-covered endpoints // FALSE POSITIVES: none expected under normal operation -- but very low true-positive probability too, since PivotC2 runs entirely on the FortiGate appliance (no Falcon sensor there) and only reaches a Falcon-covered host if an analyst manually copies the implant off-box for forensic review, or an internal jump box was used as a mount/staging point. // TUNING: none needed; this is a narrow, opportunistic net-catch, not a primary detection. Do not rely on this as your main PivotC2 hunt -- see Section 15 for why on-appliance artifacts are not natively visible to Falcon. // NOTE: corrected from an earlier draft that referenced non-existent event names (FileCreateInfo, FileWritten) -- PeFileWritten / NewExecutableWritten are real Falcon file-write events. #event_simpleName=/^(PeFileWritten|NewExecutableWritten)$/ | FileName=/^\.i\.js$/i | table([@timestamp, aid, ComputerName, FileName, FilePath, ImageFileName]) | sort(@timestamp, order=desc)
CrowdStrike Custom IOA Recommendations
Two queries are promotable to scheduled detections / Custom IOAs today; the remainder stay investigate-only pending tenant-specific field validation and FP tuning (see badges in §8).
IOA Candidate 1 — Q1: PivotC2 C2 Communication
| Field | Value |
|---|---|
| Scheduled Search name | DETECT — PivotC2 C2 Communication (CVE-2025-25249) |
| Description | Fires when any Falcon-covered host connects to 146.103.99.177:8443 or 46.151.29.58, the two IPs publicly attributed to the PivotC2 FortiGate RAT campaign. A hit indicates a Falcon-covered asset is talking to confirmed attacker infrastructure. |
| Alert email subject | [CRITICAL] Detection: PivotC2 C2 Communication — Outbound Connection to Known Attacker IP |
| Alert email body | A Falcon-covered host (ComputerName / aid) established a network connection to RemoteAddressIP4:RemotePort, an IP address publicly attributed to the PivotC2 post-exploitation framework associated with active exploitation of CVE-2025-25249 (FortiGate CAPWAP RCE). This may indicate the host is directly compromised, or is being used as a pivot/tunnel endpoint by an attacker who has already compromised an internal FortiGate appliance. Immediate action: isolate the host from the network pending triage, capture the parent process tree for the connecting process, and check whether the organization has an internet-facing FortiGate/FortiSwitchManager running an unpatched version (FortiOS < 7.6.4/7.4.9/7.2.12/7.0.18 or FortiSwitchManager < 7.2.7/7.0.6). Escalate to IR lead if the host holds domain admin, LDAP-bind, or VPN gateway credentials. |
| Triage checklist |
1. Confirm the destination IP/port against the IOC table (§4) — verify it is not an internal NAT artifact. 2. Pull the full process tree for the connecting process (parent, command line, signed/unsigned). 3. Check DNS history on the host for any resolution activity involving the C2 IP. 4. Identify which FortiGate/FortiSwitchManager appliances in the environment are internet-facing and check their patch level. 5. Run §7 native FortiOS CLI checks against any unpatched appliance found. 6. Pivot with Q2/Q3/Q4 for any credential-reuse or lateral-movement activity tied to the same host or account. 7. If confirmed malicious, isolate host, rotate any credentials it held, and open a formal IR case. 8. Notify network team to block the C2 IPs at the perimeter. |
| Pivot queries | Host-scoped: add | ComputerName="<host>" to Q1 and run against 30 days. Environment-wide: run Q2/Q3/Q4 unscoped to check for any other credential-reuse or lateral-movement activity in the same time window. |
| IOC blocklist entries (Custom IOC ingestion) | type: ipv4, value: 146.103.99.177, action: watch/detect, severity: high, description: "PivotC2 C2 (CVE-2025-25249 campaign)" type: ipv4, value: 46.151.29.58, action: watch/detect, severity: high, description: "PivotC2 secondary C2 (CVE-2025-25249 campaign)" |
IOA Candidate 2 — Q4: Single-Source-IP Authentication Fan-Out
| Field | Value |
|---|---|
| Scheduled Search name | DETECT — Single Source IP Authenticating to Abnormally Many Hosts |
| Description | Fires when one source IP authenticates to 8+ distinct Falcon-covered hosts within the search window — the downstream signature of PivotC2's internal auto-mode scan-then-credential-reuse behavior, or any other mass lateral-movement activity. |
| Alert email subject | [HIGH] Detection: Authentication Fan-Out From a Single Source IP — Possible Lateral Movement |
| Alert email body | Source IP RemoteAddressIP4 authenticated to DistinctHostsTargeted distinct Falcon-covered hosts in the search window using account(s) UserName. This pattern matches mass lateral movement following credential compromise, and is the closest downstream signal available for PivotC2's internal CIDR auto-scan (which itself runs on an appliance with no Falcon visibility). Immediate action: identify whether the source IP belongs to a known jump box/RMM tool (expected) or an unexpected host — if unexpected, treat as an active intrusion, isolate the source host, and force-rotate any accounts observed. |
| Triage checklist |
1. Identify the source IP — internal host, VPN concentrator, or a FortiGate's internal interface? 2. Cross-reference against your known RMM/deployment/bastion IP allowlist. 3. List every account and host touched by this source IP in the window. 4. Check whether any FortiGate/FortiSwitchManager appliance owns this internal IP and is unpatched. 5. Run Q2/Q3 for the same accounts to check for prior anomalous logons. 6. Run Q5 for RDP-enablement activity on any targeted host. 7. If confirmed unauthorized, isolate the source host and rotate all touched credentials. 8. Escalate to IR — this pattern often precedes ransomware/data-theft staging. |
| Pivot queries | Host-scoped: | RemoteAddressIP4="<source-ip>" against 30 days. Environment-wide: cross-reference the account list against Q7 (AD enumeration) in the same window. |
Investigate-Only Queries (Q2, Q3, Q5, Q6, Q7, Q8, Q9)
| Query | Hunt Description | Investigation Notes |
|---|---|---|
| Q2 | Surfaces admin/service/LDAP-bind logons grouped by user for manual new-IP review. | Not IOA-ready — needs a 30-day baseline join or UEBA input to auto-flag "new" IPs; currently a manual-review aid. |
| Q3 | Surfaces privileged accounts authenticating from 2+ distinct IPs within an hour. | Needs geo-IP enrichment to become true impossible-travel; pair with Identity Protection risk scoring if licensed. |
| Q5 | Flags RDP enablement via registry. | High legitimate-IT-activity rate; correlate with Q2/Q4 before triage. |
| Q6 | Flags DNS resolution of Wasabi storage. | Will be noisy if Wasabi is an approved vendor; scope to non-backup hosts before any promotion. |
| Q7 | Flags high-volume AD authentication/bind activity for accounts matching harvested-credential naming patterns. | Real Falcon Identity Protection event (ActiveDirectoryAuthentication), but module/license-dependent; validate against a sample row in tenant first. |
| Q8 | Flags process access to browser credential stores. | Generic technique, high FP; low priority relative to Q1/Q4. |
| Q9 | Flags the literal implant filename on any Falcon-covered host. | Very low true-positive probability by design (appliance-only malware); kept for opportunistic forensic catch only. |
Machine-Readable IOC Appendix
type,value,action,severity,expiration,description,tags ipv4,146.103.99.177,detect,high,2027-03-11,PivotC2 C2 (observed path /0c5b76709523; port 8443),campaign:PivotC2 cve:CVE-2025-25249 ipv4,46.151.29.58,detect,high,2027-03-11,PivotC2 secondary C2 (no port published),campaign:PivotC2 cve:CVE-2025-25249 filename,fortirun.bin,hunt,high,2027-03-11,Exploit/orchestration binary used against the CAPWAP overflow (appliance-side only -- FortiOS CLI hunt, Section 7),campaign:PivotC2 cve:CVE-2025-25249 filename,fsv_sync.dat,hunt,medium,2026-12-11,Device-specific harvested secret/config artifact (appliance-side only -- FortiOS CLI hunt, Section 7),campaign:PivotC2 filename,.i.js,hunt,high,2027-03-11,Persisted PivotC2 2nd-stage implant at /tmp/.i.js (appliance-side only; opportunistic Falcon net-catch via Q9),campaign:PivotC2
# XOR payload-decryption key (2nd-stage retrieval) "pivot" # Auto-mode 5-stage internal pipeline (fully appliance-side) harvest config -> decrypt credentials -> extract internal subnets -> CIDR-based port scan -> stage for lateral movement # PivotC2 protocol behavior Compact binary protocol multiplexing multiple SSH-like channels (interactive shell, file transfer, SOCKS5/HTTP proxy, port forwarding, DNS lookups, process enumeration) over one TLS connection to C2 # CAPWAP exploitation surface Malformed CAPWAP control packets to UDP 5246 (observed up to 5249)
Implant: PivotC2 (Node.js RAT), version 0.2.3
Exploit binary: fortirun.bin (Bash/Python-orchestrated CAPWAP exploit)
CVE: CVE-2025-25249 (cw_acd CAPWAP heap overflow, CVSS 9.8)
Attribution: Russian-speaking, financially motivated cybercrime
operator (SOCRadar STRU, high confidence) -- Russian-
language code comments, AI-assisted tooling, exfil
pattern focused on backup/storage infrastructure
Scope observed: 30,000+ FortiGate IPs scanned; 178 confirmed
compromised (US > Chile > Colombia > UK)
CVE-2025-25249 FortiOS/FortiSwitchManager cw_acd CAPWAP heap
overflow (CVSS 9.8) CISA KEV added 2026-09-09
FCEB due 2026-09-12
CWE-122 (Heap Overflow), CWE-787 (OOB Write)
[ ] Verify FortiOS is at or above 7.6.4 / 7.4.9 / 7.2.12 / 7.0.18
[ ] Verify FortiSwitchManager is at or above 7.2.7 / 7.0.6
[ ] Confirm CAPWAP Control (UDP 5246-5249) is not exposed to the
internet on any WAN-facing interface
[ ] Run Section 7 FortiOS CLI checks against every internet-facing
FortiGate/FortiSwitchManager appliance
[ ] Treat all locally stored credentials as exposed and rotate them
on any device showing compromise indicators (Playbook C)
Detection Validation Gates
| Gate | Requirement | Status |
|---|---|---|
| Field-name validation | Every CQL field validated against the known Falcon data model (lint_cql_fields.py) or explicitly flagged ⚠ unverified | Pass — 9/9 (fixed: all ContextTimeStamp occurrences corrected to @timestamp); Q2/Q3/Q4/Q7 remain marked ⚠ module-dependent (Identity Protection licensing/ingestion), not fabricated fields |
| Event-name validation | Every #event_simpleName value is a real Falcon event (lint_cql_syntax.py) | Pass — Q7 corrected from fabricated AuthActivityAuditData/LdapSearch to real ActiveDirectoryAuthentication; Q9 corrected from fabricated FileCreateInfo/FileWritten to real PeFileWritten/NewExecutableWritten |
| CONF/FP/COST ratings present | Every query carries all three ratings | Pass — 9/9 |
| FP exclusion guidance (medium+ FP) | Every FP-medium-or-higher query has a // TUNING: note | Pass — 9/9 |
| IOC provenance | Every atomic IOC traces to a saved source snapshot; untraceable IOCs dropped or converted to behavioral/placeholder | Pass — see §4, §10 grab-csv, and sources/00-fetch-notes.txt; no hashes shipped since none were published |
| Coverage-gap honesty | Appliance-only exploitation steps explicitly marked not Falcon-visible, not glossed over | Pass — see §3, §6, §15 |
| Regex path-slash safety | No unescaped path separator inside a /.../ CQL regex; basenames matched via FileName-style fields | Pass — Q9 uses FileName=/^\.i\.js$/i |
| HTML escaping in <pre> blocks | <, >, & escaped throughout, including bare >= | Pass — verified against verify_huntpack.py |
| Gold template structure | Fixed left sidebar with show/hide toggle, hp-header/meta-grid hero, section/section-hdr/section-body skeleton, region selector inside the CQL section, all five Falcon clouds | Pass — rebuilt on the gold template; region selector confirmed inside §8; US-GOV-2 added |
Hardening — Tiered
Immediate (this week)
| Control | MITRE Mitigation | Authority | Verification |
|---|---|---|---|
| Patch FortiOS to 7.6.4 / 7.4.9 / 7.2.12 / 7.0.18 or later; FortiSwitchManager to 7.2.7 / 7.0.6 or later | M1051 (Update Software) | Fortinet PSIRT FG-IR-25-084 (via CISA KEV notes field); CISA BOD 26-04 — due 2026-09-12 | get system status — confirm version |
| Restrict CAPWAP Control (UDP 5246–5249) exposure to the internet; disable the wireless-controller/fabric service on WAN-facing interfaces where not required | M1030 (Network Segmentation), M1042 (Disable/Remove Feature or Program) | Fortinet PSIRT FG-IR-25-084 remediation guidance; CyberSecurityNews/GBHackers remediation notes | show system interface — confirm allowaccess excludes CAPWAP on WAN; local-in-policy deny confirmed present |
| Run the §7 native FortiOS CLI checks against every internet-facing FortiGate/FortiSwitchManager appliance | M1047 (Audit) — best-practice, no formal benchmark for this specific artifact set | CyberSecurityNews/GBHackers IOC guidance | Absence of /tmp/.i.js, fsv_sync.dat, fortirun.bin, and no sessions to the two C2 IPs |
| Rotate all locally stored credentials on any device showing compromise indicators — VPN PSKs, SSL-VPN credentials, wireless PSKs, LDAP bind secrets, local admin passwords | M1026 — best-practice, no formal benchmark; treat as mandatory post-compromise hygiene | CyberSecurityNews/GBHackers explicit remediation guidance ("treat all locally stored credentials as exposed") | Confirm new PSK/credential values propagated to all dependent VPN peers/clients; old values rejected |
Near-term (1–4 weeks)
| Control | MITRE Mitigation | Authority | Verification |
|---|---|---|---|
| Enforce MFA on SSL-VPN and all administrative access to reduce the value of any still-undetected harvested static credential | M1032 (Multi-factor Authentication) | CIS Controls v8, Control 6.3/6.5 — best-practice for remote access | Attempt SSL-VPN logon with password only — must be rejected without second factor |
| Network-segment FortiGate management/internal interfaces from sensitive internal subnets to limit blast radius of auto-mode CIDR scanning and pivoting | M1030 (Network Segmentation) | CIS Controls v8, Control 12 (Network Infrastructure Management) — best-practice | From the FortiGate's internal interface, confirm ACL/firewall policy blocks reach into sensitive VLANs by default |
| Ingest FortiGate SSL-VPN/VPN authentication logs into Falcon Next-Gen SIEM (or existing SIEM) to close the identity-visibility gap flagged in §5/§15 | M1047 (Audit) | ⚠ best-practice, no formal benchmark — visibility control specific to this pack's stated coverage gap | Confirm test VPN logon appears as a searchable event within 15 minutes |
Strategic (1–3 months)
| Control | MITRE Mitigation | Authority | Verification |
|---|---|---|---|
| Formal edge-appliance vulnerability-management program with an SLA tied to CISA KEV due dates for all internet-facing network/security appliances | M1051 (Update Software), process control | CISA BOD 22-01 / BOD 26-04 | Audit shows 100% of KEV-listed appliance CVEs patched within their published due date over a rolling quarter |
| Privileged Access Management (PAM) / vault-based rotation for all network-appliance admin, LDAP-bind, and VPN PSK credentials, with just-in-time checkout | M1026 (Privileged Account Management) | CIS Controls v8, Control 5/6 — best-practice | Confirm appliance admin credentials are not stored in plaintext config or shared spreadsheets; checkout logged |
Deployable Playbooks
Playbook A — Block CAPWAP Exposure & Disable Unneeded Wireless-Controller Service on WAN Interfaces
config firewall service custom
edit "CAPWAP-mgmt"
set protocol UDP
set udp-portrange 5246-5249
next
end
config firewall local-in-policy
edit 1
set intf "wan1"
set srcaddr "all"
set dstaddr "all"
set action deny
set service "CAPWAP-mgmt"
set schedule "always"
next
end
Playbook B — Firmware Upgrade to a Patched Release
! 1. Back up full configuration before upgrading execute backup config flash ! 2. Confirm current version get system status ! 3. Follow Fortinet's documented upgrade path to a patched build: ! FortiOS -> 7.6.4 / 7.4.9 / 7.2.12 / 7.0.18 (or later) ! FortiSwitchManager -> 7.2.7 / 7.0.6 (or later) ! (Follow Fortinet's official upgrade-path documentation for any ! required intermediate hops between your current and target build.) execute restore image flash <target-firmware-image> ! 4. Post-upgrade, re-verify version and re-run the Section 7 IOC checks get system status
Playbook C — Credential Rotation for a Confirmed or Suspected Compromised FortiGate
! 1. Rotate all IPsec/SSL-VPN pre-shared keys and re-distribute to legitimate peers
config vpn ipsec phase1-interface
edit "<tunnel-name>"
set psksecret <new-strong-psk>
next
end
! 2. Force-expire and reset all local admin account passwords
config system admin
edit "<admin-account>"
set password <new-strong-password>
next
end
! 3. Rotate the LDAP bind account's password both on the FortiGate
! and in Active Directory, then update the FortiGate LDAP server object
config user ldap
edit "<ldap-server-name>"
set password <new-bind-password>
next
end
! 4. Rotate wireless PSKs for any SSID using pre-shared key authentication
config wireless-controller vap
edit "<ssid-name>"
set passphrase <new-strong-passphrase>
next
end
Containment Runbook
| Phase | Actions |
|---|---|
| Isolate |
1. Identify every internet-facing FortiGate/FortiSwitchManager appliance and check patch level against §12 Immediate controls. 2. For any appliance found unpatched or showing IOC hits (§7), apply Playbook A (block CAPWAP exposure) immediately, even before the firmware upgrade window. 3. If Q1 or Q4 fires on a Falcon-covered host, isolate that host from the network pending triage. 4. Block the two known C2 IPs (146.103.99.177, 46.151.29.58) at the perimeter firewall/proxy. |
| Eradicate |
1. Apply Playbook B (firmware upgrade) to every affected appliance. 2. Remove confirmed implant artifacts ( /tmp/.i.js, fsv_sync.dat, fortirun.bin) — a factory reset plus clean config restore is the safest path for any appliance with confirmed compromise, since arbitrary code execution on the device means the full extent of persistence cannot be guaranteed by artifact removal alone.3. Terminate any active sessions to the C2 IPs found via §7 checks. 4. Apply Playbook C (credential rotation) for every credential type stored on the affected appliance. |
| Recover |
1. Re-verify firmware version and re-run all §7 checks clean before returning the appliance to production. 2. Re-enable CAPWAP/wireless-controller service only if operationally required, with the restricted local-in-policy from Playbook A still in place. 3. Monitor Q1–Q9 for 30 days post-recovery for any recurrence. 4. Review AD/identity telemetry (Q2, Q3, Q7) for any lingering unauthorized access using previously-harvested (now rotated) credentials. 5. Conduct a lessons-learned review covering exposure window, why the appliance was internet-facing on CAPWAP, and whether centralized FortiGate log ingestion (§12 near-term) should be accelerated. |
Detection Coverage Map
| Technique / Step | Behavior | CQL | IOA | Coverage |
|---|---|---|---|---|
| T1190 — CAPWAP heap overflow exploitation | On-appliance RCE via malformed CAPWAP packet | — | — | Gap — appliance-internal; no Falcon sensor exists on FortiOS/FortiSwitchManager firmware. Mitigate via patch (§12), do not expect to detect. |
| T1059.007 / T1027 — JS stager, Base64/XOR payload | Node.js stager execution and payload decryption on-appliance | — | — | Gap — appliance-internal, same reason as above. |
| T1552.001 — Credential store decryption | AES-256-CBC/AES-128-GCM decryption of FortiGate ENC fields | — | — | Gap — appliance-internal; detect the downstream reuse instead (rows below). |
| T1071.001 — C2 communication | Outbound TLS to 146.103.99.177:8443 / 46.151.29.58 | Q1 | Candidate 1 | High — only if the connecting asset is Falcon-covered; the C2 session originating from the appliance itself remains invisible |
| T1090 — SOCKS5/HTTP proxy tunneling | PivotC2 multiplexed tunnel channels | — | — | Gap — no reliable EDR signal for traffic tunneled through a non-Falcon-covered pivot; only the far end (if Falcon-covered) generating its own separate connections is visible. |
| T1046 / T1018 — internal CIDR auto-mode scan | Port scan of internal subnets from the compromised appliance | Q4 (proxy signal) | Candidate 2 | Medium — raw inbound scan telemetry is a known EDR blind spot; Q4 detects the authenticated-access fan-out that typically follows, not the scan itself |
| T1078 — Credential reuse (VPN/SSL-VPN/LDAP/admin) | Harvested credentials used elsewhere in the environment | Q2, Q3, Q4 | Candidate 2 (Q4) | Medium — depends on Identity Protection/AD telemetry being present in tenant (⚠ flagged); FortiGate's own SSL-VPN logon events are NOT natively in Falcon unless separately ingested (§5) |
| T1021.001 — RDP lateral movement | RDP enablement/use during confirmed intrusions | Q5 | — | Good — standard Falcon registry/process telemetry |
| T1087.002 / T1069.002 — AD enumeration | Directory/group discovery during confirmed intrusions | Q7 | — | Medium — noisy, module-dependent (Identity Protection); event name now confirmed real (§11) |
| T1555.003 — Browser credential theft | Confirmed in full-network-intrusion cases, generic technique | Q8 | — | Low-Medium — generic behavioral signal only |
| T1567.002 — Exfiltration to Wasabi | Exchange mailbox / config data exfil | Q6 | — | Medium — generic cloud-storage signal, not PivotC2-exclusive; high FP if Wasabi is a sanctioned vendor |
Hunt Summary Ticket
TITLE.....: PivotC2 Node.js RAT via FortiGate CAPWAP RCE (CVE-2025-25249) THREAT....: PivotC2 (custom Node.js post-exploitation framework, v0.2.3) SEVERITY..: Critical (CVSS 9.8) / CISA KEV (added 2026-09-09, due 2026-09-12) SCOPE.....: 30,000+ FortiGate IPs scanned; 178 confirmed compromised (US > Chile > Colombia > UK); active since >= July 2026 HYPOTHESIS: Compromised FortiGate appliances harvest and exfiltrate local credentials; those credentials are then reused, and PivotC2's internal auto-mode scanner probes the internal network -- both effects are visible from Falcon-covered endpoints even though the appliance itself is not. QUERIES...: 9 CQL hunts (Q1-Q9); 2 promoted to Custom IOA candidates (Q1, Q4) DO FIRST..: (1) Patch every internet-facing FortiOS/FortiSwitchManager to a fixed build. (2) Run Section 7 CLI checks against every such appliance. (3) Run Q1 across the full Falcon fleet for the two known C2 IPs. FINDINGS..: [analyst to fill in after first run] GAPS......: On-appliance exploitation, stager execution, and credential decryption are NOT visible to Falcon (no sensor on FortiOS/FortiSwitchManager firmware). FortiGate's own SSL-VPN auth logs are not natively in Falcon unless separately ingested. ACTIONS...: Patch (Playbook B) -> restrict CAPWAP exposure (Playbook A) -> rotate credentials on any device with compromise indicators (Playbook C) -> monitor Q1-Q9 for 30 days. OWNER.....: [assign at ticket creation] VERSION...: 1.0 -- 2026-09-11
Changelog
ContextTimeStamp references corrected to @timestamp. Fixed fabricated event names: Q7 AuthActivityAuditData/LdapSearch → ActiveDirectoryAuthentication; Q9 FileCreateInfo/FileWritten → PeFileWritten/NewExecutableWritten. Added the missing US-GOV-2 Falcon cloud option; confirmed region selector sits inside the CQL section. No IOC, attack-chain, or hardening content was altered.References
- CyberSecurityNews — "Hackers Actively Exploiting FortiGate Firewalls to Deploy Custom Node.js Malware" (Sep 8, 2026). cybersecuritynews.com — saved:
sources/01-cybersecuritynews-report.txt - GBHackers — "Hackers Exploit Critical FortiGate Flaw to Deploy AI-Assisted PivotC2 RAT" (Sep 9, 2026). gbhackers.com — saved:
sources/02-gbhackers-report.txt - CISA Known Exploited Vulnerabilities Catalog (live JSON feed), entry for CVE-2025-25249. cisa.gov/known-exploited-vulnerabilities-catalog — saved:
sources/03-cisa-kev-catalog.txt - SOCRadar — "CVE-2025-25249 (PivotC2): FortiGate RAT Exploited in the Wild" — primary research cited by references 1 and 2 above; not independently fetchable at build time (HTTP 403 / Cloudflare bot challenge across three attempts). socradar.io/blog/cve-2025-25249-pivotc2-fortigate-rat
- Fortinet PSIRT advisory FG-IR-25-084 (referenced in the CISA KEV entry's notes field — vendor advisory for CVE-2025-25249). fortiguard.fortinet.com/psirt/FG-IR-25-084
- NVD — CVE-2025-25249 detail page (referenced in the CISA KEV entry's notes field). nvd.nist.gov/vuln/detail/CVE-2025-25249