PoeLLM / Canto Incognito: Poem-C2 Mining Botnet on Exposed AI Servers

3,400+ internet-facing Linux servers (LiteLLM, Ollama, Gotenberg, Gitea) enrolled in a Kryptex mining botnet whose C2 address is encoded in a GitHub poem · Lumen Black Lotus Labs
Threat
PoeLLM (campaign: Canto Incognito)
Severity
HIGH
Type
Botnet / Cryptojacking / Dead-drop C2 (Linux ELF)
Entry
Exploited internet-facing services
CVEs
CVE-2026-42271 · CVE-2026-10520
Version
v0.3 · 2026-10-09
Author
HuntPack
Confidence
High on infrastructure, medium on attribution
01

Executive Summary

PoeLLM is a Linux ELF botnet implant tracked by Lumen Black Lotus Labs as the Canto Incognito campaign. It has been active since at least April 2026 (first poem commit 2026-04-13) and has impacted 3,400+ victim servers, with a mid-June peak of nearly 2,200 affected servers and roughly 800 active per day. Victims are mostly in the United States and Western Europe. Lumen assesses with moderate confidence that an Italian-speaking, financially motivated actor is behind it.

Entry and targets: the actor scans for and exploits internet-facing open-source and AI services: LiteLLM (default port 4000), Ollama, Gotenberg (port 3000) and Gitea, with possible targeting of Ivanti Sentry. The LiteLLM path is a crafted POST to /mcp-rest/test/connection (command injection, CVE-2026-42271) that tells the target to download the payload from port 81 on the C2. Lumen first found the infrastructure while investigating Ivanti Sentry CVE-2026-10520.

Tradecraft: the payload is an ELF named libgcrypt with a remote shell, XMRig and Iron miners, HTTP/S scanning and exploit delivery. Victims mine to Kryptex endpoints and are reused as scanners and exploit servers, which is how the botnet grows. Its signature trick is the C2 dead drop: the current C2 IPv4 address is derived from four words in a poem titled "On the Nature of Connection" in dash.css of a GitHub repo owned by ejejejdfbbebe (a fork of the nodejs.org source). Changing four words rotates every victim to a new C2, so IP blocklists age quickly. Many C2s were compromised routers running Boa web servers with vulnerable admin pages (CVE-2018-21027 and CVE-2018-21028 are named for the first C2 router; Lumen saw no direct evidence they were exploited by the actor).

Defender priority: this pack is built for the Falcon Linux sensor. First find every internet-reachable LiteLLM, Gotenberg, Gitea, Ollama and Ivanti Sentry instance and patch or hide it (Q10, section 12). Then hunt the host-side signals that survive C2 rotation: a service process spawning a shell or downloader (Q5), a fetch from port 81 (Q6), a server talking to a mining pool (Q3, Q9), and a server fanning out to many public hosts on 3000, 4000 or 22 (Q8). Treat the IP list (Q1) as a retro-hunt, not the defence.

02

Source Review & Web Hunter Notes

TierSourceKey findingCarry forward
PrimaryLumen Black Lotus Labs: Canto incognito: tracking the PoeLLM malwareOriginal research. Campaign and malware names, poem C2 mechanism, 12 C2 IPs with dates, Kryptex endpoints, sample hash, targets, CVEs, ports, attribution.yes
CorroboratingThe Hacker News (2026-10-07)Reports Lumen's findings plus a Lumen engineer quote on poem rotation. Confirms 3,400+ victims, GitHub repo name, targets, XMRig and Iron, Kryptex.partial
CorroboratingHelp Net Security (2026-10-08)Reports Lumen's findings. Confirms dash.css, the endpoint path, ports 3000 and 4000, the Ivanti Sentry CVE and the 11 poem edits.partial

Web-hunter notes and decisions

  • Independence: both news articles derive from the Lumen report and add no atomic indicators of their own. Every atomic IOC is therefore single-sourced, so every indicator in this pack ships detect. None is eligible for prevent or critical.
  • Raw text, not summaries: the three pages were fetched and their plain text saved verbatim as source snapshots (PoeLLM-CantoIncognito-Hunt-sources/); the provenance gate reads those files.
  • Corrections to the request brief, after checking the primary source: (1) port 81 is the payload download port, not a beacon port; the beacon ports are 3778, 5001, 5002 and 9999. (2) CVE-2018-21027 and CVE-2018-21028 are flaws in the router admin pages of C2 hosts; Lumen reports no direct evidence the actor exploited them, so they are not listed as PoeLLM exploits. (3) Ivanti Sentry is "possible targeting" in Lumen's words, tied to CVE-2026-10520 through one compromised victim. (4) Lumen's own text gives both "more than 3,400 victim servers" and "almost 2,200" for the mid-June peak; both figures are reported as stated.
  • Not in the sources: no persistence mechanism, no Iron miner binary name or hash, no fixed-version numbers for CVE-2026-42271 or CVE-2026-10520, and no Ollama CVE. These are flagged as gaps rather than filled in.
  • Prompt-injection check: no embedded instructions or requests directed at an AI agent were found in any fetched page. No source was disqualified.
  • Actor admin host: Lumen assesses, with moderate confidence, that an Italy-hosted server running Prometheus and Uptime Kuma is the operator's management interface. No victim contacts it, so it has no endpoint-detection value and its address is deliberately not shipped as an indicator.
  • Dedupe: name and IOC checks against the published library were clear. The published LiteLLM and Ivanti Sentry packs cover the CVEs; this pack covers the PoeLLM campaign and shares none of their indicators.
03

Hunt Brief & Attack Chain

Hypotheses (ordered by fidelity)

#HypothesisMITRETelemetryConfidence
H1A Linux host executes an ELF named libgcrypt or the Lumen sample hash.T1059.004, T1036.005Process creation (Falcon: ProcessRollup2)High (Q4)
H2A server connects to a Kryptex mining endpoint or resolves the Kryptex node.T1496Network connections and DNS lookups (Falcon: NetworkConnectIP4, DnsRequest)High (Q3, Q2)
H3A command or shell fetches a payload from a C2 port 81 or the /private/ tool paths.T1105Process creation (Falcon: ProcessRollup2)High (Q6)
H4An exposed AI or dev service is exploited and spawns a shell or downloader.T1190, T1059.004Process creation (Falcon: ProcessRollup2)Medium (Q5)
H5A compromised server fans out to many public hosts on 3000, 4000 or 22.T1595.002, T1110Network connections (Falcon: NetworkConnectIP4)Medium (Q8)
H6A server contacts known C2 or supporting infrastructure.T1071, T1584.008Network connections and DNS lookups (Falcon: NetworkConnectIP4, DnsRequest)High for active IPs, lower once rotated (Q1, Q2, Q7)
H7A miner runs on the host (XMRig, stratum command lines).T1496Process creation (Falcon: ProcessRollup2)Medium (Q9)
H8The vulnerable services are reachable on their default ports.T1190NetworkListenIP4Low, posture only (Q10)

