k0t Edge-Device Intrusions — FortiWeb, FortiGate and GlobalProtect — Microsoft Sentinel Threat Hunts

Threat Overview

Group-IB and NyxLab published a joint investigation on October 21, 2026, describing a global intrusion campaign attributed to the operator k0t (also CryptoFeel/Member19/QazWsxShop). Researchers recovered evidence of large-scale scanning of exposed security appliances, exploitation of FortiWeb CVE-2025-64446, FortiGate credential brute forcing, and abuse of Palo Alto GlobalProtect CVE-2026-0257 where authentication-override cookies are enabled. The researchers identified more than 70,000 exposed credentials and related records, including network-device and LDAP material. After initial access, the operators used OpenConnect VPN access, MeshCentral/MeshAgent, AdaptixC2, RMM tools, credential extraction, and Rclone exfiltration. This is not evidence that every listed credential belongs to a distinct compromised organization. Group-IB found overlaps with Qilin and The Gentlemen victims but did not confirm direct ransomware affiliation. This report focuses on the newly described cross-vendor intrusion chain, not the previously covered GlobalProtect vulnerability in isolation.

References

Impacted Systems

  • Fortinet FortiWeb management/web appliance, on-premises/virtual; CVE-2025-64446 affects 7.0.0–7.0.11, 7.2.0–7.2.11, 7.4.0–7.4.9, 7.6.0–7.6.4, 8.0.0–8.0.1. Fixed at 7.0.12, 7.2.12, 7.4.10, 7.6.5, 8.0.2 respectively. Exposure: reachable HTTP(S) management service; attacker does not require credentials for the vulnerable request. FortiGate is not affected by this FortiWeb-specific CVE.
  • Fortinet FortiGate / FortiOS, physical/virtual firewall and VPN roles: campaign includes brute force of exposed administrative/API/VPN authentication, and theft of appliance configuration secrets. No single FortiGate software version is implied by this credential-attack technique; actual vulnerable configuration and patch status require inventory.
  • Palo Alto Networks GlobalProtect portals/gateways on affected PAN-OS/Prisma Access configurations; CVE-2026-0257 depends on authentication-override cookie/certificate configuration. Specific affected and fixed build must be checked against the current Palo Alto advisory for the deployed release; no blanket build range is asserted. Internet-facing VPN endpoints are relevant.
  • Windows/Active Directory hosts reachable after VPN access: downstream lateral movement, credential dumping, unauthorized RMM installation, and exfiltration; not a product vulnerability in Windows itself.

Why this matters

Security appliances often lack endpoint EDR visibility. Successful exploitation or credential reuse can expose LDAP bind secrets, administrative accounts, VPN access, and downstream Windows hosts. This hunt prioritizes appliance authentication/configuration anomalies and post-access persistence, not generic scanning volume.

Exploitation Status

Confirmed by researchers: recovered tooling, credential datasets, MeshCentral device groups and observed post-compromise artifacts. Vendor/third-party reporting: CVE-2025-64446 is a known exploited FortiWeb vulnerability. Assessment, not confirmed attribution: relationship to FortiBleed and ransomware operators remains uncertain. Historical IOCs: mesh.buttruyen.com, agent.afahimsa.top, 64.94.85.14, 162.33.178.213, sthyjk.com, alknene.shop (Group-IB, October 21); infrastructure may rotate.

What this hunt looks for

Prepared Sentinel searches for FortiWeb request structure, unexpected appliance administrator/trusted-host changes, failed-to-successful Fortinet logins, newly observed GlobalProtect VPN sources, published C2, unauthorized RMM, credential-dumping commands, and Rclone transfer execution. These are proposed hunts, not executed reviews.

Required logs

  • CommonSecurityLog with full HTTP URI (WAF/CEF/IPS); only when ingested into Microsoft Sentinel.
  • CommonSecurityLog with appliance/security-event fields; only when ingested into Microsoft Sentinel.
  • DeviceProcessEvents (Microsoft Defender for Endpoint); only when ingested into Microsoft Sentinel.