Attack chain

StepBehaviorTelemetryHunt angle
1 Dead dropMalware reads the poem in dash.css on GitHub and derives the C2 IPv4 from four wordsProxy, TLS or DNS logs (not endpoint)Section 7 native hunt; gap in Falcon
2 ScanInfected servers and the operator scan the internet, mainly ports 3000 and 4000Network connections (Falcon: NetworkConnectIP4)Q8
3 ExploitCrafted POST to /mcp-rest/test/connection (LiteLLM) tells the target to download from C2 port 81Web/app logs; ProcessRollup2 for aftermathSection 7, Q5, Q6
4 InstallELF libgcrypt downloaded and runProcess creation (Falcon: ProcessRollup2)Q4, Q6
5 C2 beaconBeacons to a C2 on 3778, 5001, 5002 or 9999Network connections (Falcon: NetworkConnectIP4)Q1, Q7
6 MonetiseXMRig and Iron miners connect to KryptexNetworkConnectIP4, DnsRequest, ProcessRollup2Q2, Q3, Q9
7 ReuseVictim becomes scanner and exploit server; SSH and login-portal brute force experimentsNetwork connections (Falcon: NetworkConnectIP4)Q8
04

Consolidated IOC Table

All indicators trace to the Lumen report (snapshot 01). Action vocabulary: detect alerts, hunt is run manually. Nothing is prevent: every atomic indicator is single-sourced because the news articles only restate Lumen. The poem rotates the C2, so treat IPs as perishable.

TypeValueConfidenceActionContextExpiry
IPv492.119.164.50highdetectActive C2 per Lumen (first seen 2026-07-23). Single source2027-04-08
IPv4103.249.201.108highdetectActive C2 per Lumen (first seen 2026-08-13). Single source2027-04-08
IPv4178.128.14.204highdetectActive C2 per Lumen (first seen 2026-06-16). Single source2027-04-08
IPv4191.37.28.160mediumdetectHistorical C2, active April 13 to May 16, 2026. Router or VPS, may be reassigned2027-01-08
IPv489.39.253.46mediumdetectHistorical C2, active April 14 to June 24, 2026. Router or VPS, may be reassigned2027-01-08
IPv4120.224.114.212mediumdetectHistorical C2, active May 9 to September 8, 2026. Router or VPS, may be reassigned2027-01-08
IPv45.78.73.122mediumdetectHistorical C2, active June 8 to August 22, 2026. Router or VPS, may be reassigned2027-01-08
IPv415.204.178.28mediumdetectHistorical C2, active June 14 to August 17, 2026. Router or VPS, may be reassigned2027-01-08
IPv492.119.165.74mediumdetectHistorical C2, active July 1 to July 23, 2026. Router or VPS, may be reassigned2027-01-08
IPv445.133.73.28mediumdetectHistorical C2, active July 18 to July 22, 2026. Router or VPS, may be reassigned2027-01-08
IPv4185.132.53.158mediumdetectHistorical C2, active July 19 to September 12, 2026. Router or VPS, may be reassigned2027-01-08
IPv4136.148.69.233mediumdetectHistorical C2, active September 12 to September 25, 2026. Router or VPS, may be reassigned2027-01-08
IPv457.131.5.211mediumdetectServer on port 80 hosting malwarescan.xyz, contacted by the first C22027-01-08
Domainmalwarescan.xyzmediumdetectRegistered February 2026; likely operator-owned2027-01-08
IPv45.180.174.162mediumdetectKryptex endpoint, port 8029. Shared third-party service2027-01-08
IPv446.21.245.211mediumdetectKryptex endpoint, port 7029. Shared third-party service2027-01-08
Domainedge-ru-07.kryptex.networkmediumdetectKryptex node hostname for the endpoint above2027-01-08
SHA2566fab94577364beec314afae3b082dd680933f08a8349b9f35b92667e8231b501highdetectELF sample named libgcrypt analysed by Lumen. Single source, so detect not prevent2027-04-08
FilenamelibgcryptmediumhuntELF basename with no extension; the genuine library is libgcrypt.so.N2027-01-08
Ports3778, 5001, 5002, 9999mediumhuntBeacon ports to the C2. 5001 and 9999 are common, so behavioral onlyn/a
Port81mediumhuntPayload download port on the C2n/a
URL pathhxxp://5.78.73[.]122:81/private/bins.shmediumhuntMalicious URL listed in VirusTotal for the early C2 (per Lumen)2027-01-08
URL pathhxxp://5.78.73[.]122:81/private/python3.6mediumhuntAs above; both /private/ paths recurred on later C2s2027-01-08
GitHub accountgithub.com/ejejejdfbbebehighhuntHosts the poem in dash.css (fork of the nodejs.org site source). Do not block GitHub; hunt for fetches of this repon/a
05

Affected Surface & Telemetry Matrix

SurfaceRequired telemetryPriorityGap risk
Linux servers running LiteLLM, Ollama, Gotenberg, Gitea (VM, bare metal, container host)Process creation, network connections, listening ports and DNS lookups on Linux (Falcon Linux sensor: ProcessRollup2, NetworkConnectIP4, NetworkListenIP4, DnsRequest)HighContainers: the sensor sees the host kernel, so confirm container processes appear with the host aid; DnsRequest coverage varies by sensor version
Ivanti Sentry applianceAppliance logs and netflowMediumNo sensor on the appliance; use native logs and network telemetry
Routers with vulnerable admin pages used as C2 (Boa web server)Netflow, firewall logsLowUnmanaged third-party devices; only your side of the traffic is visible
Proxy, DNS and egress firewallWeb proxy URL logs, DNS logs, flow logsMediumThe GitHub poem fetch is only visible here, if TLS inspection or URL logging exists
06

ATT&CK Mapping

TacticTechniqueObserved behaviorQuery or control
Initial AccessT1190 Exploit Public-Facing ApplicationLiteLLM CVE-2026-42271 via /mcp-rest/test/connection; Gotenberg, Gitea, Ollama, Ivanti Sentry targetedQ5, Q10, section 7, section 12
ExecutionT1059.004 Unix ShellRemote shell in the ELF; shell spawned by the exploited serviceQ4, Q5
Command and ControlT1105 Ingress Tool TransferPayload fetched from C2 port 81Q6
Command and ControlT1102.001 Dead Drop ResolverC2 IPv4 derived from poem words on GitHubSection 7 (gap in Falcon)
Command and ControlT1071 / T1571Beacons on 3778, 5001, 5002, 9999Q1, Q7
Resource DevelopmentT1584.008 Network DevicesCompromised Boa routers reused as C2 and malware hostsSection 7 netflow
ReconnaissanceT1595.002 Vulnerability ScanningInfected hosts scan for ports 3000 and 4000Q8
Credential AccessT1110 Brute ForceExperimental distributed brute force at SSH and login portals (maturity uncertain)Q8
ImpactT1496 Resource HijackingXMRig and Iron mining to KryptexQ2, Q3, Q9
Defense EvasionT1036.005 Match Legitimate NamePayload named libgcrypt, mimicking a real libraryQ4
07

Native Audit-Log Hunts

SourceWhat to checkWhy
Web proxy / TLS inspection / egress logsServer-class hosts requesting dash.css from the ejejejdfbbebe GitHub repo (github.com or raw.githubusercontent.com). Servers should not read this file.Direct sign of the poem dead drop. Do not block GitHub itself.
LiteLLM access logs / reverse proxyPOST requests to /mcp-rest/test/connection, especially from unknown public sources or followed within seconds by a new outbound connectionCVE-2026-42271 exploitation path named by Lumen
Gotenberg, Gitea, Ollama access logsUnexpected POSTs from scanning IPs; requests on ports 3000 and 4000 from many unrelated sourcesInitial scan and exploit traffic
Ivanti Sentry (MICS) logs and appliance egressOutbound connections from the appliance to unfamiliar public hosts and new scanning behavior after patch-level checks for CVE-2026-10520Lumen discovered PoeLLM through a compromised Sentry that began scanning
NetFlow / firewallAny flow to the Section 4 addresses; internal servers sending port 81 flows to public hosts; high-fan-out sourcesRetro-hunt where there is no sensor
External attack-surface scanPorts 3000, 4000 and the Ollama listener reachable from the internet; Boa web servers on unusual ports such as 2222 on your edge routersGotenberg's own guide warns against exposure; Lumen found a Boa router on port 2222
Linux host (read-only)ss -ltnp for unexpected listeners; look for an executable named libgcrypt outside library directories; review crontab and systemd units (the sources document no persistence, so this is a precaution)Triage on hosts without full sensor coverage
08

Hunt Queries: CrowdStrike CQL and SentinelOne PowerQuery

Show all queries in
Pick your tenant's cloud first: every "Open in Falcon" button below uses this selection.

All queries target the Falcon Linux sensor (event_platform=Lin) and use only documented events: ProcessRollup2, SyntheticProcessRollup2, NetworkConnectIP4, NetworkListenIP4 and DnsRequest. Set the time window in the console; each query records its intended lookback in a // LOOKBACK comment.

Q1 · PoeLLM C2 and supporting infrastructure sweep (Linux outbound)
CONF HIGHFP MEDIUMCOST LOW

Looks for: Any Linux sensor outbound connection to the 12 Lumen-published C2 addresses or the supporting server that hosts malwarescan.xyz. FP: the nine historical C2s were compromised routers or short-lived VPS hosts and may have been reassigned since; judge hits against the active windows in section 4.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: A connection through a proxy or NAT the agent did not observe as a direct IP Connect is not captured.
  • PowerQuery assumes: endpoint.os holds the lowercase value linux on Linux agents.
  • PowerQuery assumes: The acting process on an IP Connect event is src.process.*, so src.process.name is the process that made the connection.
// HUNT: PoeLLM C2 and supporting infrastructure sweep (Linux outbound)
// MITRE: T1071.001, T1571, T1584.008
// CONF: high  FP: medium  COST: low | REQUIRES: Falcon Linux sensor, NetworkConnectIP4
// FALSE POSITIVES: historical C2 addresses were compromised routers and rented servers that may now belong to unrelated owners
// TUNING: for the nine historical addresses compare the hit timestamp to the active window in section 4 and escalate only inside that window; the three active addresses and the supporting server need no exclusion
// LOOKBACK: 30d (set in the console time picker)
#event_simpleName=NetworkConnectIP4 event_platform=Lin
| in(field=RemoteAddressIP4, values=["92.119.164.50", "103.249.201.108", "178.128.14.204", "191.37.28.160", "89.39.253.46", "120.224.114.212", "5.78.73.122", "15.204.178.28", "92.119.165.74", "45.133.73.28", "185.132.53.158", "136.148.69.233", "57.131.5.211"])
| table([@timestamp, aid, ComputerName, RemoteAddressIP4, RemotePort, ContextProcessId_decimal])
| sort(@timestamp, order=desc)
Q2 · DNS lookups for malwarescan.xyz and the Kryptex node
CONF MEDIUMFP LOWCOST LOW

Looks for: Linux hosts resolving the operator-linked domain or the Kryptex node hostname that PoeLLM victims contacted.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: Lookups made over DNS-over-HTTPS or by a resolver the agent does not observe are not captured.
  • PowerQuery assumes: event.dns.request (pySigma mapping) is the populated lookup-name field; some schema versions carry dns.request instead.
  • PowerQuery assumes: The matches operator is case-insensitive by default, mirroring the CQL /i flag.
  • PowerQuery assumes: Linux agents emit DNS Resolved events for the lookups of interest.
// HUNT: DNS lookups for the operator domain and the Kryptex node
// MITRE: T1071.004, T1496
// CONF: medium  FP: low  COST: low | REQUIRES: Falcon Linux sensor with DnsRequest telemetry
// FALSE POSITIVES: researchers or sandboxes resolving the published indicators; a sanctioned Kryptex user on the same host would also match the second name
// LOOKBACK: 30d (set in the console time picker)
#event_simpleName=DnsRequest event_platform=Lin
| DomainName=/(^|\.)(malwarescan\.xyz|edge-ru-07\.kryptex\.network)$/i
| table([@timestamp, aid, ComputerName, DomainName, ContextProcessId_decimal])
| sort(@timestamp, order=desc)
Q3 · Kryptex mining endpoint egress from servers
CONF HIGHFP LOWCOST LOW

Looks for: Server connections to the two Kryptex endpoint and port pairs Lumen observed from PoeLLM victims (5.180.174.162:8029, 46.21.245.211:7029). A server talking to a mining pool is the payoff signal.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: Mining traffic relayed through a proxy the agent did not observe as a direct connection is not captured.
  • PowerQuery assumes: dst.port.number is stored as a number, so the comparison uses numeric literals.
  • PowerQuery assumes: endpoint.os holds the lowercase value linux on Linux agents.