Hunt 01 — FortiWeb path traversal and forged-admin request

Signal: Very high — attempted exploitation

CommonSecurityLog
| where TimeGenerated >= ago(30d)
| extend U=tolower(tostring(column_ifexists("RequestURL",""))), E=tolower(tostring(column_ifexists("AdditionalExtensions","")))
| where U contains "/cgi-bin/fwbcgi" and (U contains "admin%3f" or U contains "../../")
| project TimeGenerated, DeviceVendor, DeviceProduct, SourceIP, DestinationIP, DeviceAction, RequestURL, AdditionalExtensions, Message
| order by TimeGenerated desc

Detection caveat: Requires full HTTP URI in CEF/WAF; a blocked request is an attempt, not proof of compromise.

Hunt 02 — Fortinet administrative account and trusted-host changes

Signal: High when admin creation is unexpected

CommonSecurityLog
| where TimeGenerated >= ago(30d)
| where DeviceVendor has "Fortinet" or DeviceProduct has_any ("FortiGate","FortiWeb","FortiAnalyzer")
| extend E=tolower(strcat(tostring(column_ifexists("Message",""))," ",tostring(column_ifexists("AdditionalExtensions",""))))
| where (E contains "admin" and (E contains "add" or E contains "create" or E contains "new")) or (E contains "trusthost" and E contains "0.0.0.0")
| project TimeGenerated, DeviceVendor, DeviceProduct, SourceIP, DestinationIP, DeviceAction, DeviceEventClassID, Message, AdditionalExtensions
| order by TimeGenerated desc

Detection caveat: CEF vendor messages vary; verify audit logs are exported and admin changes are not approved.

Hunt 03 — Fortinet authentication failure burst followed by success

Signal: High when same source successfully authenticates

let F=CommonSecurityLog
| where TimeGenerated >= ago(14d)
| where DeviceVendor has "Fortinet"
| extend M=tolower(strcat(tostring(column_ifexists("Message",""))," ",tostring(column_ifexists("DeviceAction",""))))
| where M contains "login" or M contains "auth"
| extend Fail=M contains "fail" or M contains "invalid" or M contains "deny", Success=M contains "success" or M contains "logged in" or M contains "login passed"
| where Fail or Success
| summarize Failures=countif(Fail), Successes=countif(Success), First=min(TimeGenerated), Last=max(TimeGenerated), Sample=take_any(Message) by SourceIP, DestinationIP, bin(TimeGenerated,30m)
| where Failures>=8 and Successes>=1;
F
| project First, Last, SourceIP, DestinationIP, Failures, Successes, Sample
| order by Last desc

Detection caveat: Needs device auth audit in CEF and consistent success/failure strings; VPN concentrators can produce legitimate retry storms.

Hunt 04 — GlobalProtect VPN success from newly observed source

Signal: Medium-high with admin/VPN context

let Events=CommonSecurityLog
| where TimeGenerated >= ago(30d)
| where DeviceProduct has "GlobalProtect" or DeviceVendor has "Palo Alto"
| extend M=tolower(strcat(tostring(column_ifexists("Message",""))," ",tostring(column_ifexists("DeviceAction",""))))
| where M contains "globalprotect" or M contains "vpn"
| where M contains "login" or M contains "auth" or M contains "connect"
| where M contains "success" or M contains "connected" or M contains "login passed"
| extend Account=coalesce(tostring(column_ifexists("SourceUserName","")),tostring(column_ifexists("DestinationUserName","")))
| where isnotempty(Account) and isnotempty(SourceIP);
let Prior=Events | where TimeGenerated between (ago(30d)..ago(3d)) | summarize by Account, SourceIP;
Events
| where TimeGenerated>=ago(3d)
| join kind=leftanti Prior on Account, SourceIP
| project TimeGenerated, Account, SourceIP, DestinationIP, DeviceProduct, Message, DeviceAction
| order by TimeGenerated desc