// HUNT: Kryptex mining endpoint egress from servers
// MITRE: T1496, T1071
// CONF: high  FP: low  COST: low | REQUIRES: Falcon Linux sensor, NetworkConnectIP4
// FALSE POSITIVES: an authorised mining rig or a lab host; neither belongs on a production server
// LOOKBACK: 30d (set in the console time picker)
#event_simpleName=NetworkConnectIP4 event_platform=Lin
| (RemoteAddressIP4=5.180.174.162 RemotePort=8029) or (RemoteAddressIP4=46.21.245.211 RemotePort=7029)
| table([@timestamp, aid, ComputerName, RemoteAddressIP4, RemotePort, ContextProcessId_decimal])
| sort(@timestamp, order=desc)
Q4 · libgcrypt ELF execution or PoeLLM sample hash
CONF HIGHFP LOWCOST LOW

Looks for: Execution of a process whose basename is exactly libgcrypt (no .so suffix, so not the legitimate shared library) or whose SHA256 matches the Lumen-analysed sample.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: If tgt.process.image.sha256 is not populated on the tenant, a renamed copy of the sample is missed by the hash arm.
  • PowerQuery assumes: tgt.process.image.sha256 is the Process Creation hash field that the independent pySigma backend maps; whether a tenant populates it is unproven, which the readiness test shows. If the tenant leaves it null the name arm still fires.
  • PowerQuery assumes: matches is case-insensitive by default, mirroring the CQL /i flag.
// HUNT: libgcrypt ELF execution or PoeLLM sample hash
// MITRE: T1059.004, T1036.005
// CONF: high  FP: low  COST: low | REQUIRES: Falcon Linux sensor, ProcessRollup2
// FALSE POSITIVES: the genuine libgcrypt is a shared object named libgcrypt.so.N and is loaded, not executed; an exact-name executable is not expected
// LOOKBACK: 30d (set in the console time picker)
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ event_platform=Lin
| (FileName=/^libgcrypt$/i or SHA256HashData=6fab94577364beec314afae3b082dd680933f08a8349b9f35b92667e8231b501)
| table([@timestamp, aid, ComputerName, FileName, ImageFileName, CommandLine, ParentBaseFileName, SHA256HashData])
| sort(@timestamp, order=desc)
Q5 · AI/dev service spawning a shell or downloader (exploitation aftermath)
CONF MEDIUMFP MEDIUMCOST MEDIUM

Looks for: A LiteLLM (Python/uvicorn), Gotenberg, Gitea or Ollama parent spawning sh, bash, curl, wget or chmod. This is what a command-injection hit such as CVE-2026-42271 looks like on the host after the crafted POST tells the target to fetch a payload. FP: Gitea legitimately spawns sh for git hooks, and Python apps shell out for health checks; scope to hosts running the exposed AI services and exclude known hook and health-check command lines.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: A shell spawned by a grandchild of the service (for example through an intermediate wrapper) is not matched because only the direct creator is tested.
  • PowerQuery assumes: tgt.process.image.sha256 is the Process Creation hash field that the independent pySigma backend maps; whether a tenant populates it is unproven, which the readiness test shows. It is shown for triage only; it does not affect matching.
  • PowerQuery assumes: matches is case-insensitive by default, mirroring the CQL /i flag.
// HUNT: AI or dev service spawning a shell or downloader
// MITRE: T1190, T1059.004, T1105
// CONF: medium  FP: medium  COST: medium | REQUIRES: Falcon Linux sensor, ProcessRollup2 with ParentBaseFileName
// FALSE POSITIVES: Gitea git hooks, Python health checks, container entrypoint scripts
// TUNING: scope to a host group of exposed AI service servers and add a line such as | CommandLine!=/healthcheck|githooks/i after reviewing 7 days of hits; keep curl, wget and chmod children unexcluded
// LOOKBACK: 14d (set in the console time picker)
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ event_platform=Lin
| ParentBaseFileName=/^(python3?(\.[0-9]+)?|uvicorn|gunicorn|litellm|gotenberg|gitea|ollama)$/i
| FileName=/^(sh|bash|dash|curl|wget|chmod|busybox)$/i
| table([@timestamp, aid, ComputerName, ParentBaseFileName, FileName, CommandLine, SHA256HashData])
| sort(@timestamp, order=desc)
Q6 · Payload fetch from a C2 on port 81 or the /private/ tool paths
CONF HIGHFP LOWCOST LOW

Looks for: curl, wget, shells or Python fetching from host:81/ or the /private/bins.sh and /private/python3.6 paths Lumen saw on PoeLLM C2s. Victims are told to download from port 81 on the C2.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: A fetch performed in-process by a language runtime without a curl or wget command line is not captured.
  • PowerQuery assumes: tgt.process.image.sha256 is the Process Creation hash field that the independent pySigma backend maps; whether a tenant populates it is unproven, which the readiness test shows. It is shown for triage only; it does not affect matching.
  • PowerQuery assumes: matches is case-insensitive by default, mirroring the CQL /i flag.
// HUNT: Payload fetch from a C2 on port 81 or the /private/ tool paths
// MITRE: T1105, T1059.004
// CONF: high  FP: low  COST: low | REQUIRES: Falcon Linux sensor, ProcessRollup2 with CommandLine
// FALSE POSITIVES: an internal web service legitimately served on port 81
// LOOKBACK: 30d (set in the console time picker)
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ event_platform=Lin
| FileName=/^(curl|wget|sh|bash|dash|busybox|python3?)$/i
| CommandLine=/:81\/|\/private\/(bins\.sh|python3\.6)/i
| table([@timestamp, aid, ComputerName, FileName, CommandLine, ParentBaseFileName, SHA256HashData])
| sort(@timestamp, order=desc)
Q7 · Egress to the PoeLLM beacon ports on public addresses
CONF LOWFP HIGHCOST MEDIUM

Looks for: Outbound Linux connections to ports 3778, 5001, 5002, 9999 or 81 on non-private addresses, grouped per host and destination. Lumen lists these as the beacon ports and the payload download port, but 5001 and 9999 are common, so use this to find rare destinations, not as an alert. FP: 5001 and 9999 are used by many legitimate services; review only destinations seen from one or a few hosts and exclude your own vendor and cloud ranges.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: Low-confidence, high-noise hunt by design: legitimate services on these ports will appear until a baseline exclusion is applied.
  • PowerQuery assumes: estimate_distinct is probabilistic, so the host count can differ slightly from the CQL distinct count, which LogScale also documents as an estimate on very large data.
  • PowerQuery assumes: dst.port.number is stored as a number, so the comparison uses numeric literals.
  • PowerQuery assumes: net_ipsubnet performs the same private-range exclusion as the CQL cidr list.
// HUNT: Egress to PoeLLM beacon ports on public addresses
// MITRE: T1571, T1071
// CONF: low  FP: high  COST: medium | REQUIRES: Falcon Linux sensor, NetworkConnectIP4
// FALSE POSITIVES: legitimate services on 5001, 9999 and 81 (storage gateways, admin consoles, internal tools)
// TUNING: after a 14 day baseline exclude each sanctioned destination with | !in(field=RemoteAddressIP4, values=["REPLACE_WITH_SANCTIONED_IP"]) and keep only destinations contacted by fewer than 3 hosts
// LOOKBACK: 14d (set in the console time picker)
#event_simpleName=NetworkConnectIP4 event_platform=Lin
| RemotePort=/^(3778|5001|5002|9999|81)$/
| !cidr(RemoteAddressIP4, subnet=["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16","127.0.0.0/8","169.254.0.0/16"])
| groupBy([RemoteAddressIP4, RemotePort], function=[count(as=connections), count(aid, distinct=true, as=hosts)])
| sort(hosts, order=asc)
| table([RemoteAddressIP4, RemotePort, hosts, connections])
Q8 · Compromised host acting as scanner or exploit worker (fan-out to 3000, 4000, 22)
CONF MEDIUMFP MEDIUMCOST MEDIUM

Looks for: A single Linux host contacting many distinct public addresses on 3000 (Gotenberg), 4000 (LiteLLM) or 22 (SSH). PoeLLM turns victims into scanning and exploit workers and has been seen directing distributed brute force at SSH and login portals. FP: legitimate scanners, bastion or jump hosts and CI runners fan out the same way; exclude them by aid or host group.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: A slow scan spread over more than the lookback window stays under the threshold.
  • PowerQuery assumes: estimate_distinct is probabilistic, so the target count near the threshold of 24 can differ slightly from the CQL distinct count, which LogScale also documents as an estimate on very large data.
  • PowerQuery assumes: dst.port.number is stored as a number, so the comparison uses numeric literals.
// HUNT: Scanner or exploit worker fan-out to ports 3000, 4000 and 22
// MITRE: T1595.002, T1046, T1110
// CONF: medium  FP: medium  COST: medium | REQUIRES: Falcon Linux sensor, NetworkConnectIP4
// FALSE POSITIVES: sanctioned vulnerability scanners, jump hosts, CI runners, uptime monitors
// TUNING: exclude sanctioned scanner and jump host aids with | !in(aid, values=["REPLACE_WITH_AID"]) and raise the threshold if the baseline is higher
// LOOKBACK: 24h (set in the console time picker)
#event_simpleName=NetworkConnectIP4 event_platform=Lin
| RemotePort=/^(22|3000|4000)$/
| !cidr(RemoteAddressIP4, subnet=["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16","127.0.0.0/8","169.254.0.0/16"])
| groupBy([aid, ComputerName, RemotePort], function=[count(RemoteAddressIP4, distinct=true, as=distinctTargets), count(as=connections)])
| distinctTargets > 24
| sort(distinctTargets, order=desc)
| table([aid, ComputerName, RemotePort, distinctTargets, connections])
Q9 · Cryptominer execution on Linux (XMRig and stratum command lines)
CONF MEDIUMFP LOWCOST LOW

Looks for: Processes named xmrig or command lines with stratum+tcp, stratum+ssl or XMRig-only flags. PoeLLM ships XMRig and a second miner called Iron; Lumen publishes no Iron binary name, so only XMRig is matched by name. XMRig is a public tool, so this is detect only.

Validation: static-reviewedEquivalence: equivalent-with-schema-assumptionsProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: A miner renamed and launched with a configuration file instead of command-line flags matches neither arm.
  • PowerQuery assumes: tgt.process.image.sha256 is the Process Creation hash field that the independent pySigma backend maps; whether a tenant populates it is unproven, which the readiness test shows. It is shown for triage only; it does not affect matching.
  • PowerQuery assumes: matches is case-insensitive by default, mirroring the CQL /i flag.
// HUNT: Cryptominer execution on Linux (XMRig and stratum command lines)
// MITRE: T1496
// CONF: medium  FP: low  COST: low | REQUIRES: Falcon Linux sensor, ProcessRollup2
// FALSE POSITIVES: sanctioned mining or benchmarking on a lab host
// LOOKBACK: 30d (set in the console time picker)
#event_simpleName=/^(ProcessRollup2|SyntheticProcessRollup2)$/ event_platform=Lin
| (FileName=/^xmrig$/i or CommandLine=/stratum\+(tcp|ssl)|--donate-level|--cpu-priority/i)
| table([@timestamp, aid, ComputerName, FileName, CommandLine, ParentBaseFileName, SHA256HashData])
| sort(@timestamp, order=desc)
Q10 · Exposure inventory: Linux hosts listening on 3000, 4000 or 11434
CONF LOWFP HIGHCOST LOW

Looks for: Which Linux hosts listen on Gotenberg (3000), LiteLLM (4000) or the Ollama default (11434, not named in the cited sources, included for exposure checking only) on a non-loopback address. This finds the attack surface, not compromise. FP: every legitimate instance matches; use the result as an inventory to check against what is actually reachable from the internet.

Validation: static-reviewedEquivalence: unsupported-without-redesignProfiles: sentinelone-endpoint-ocsf
Known limitations and deployment notes
  • PowerQuery: SentinelOne listening-port inventory is not covered by this pack; run the CQL tab on Falcon or query the application inventory.
// HUNT: Exposure inventory of hosts listening on 3000, 4000 or 11434
// MITRE: T1190
// CONF: low  FP: high  COST: low | REQUIRES: Falcon Linux sensor, NetworkListenIP4
// FALSE POSITIVES: every sanctioned LiteLLM, Gotenberg, Gitea or Ollama instance, and unrelated apps on port 3000
// TUNING: compare the list to your external attack-surface scan and exclude hosts that are provably internal-only
// LOOKBACK: 7d (set in the console time picker)
#event_simpleName=NetworkListenIP4 event_platform=Lin
| LocalPort=/^(3000|4000|11434)$/
| LocalAddressIP4!=127.0.0.1
| groupBy([aid, ComputerName, LocalAddressIP4, LocalPort], function=count(as=listenEvents))
| table([aid, ComputerName, LocalAddressIP4, LocalPort, listenEvents])
09

CrowdStrike Custom IOA Recommendations