Detection caveat: A new VPN IP alone is not malicious; investigate device identity, MFA, travel, and authentication-override settings.

Hunt 05 — Campaign-specific MeshCentral and AdaptixC2 infrastructure

Signal: High — published infrastructure contact

let Ips=dynamic(["64.94.85.14","162.33.178.213"]);
let Domains=dynamic(["mesh.buttruyen.com","agent.afahimsa.top","sthyjk.com","alknene.shop"]);
CommonSecurityLog
| where TimeGenerated >= ago(30d)
| extend U=tolower(tostring(column_ifexists("RequestURL",""))), H=tolower(tostring(column_ifexists("DestinationHostName","")))
| where DestinationIP in (Ips) or SourceIP in (Ips) or H has_any (Domains) or U has_any (Domains)
| project TimeGenerated, DeviceVendor, DeviceProduct, SourceIP, DestinationIP, DestinationPort, DestinationHostName, RequestURL, DeviceAction
| order by TimeGenerated desc

Detection caveat: Historical actor infrastructure can change; validate direction and ownership. Domain tokens may be absent in pure flow logs.

Hunt 06 — Unexpected remote-management agent installation

Signal: High with unapproved installation

DeviceProcessEvents
| where TimeGenerated >= ago(30d)
| extend F=tolower(FileName), C=tolower(ProcessCommandLine), P=tolower(InitiatingProcessFileName)
| where F has_any ("meshagent","atera","anydesk","teramind","ngrok") or C has_any ("meshagent","meshcentral","atera","anydesk","teramind","ngrok")
| where C contains "install" or C contains "--install" or P in ("powershell.exe","cmd.exe","wscript.exe","mshta.exe","bash","sh")
| project TimeGenerated, DeviceName, Account=InitiatingProcessAccountName, InitiatingProcessFileName, FileName, ProcessCommandLine, FolderPath
| order by TimeGenerated desc

Detection caveat: Legitimate RMM is common; require software-owner approval and deployment context.

Hunt 07 — Credential dumping or domain extraction tooling

Signal: High when tools and dumping arguments align

DeviceProcessEvents
| where TimeGenerated >= ago(30d)
| extend C=tolower(ProcessCommandLine), F=tolower(FileName)
| where (C contains "secretsdump" and C contains "-just-dc") or (C contains "netexec" and (C contains "--sam" or C contains "--lsa" or C contains "--ntds")) or (C contains "mimikatz" and C contains "sekurlsa") or (C contains "lsadump::dcsync")
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, FileName, ProcessCommandLine, InitiatingProcessFileName
| order by TimeGenerated desc

Detection caveat: Dual-use assessment tools; check authorized red-team activity.

Hunt 08 — Rclone cloud exfiltration command execution

Signal: High if remote-copy command unexpected

DeviceProcessEvents
| where TimeGenerated >= ago(30d)
| where FileName in~ ("rclone.exe","rclone")
| extend C=tolower(ProcessCommandLine)
| where C contains " copy " or C contains " sync " or C contains " move "
| project TimeGenerated, DeviceName, InitiatingProcessAccountName, FileName, ProcessCommandLine, InitiatingProcessFileName
| order by TimeGenerated desc

Detection caveat: Rclone is legitimate backup software; distinguish scheduled approved jobs from first-seen interactive execution.

Detection Notes

Highest signal: explicit FortiWeb exploit request, unexpected privileged admin/trusted-host changes, campaign C2 contact, credential-dumping process arguments. Authentication bursts and RMM installation can be legitimate; require asset context. CommonSecurityLog URL/Message fields depend on CEF mapping and whether the source exports HTTP/admin audit. DeviceProcessEvents is absent unless relevant endpoints are onboarded to MDE and connected to Sentinel. An appliance can be compromised without a detectable endpoint event.