IOA namePatternExclusionsDeployment
PoeLLM-libgcrypt-ExecLinux process creation where the image file name is an exact libgcrypt with no .so suffixNone expectedHost group: Linux servers; Action: Detect
PoeLLM-ServiceSpawnsShellLinux process creation of sh, bash, curl or wget whose parent is the LiteLLM Python process, Gotenberg, Gitea or OllamaGitea git hooks; sanctioned health checksHost group: exposed AI service servers; Action: Detect
PoeLLM-C2-Port81-FetchProcess creation of curl or wget with a command line containing :81/Internal services on port 81Host group: Linux servers; Action: Detect
PoeLLM-Miner-CmdlineCommand line containing stratum+tcp or stratum+sslSanctioned mining labHost group: all Linux; Action: Detect
PoeLLM-Kryptex-EgressNetwork connection to the two Kryptex endpoint and port pairs in section 4None expected on serversHost group: Linux servers; Action: Detect

All IOAs ship as Detect. Promoting any of them to Prevent needs a second, independent source or confirmed hits from your own telemetry. XMRig is a public miner and must never be prevented by name or hash.

10

Machine-Readable IOC Appendix

Falcon IOC Management CSVbulk import · 18 rows · all detect
type,value,action,severity,expiration,description,tags
ipv4,92.119.164.50,detect,high,2027-04-08,PoeLLM active C2 as of Lumen publication (first seen 2026-07-23),campaign:CantoIncognito;malware:PoeLLM
ipv4,103.249.201.108,detect,high,2027-04-08,PoeLLM active C2 as of Lumen publication (first seen 2026-08-13),campaign:CantoIncognito;malware:PoeLLM
ipv4,178.128.14.204,detect,high,2027-04-08,PoeLLM active C2 as of Lumen publication (first seen 2026-06-16),campaign:CantoIncognito;malware:PoeLLM
ipv4,191.37.28.160,detect,medium,2027-01-08,PoeLLM historical C2 (April 13 to May 16, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,89.39.253.46,detect,medium,2027-01-08,PoeLLM historical C2 (April 14 to June 24, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,120.224.114.212,detect,medium,2027-01-08,PoeLLM historical C2 (May 9 to September 8, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,5.78.73.122,detect,medium,2027-01-08,PoeLLM historical C2 (June 8 to August 22, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,15.204.178.28,detect,medium,2027-01-08,PoeLLM historical C2 (June 14 to August 17, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,92.119.165.74,detect,medium,2027-01-08,PoeLLM historical C2 (July 1 to July 23, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,45.133.73.28,detect,medium,2027-01-08,PoeLLM historical C2 (July 18 to July 22, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,185.132.53.158,detect,medium,2027-01-08,PoeLLM historical C2 (July 19 to September 12, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,136.148.69.233,detect,medium,2027-01-08,PoeLLM historical C2 (September 12 to September 25, 2026). Compromised router or VPS: may be reassigned,campaign:CantoIncognito;malware:PoeLLM;status:historical
ipv4,57.131.5.211,detect,medium,2027-01-08,Server hosting malwarescan.xyz contacted by the first C2 (port 80),campaign:CantoIncognito;malware:PoeLLM
domain,malwarescan.xyz,detect,medium,2027-01-08,Domain registered February 2026 on likely operator-owned infrastructure,campaign:CantoIncognito;malware:PoeLLM
ipv4,5.180.174.162,detect,medium,2027-01-08,Kryptex mining endpoint (port 8029) contacted by PoeLLM victims. Shared third-party service,campaign:CantoIncognito;role:mining-pool
ipv4,46.21.245.211,detect,medium,2027-01-08,Kryptex mining endpoint (port 7029) contacted by PoeLLM victims. Shared third-party service,campaign:CantoIncognito;role:mining-pool
domain,edge-ru-07.kryptex.network,detect,medium,2027-01-08,Kryptex node hostname for 46.21.245.211 contacted by PoeLLM victims,campaign:CantoIncognito;role:mining-pool
sha256,6fab94577364beec314afae3b082dd680933f08a8349b9f35b92667e8231b501,detect,high,2027-04-08,PoeLLM ELF sample named libgcrypt (single source: Lumen),campaign:CantoIncognito;malware:PoeLLM
SentinelOne IOC importnot included

This pack does not ship a SentinelOne import block: the import format could not be verified against SentinelOne's own documentation. Export a sample from your console and the block can be added with confidence.

Behavioral Signatureshunt, not import
# Poem dead drop (Lumen)
repo        : github.com/ejejejdfbbebe  (fork of the nodejs.org source)
file        : dash.css
poem title  : On the Nature of Connection
anchors     : "In the silent hum of " | "each pulse of " | "Beyond the wall of " | "of distant servers"
rotation    : only the four key words change; the parsing pattern stays fixed

# Exploit and staging
LiteLLM path: /mcp-rest/test/connection   (CVE-2026-42271)
download    : target told to fetch from C2 port 81
URL paths   : hxxp://5.78.73[.]122:81/private/bins.sh
              hxxp://5.78.73[.]122:81/private/python3.6

# Network
beacon ports: 3778, 5001, 5002, 9999
scan ports  : 3000 (Gotenberg), 4000 (LiteLLM), plus SSH and login portals
miner pools : 5.180.174.162:8029, 46.21.245.211:7029
Named Malware and Toolingcontext
campaign    : Canto Incognito   (Lumen Black Lotus Labs)
malware     : PoeLLM
payload     : ELF named libgcrypt  (sha256 in the CSV)
capabilities: remote shell, HTTP/S scanning, exploit delivery
miners      : XMRig (public tool, detect only), Iron (no binary name published)
pool        : Kryptex
attribution : Italian-speaking actor, moderate confidence
Patch and Exposure Auditchecklist
[ ] LiteLLM: patched for CVE-2026-42271 (confirm fixed version in the vendor advisory)
[ ] Ivanti Sentry: patched for CVE-2026-10520
[ ] Gotenberg on 3000, LiteLLM on 4000, Ollama listener: not reachable from the internet
[ ] Gitea: current release, not exposed without authentication and MFA
[ ] Boa-based edge routers: admin pages not exposed (CVE-2018-21027, CVE-2018-21028
    are named for the first C2 router, not as actor exploits)
[ ] Egress from AI service hosts restricted to required destinations
[ ] SSH: key-only auth, source-restricted
11

Detection Validation Gates

GateCheckPass criteria
Telemetry readyProcess creation, network connections, listening ports and DNS lookups flowing for the AI and dev service hosts, container hosts included (Falcon Linux sensor: ProcessRollup2, NetworkConnectIP4, NetworkListenIP4, DnsRequest)Each event type returns rows for those aids in the last 24h
Benign baselineRun Q5, Q7, Q8 and Q10 for 7 to 14 days; build the allowlist for Gitea hooks, jump hosts, scanners and sanctioned destinationsDocumented exclusions before any alerting
Positive testOn a lab Linux host copy a harmless binary to a file named libgcrypt and run it; run curl against a lab web server on port 81; run a sleep via a shell launched from a Python parentQ4, Q6 and Q5 fire
Atomic sweepRun Q1, Q2 and Q3 over 30 daysZero hits in a clean estate; any hit on an active IP is an incident
PromotionMove IOAs from Detect only after the baseline; keep every PoeLLM IOA at Detect unless a second independent source confirmsWritten sign-off per IOA
12

Hardening: Tiered

Immediate (0 to 72h)
  • Remove internet exposure of LiteLLM (4000), Gotenberg (3000), Ollama and Gitea admin surfaces: bind to loopback or a private interface and publish only through an authenticating reverse proxy or VPN. M1035 Limit Access to Resource Over Network, M1030 Network Segmentation; CIS Controls v8 4.4 (server firewall); Gotenberg's own install guide warns against internet exposure.
  • Patch LiteLLM for CVE-2026-42271 and Ivanti Sentry for CVE-2026-10520, and update Gitea, Gotenberg and Ollama to current releases. Take the fixed version from the vendor advisory (not stated in the cited sources). M1051 Update Software, M1016 Vulnerability Scanning.
  • Interim LiteLLM control until patched: deny /mcp-rest/test/connection at the reverse proxy (playbook 3). M1050 Exploit Protection; ⚠ best-practice, no formal benchmark.
  • Run Q1 to Q10; if any host hits, treat it as compromised and rotate the LiteLLM master key and every upstream model-provider key stored on it.
Near term (this week)
  • Egress control: default-deny outbound for AI service hosts with an allowlist for the model providers and package mirrors they truly need. This removes mining-pool, C2 and scan traffic regardless of which IP the poem names. M1037 Filter Network Traffic; CIS Controls v8 13.4 and 4.4.
  • Container and process hardening: non-root user, read-only root filesystem, noexec temp storage, dropped capabilities, no-new-privileges (playbook 2). M1038 Execution Prevention, M1048 Application Isolation and Sandboxing; NIST SP 800-190, CIS Docker Benchmark.
  • Deploy the section 9 IOAs in Detect on the Linux fleet.
  • SSH: key-only authentication, restrict by source, disable root login. This blunts the experimental brute-force capability. M1032 Multi-factor Authentication, M1036 Account Use Policies; CIS Linux Benchmark SSH section.
Strategic
  • Add AI/LLM and developer tooling to attack surface management and the patch cycle with named owners, as Lumen recommends. M1016 Vulnerability Scanning; CIS Controls v8 7.1 and 12.
  • Consider a managed SASE or private access layer so self-hosted AI services never face the internet. M1035.
  • Keep edge routers and IoT devices patched and rebooted on a schedule; PoeLLM reused routers with vulnerable admin pages as C2 hosts. M1051; vendor hardening guidance.
  • Automate egress allowlist drift review and alert on first-time public destinations from AI service hosts.
13

Deployable Playbooks

1 · Exposure inventory (read-only)

#!/bin/bash
# Prerequisites: shell on the host; iproute2 (ss); docker CLI if containers are used.
# Reboot required: no
# Rollback: none required, read-only.
ss -H -ltn | awk '$4 ~ /:(3000|4000|11434)$/ {print "LISTEN", $4}'
docker ps --format '{{.Names}} {{.Ports}}' 2>/dev/null | grep -E '(3000|4000|11434)'
# Anything shown as 0.0.0.0 or [::] is reachable from every network the host is on.

2 · Harden the container for LiteLLM or Gotenberg (compose fragment)

# Prerequisites: a copy of the current compose file (cp compose.yml compose.yml.bak); a reverse proxy
#   with authentication already in front of the service; test in staging, the app may need extra writable paths.
# Reboot required: no (container is recreated, brief service interruption).
# Rollback: cp compose.yml.bak compose.yml && docker compose up -d
services:
  litellm:
    ports:
      - "127.0.0.1:4000:4000"      # loopback only; publish through the authenticating proxy
    user: "10001:10001"
    read_only: true
    tmpfs:
      - /tmp:rw,noexec,nosuid,size=256m
    cap_drop: [ALL]
    security_opt:
      - no-new-privileges:true

3 · Interim deny for the LiteLLM test-connection endpoint (nginx reverse proxy)

# Prerequisites: LiteLLM sits behind nginx; confirm nobody legitimately uses the MCP test-connection feature.
#   This is a stop-gap for CVE-2026-42271, not a patch.
# Reboot required: no (nginx reload).
# Rollback: remove the location block, then nginx -t && systemctl reload nginx
location = /mcp-rest/test/connection {
    return 403;
}

4 · Restrict the service ports to an admin range (nftables)

# Prerequisites: nftables; out-of-band or console access (a wrong rule can lock you out);
#   replace REPLACE_WITH_ADMIN_CIDR. Docker-published ports bypass INPUT: bind to 127.0.0.1 (playbook 2) or use DOCKER-USER.
# Reboot required: no (runtime rules; persist in /etc/nftables.conf after testing).
# Rollback: nft delete table inet poellm_expose
nft add table inet poellm_expose
nft add chain inet poellm_expose input '{ type filter hook input priority -10; policy accept; }'
nft add rule inet poellm_expose input tcp dport '{ 3000, 4000, 11434 }' ip saddr != REPLACE_WITH_ADMIN_CIDR drop

5 · Log-only watch on the three active C2 addresses (no blocking)

# Prerequisites: nftables; kernel log or journald collected by your SIEM.
# Reboot required: no.
# Rollback: nft delete table inet poellm_watch
# Log only, not drop: these indicators are single-sourced (Lumen). Promote to drop after a second
# independent source or your own confirmed hits.
cat <<'EOF' | nft -f -
table inet poellm_watch {
  chain out {
    type filter hook output priority 0; policy accept;
    ip daddr { 92.119.164.50, 103.249.201.108, 178.128.14.204 } log prefix "poellm-c2 " counter
  }
}
EOF

6 · Verify

# Exposure gone: from an external vantage point, ports 3000, 4000 and the Ollama listener must not answer.
# Hardening in place:
docker inspect --format '{{.HostConfig.ReadonlyRootfs}} {{.HostConfig.CapDrop}}' litellm
# Behavior gone: re-run Q5 and Q10 in Falcon; Q10 should list only intended listeners.

Nothing in these playbooks blocks a PoeLLM indicator by IP, domain or hash. That is deliberate: every indicator is single-sourced, so network blocking of them is left to your own judgment and to Lumen's disruption of the C2s.

14

Containment Runbook

PhaseActionsOwnerEvidence
IsolateNetwork-contain the host in Falcon; remove public exposure of the service (playbooks 2 and 4); do not power off, to keep memorySOC + InfraContainment timestamp, firewall change record
Isolate: by platformCrowdStrike: network-contain the host. SentinelOne: network quarantine (Disconnect from Network; confirm the label in your console version). Keep the host powered on for memory capture on all of them.SOC + InfraContainment timestamp, firewall change record
PreserveCapture process list, ss -tanp, the executable behind any suspect PID (/proc/PID/exe), reverse-proxy and application logs, and the exploit request (POST to /mcp-rest/test/connection or the equivalent)IRHashes of artifacts, log exports
ScopeRun Q1 to Q10 estate-wide for 30 days; check which other hosts show fan-out (Q8) or Kryptex contact (Q3); the infected host may have been used to attack othersIR + Threat huntingAffected aid list
EradicateKill the miner and libgcrypt process, remove the binary, review cron, systemd and shell profiles even though the sources document no persistence; rebuild from a clean image rather than clean in place when root was obtainedInfraRebuild record, clean verification scan
CredentialsRotate the LiteLLM master key, upstream model-provider API keys, Gitea tokens, and any secret stored on or reachable from the host; review provider billing for unauthorised usagePlatform + SecurityRotation log, billing review
RecoverRedeploy patched and hardened (section 12), behind an authenticating proxy, with egress allowlist; confirm Q5 and Q10 are cleanInfraVersion and config proof
MonitorKeep IOAs in Detect; re-run Q1 weekly since the poem rotates C2s; watch Lumen's GitHub IOC page for new addressesSOCWeekly hunt results
15

Detection Coverage Map

TechniqueBehaviorCQLIOACrowdStrike coverageSentinelOne
T1059.004 / T1036.005libgcrypt ELF or known hash executesQ4PoeLLM-libgcrypt-ExecGoodGood, with assumptions
T1496Mining pool egress, DNS, miner processQ2, Q3, Q9PoeLLM-Kryptex-Egress, PoeLLM-Miner-CmdlineGoodGood, with assumptions
T1105Fetch from C2 port 81 or /private/ pathsQ6PoeLLM-C2-Port81-FetchGoodGood, with assumptions
T1190 / T1059.004Service spawns shell or downloader after exploitationQ5PoeLLM-ServiceSpawnsShellPartialPartial: same limit as CrowdStrike
T1071 / T1571 / T1584.008C2 IP contact and beacon portsQ1, Q7IOC importPartialPartial: same limit as CrowdStrike
T1595.002 / T1046 / T1110Scanner and brute-force fan-outQ8n/aPartialPartial: same limit as CrowdStrike
T1190 (exposure)Vulnerable services reachableQ10n/aPartialGAP
T1190 (the exploit request itself)Crafted POST to the servicenonen/aGAPGAP
T1102.001Poem fetch from GitHubnonen/aGAPGAP
Persistence / file writeNot documented in sources; no ELF-write query shippednonen/aGAPGAP
Iron miner, Ivanti Sentry hostNo binary name published; appliance has no sensornonen/aGAPGAP

Coverage gaps: the exploit request and the GitHub poem fetch are network and application events that the Falcon sensor does not record; close them with reverse-proxy logs and proxy or TLS-inspection URL logs (section 7). Lumen documents no persistence mechanism and no Iron binary name, and the Ivanti Sentry appliance cannot run a sensor, so those are open. Because the poem rotates the C2 address, Q1 is a retro-hunt; Q3, Q4, Q5, Q6 and Q8 are the durable detections. Validation: see section 11.

16

Hunt Summary Ticket

TITLE      : PoeLLM / Canto Incognito (Lumen Black Lotus Labs)
SEVERITY   : High. Active botnet, 3,400+ victims, exploits internet-facing AI and dev services (Linux)
SCOPE      : Linux servers running LiteLLM, Ollama, Gotenberg, Gitea; Ivanti Sentry (no sensor)
HYPOTHESIS : Exposed service exploited (LiteLLM CVE-2026-42271) -> payload from C2 port 81 -> ELF libgcrypt -> XMRig/Iron to Kryptex -> host reused as scanner
QUERIES    : Q1 C2 sweep | Q2 DNS | Q3 Kryptex egress | Q4 libgcrypt/hash | Q5 service spawns shell | Q6 port-81 fetch | Q7 beacon ports | Q8 fan-out | Q9 miner | Q10 exposure
DO FIRST   : Find and hide exposed 3000/4000/Ollama/Gitea/Sentry; patch CVE-2026-42271 and CVE-2026-10520; run Q3-Q6 and Q8 over 30d
FINDINGS   : <fill from hunt>
GAPS       : Exploit request and GitHub poem fetch outside endpoint telemetry; no persistence or Iron binary published; Sentry has no sensor
ACTIONS    : Deploy IOAs (sect 9, all Detect); import CSV as detect only; egress allowlist; rotate LiteLLM and provider keys on any hit
OWNER      : HuntPack
VERSION    : v0.3 · 2026-10-09
17

Changelog

v0.32026-10-09Added an isolation row (s14) and a SentinelOne coverage column (s15). The query heading and the telemetry wording now name every platform rather than only CrowdStrike. Fixed Q7 and Q8: the CQL called dcount, which LogScale does not have, and now uses count with distinct=true, and the SentinelOne queries move the private-range exclusion into a filter stage. The Q10 note was reworded.
v0.22026-10-08Added a language switch above the queries (CrowdStrike CQL or SentinelOne PowerQuery for every card at once) and a SentinelOne console box. Query content unchanged.
v0.12026-10-08Initial HuntPack for the PoeLLM malware and Canto Incognito campaign. 10 CQL queries built on Falcon Linux sensor telemetry (ProcessRollup2, NetworkConnectIP4, NetworkListenIP4, DnsRequest), native hunts, five detect-only custom IOA recommendations, tiered hardening, playbooks and containment. Ships 18 atomic indicators, all detect, all traced to the Lumen report; none prevent because every indicator is single-sourced. SentinelOne PowerQuery tabs added to Q1-Q10: SIEM Query Rosetta release 0.1.0 (public-beta; static-reviewed translations).
18

References

TierSourceUsed forAccess date
ResearchLumen Black Lotus Labs: Canto incognito: tracking the PoeLLM malwarePrimary intel: campaign, mechanism, IOCs, ports, CVEs2026-10-08
ReportingThe Hacker News: PoeLLM infects 3,400+ serversCorroboration: victim count, targets, repo name, attribution2026-10-08
ReportingHelp Net Security: cryptomining botnet hides C2 in a GitHub poemCorroboration: dash.css, endpoint path, ports, CVEs2026-10-08
FrameworkMITRE ATT&CK T1102.001 Dead Drop ResolverTechnique mapping for the poem C22026-10-08
FrameworkMITRE ATT&CK T1496 Resource HijackingTechnique mapping for mining2026-10-08

Generated 2026-10-09 by HuntPack · defensive hunt, detection and hardening content only