Contents
MITRE ATT&CK coverage — 20 techniques across 9 tactics
| Tactic / Technique | Name | Rules |
|---|---|---|
| Reconnaissance / T1595.002 | Vulnerability Scanning | MAL_Linux_GHOST_ComfyUI_Python_Kit (YARA, Detection); MAL_Linux_GHOST_check_comfyui_Scanner (YARA, Hunting); MAL_Linux_GHOST_get_all_ranges_CloudEnumerator (YARA, Hunting) |
| Execution / T1059.004 | Unix Shell | MAL_Linux_GHOST_Kit_Shell_Installer (YARA, Detection); MAL_Linux_GHOST_Hysteria_Operator_Wrapper (YARA, Hunting); MAL_Linux_GHOST_min1_DualTelegram_Wrapper (YARA, Hunting); MAL_Linux_GHOST_check_comfyui_Scanner (YARA, Hunting); MAL_Linux_GHOST_get_all_ranges_CloudEnumerator (YARA, Hunting); Suspicious LD_PRELOAD Set to Non-Standard Library Path (SIGMA, Hunting); Ncat Listener Creation on Linux Host (SIGMA, Hunting); GHOST Kit Distribution File Download from AEZA Hosting Range (SURICATA, Detection) |
| Execution / T1059.006 | Python | MAL_Linux_GHOST_ComfyUI_Python_Kit (YARA, Detection); SUSP_Linux_ComfyUI_PerformanceMonitor_Node_Registration (YARA, Hunting) |
| Persistence / T1543.002 | Systemd Service | MAL_Linux_GHOST_Hysteria_Operator_Wrapper (YARA, Hunting); GHOST Kit Camouflage Name in a Created File Path (Systemd Unit Names and inotify_guard) (SIGMA, Detection) |
| Persistence / T1554 | Compromise Host Software Binary | MAL_Linux_GHOST_ComfyUI_Python_Kit (YARA, Detection); SUSP_Linux_ComfyUI_PerformanceMonitor_Node_Registration (YARA, Hunting); ComfyUI Custom Node Python File With a PerformanceMonitor Path Prefix Created (SIGMA, Hunting) |
| Privilege Escalation / T1611 | Escape to Host | MAL_Linux_GHOST_Kit_Shell_Installer (YARA, Detection) |
| Stealth / T1014 | Rootkit | MAL_Linux_GHOST_libpam_cache_Rootkit_Family (YARA, Detection); MAL_Linux_GHOST_libpam_cache_Source (YARA, Detection); Suspicious Shared Library Created in PAM Security Directory (SIGMA, Detection); Auditd - PAM Security Library Directory File Creation by Non-Package-Manager (SIGMA, Hunting) |
| Stealth / T1027 | Obfuscated Files or Information | Suspicious Shared Library Created in PAM Security Directory (SIGMA, Detection) |
| Stealth / T1036.005 | Match Legitimate Resource Name or Location | GHOST Kit Camouflage Name in a Created File Path (Systemd Unit Names and inotify_guard) (SIGMA, Detection) |
| Stealth / T1480.002 | Mutual Exclusion | MAL_Linux_GHOST_Kit_Shell_Installer (YARA, Detection) |
| Stealth / T1564.001 | Hidden Files and Directories | MAL_Linux_GHOST_libpam_cache_Rootkit_Family (YARA, Detection) |
| Stealth / T1574.006 | Dynamic Linker Hijacking | MAL_Linux_GHOST_libpam_cache_Rootkit_Family (YARA, Detection); MAL_Linux_GHOST_libpam_cache_Source (YARA, Detection); MAL_Linux_GHOST_Kit_Shell_Installer (YARA, Detection); SUSP_Linux_ComfyUI_PerformanceMonitor_Node_Registration (YARA, Hunting); Linux LD_PRELOAD Persistence File Modification (SIGMA, Detection); Suspicious Shared Library Created in PAM Security Directory (SIGMA, Detection); Chattr Immutable Bit Set on Linux Persistence Target Paths (SIGMA, Detection); Suspicious LD_PRELOAD Set to Non-Standard Library Path (SIGMA, Hunting); Auditd - PAM Security Library Directory File Creation by Non-Package-Manager (SIGMA, Hunting); GHOST Kit Distribution File Download from AEZA Hosting Range (SURICATA, Detection) |
| Stealth / T1620 | Reflective Code Loading | memfd_create Syscall Outside a Java, Browser and Node Filter on Linux Server (SIGMA, Hunting) |
| Defense Impairment / T1222.002 | Linux and Mac Permissions | Chattr Immutable Bit Set on Linux Persistence Target Paths (SIGMA, Detection) |
| Discovery / T1018 | Remote System Discovery | MAL_Linux_GHOST_get_all_ranges_CloudEnumerator (YARA, Hunting) |
| Command and Control / T1102.002 | Bidirectional Communication | MAL_Linux_GHOST_min1_DualTelegram_Wrapper (YARA, Hunting); Telegram API TLS SNI Egress from an Internal Host (Reporting Channel Used by the GHOST Kit, Not Specific to It) (SURICATA, Hunting) |
| Command and Control / T1105 | Ingress Tool Transfer | GHOST Kit Distribution File Download from AEZA Hosting Range (SURICATA, Detection) |
| Command and Control / T1571 | Non-Standard Port | Ncat Listener Creation on Linux Host (SIGMA, Hunting); GHOST Cryptojacker Kit QUIC v1 Initial Egress to Candidate Hysteria Operator Ports 14433 to 14444 (SURICATA, Hunting); GHOST Cryptojacker Kit QUIC v1 Initial Inbound to Candidate Hysteria Listener Ports 14433 to 14444 (SURICATA, Hunting) |
| Command and Control / T1572 | Protocol Tunneling | MAL_Linux_GHOST_Hysteria_Operator_Wrapper (YARA, Hunting); Hysteria Proxy Process Execution on Linux Server (SIGMA, Hunting); GHOST Cryptojacker Kit QUIC v1 Initial Egress to Candidate Hysteria Operator Ports 14433 to 14444 (SURICATA, Hunting); GHOST Cryptojacker Kit QUIC v1 Initial Inbound to Candidate Hysteria Listener Ports 14433 to 14444 (SURICATA, Hunting) |
| Impact / T1496.001 | Compute Hijacking | MAL_Linux_GHOST_min1_DualTelegram_Wrapper (YARA, Hunting); memfd_create Syscall Outside a Java, Browser and Node Filter on Linux Server (SIGMA, Hunting); Telegram API TLS SNI Egress from an Internal Host (Reporting Channel Used by the GHOST Kit, Not Specific to It) (SURICATA, Hunting) |
Campaign: GHOST-Cryptojacker-Vova75Rus-77[.]110[.]96[.]200 Date: 2026-05-25 Author: The Hunters Ledger License: CC BY 4.0 Reference: https://the-hunters-ledger.com/reports/ghost-cryptojacker-vova75rus-77.110.96.200/
Sub-report context: This is the GHOST-kit-specific detection file. GHOST Case 9 is sub-report 1 of the parent series
ai-agent-frameworks-2026-05-23. The parent detection file (ai-agent-frameworks-2026-05-23-detections[.]md) covers cross-campaign rules for all five cases in that series. Rules here go deeper on Case 9 only. Do not duplicate parent-level general coverage.
Calibration Notes
The following corrections from the investigation apply to detection rule derivation and should be understood before deploying these rules:
T1556.003 mis-mapping retraction (Phase 7 → Phase 15 §23): The initial Phase 7 session-start framing categorized libpam_cache[.]so as a PAM authentication backdoor (T1556.003, Modify Authentication Process: PAM). Direct source-code inspection of the 98-line C source refutes this entirely: the file contains zero PAM symbols, zero pam_authenticate/pam_handle_t/pam_acct_mgmt references, and zero authentication-flow code. The correct technique mapping is T1014 (Rootkit) + T1574.006 (Dynamic Linker Hijacking) + T1564.001 (Hide Artifacts: Hidden Files and Directories) + T1027 (Obfuscated Files or Information). Detection rules in this file are mapped accordingly. No PAM-auth-backdoor detection logic applies.
VT “dropped_files” retraction: VT’s dropped_files relationship for ghost[.]sh (sha e943b581...) and min1[.]sh (sha 008bc5ab...) surfaces SHA-256s 44a3bab2c338e3bca24c00f7c3da1301eb4a5a889f1c667cc781e1bdacd3b9e7 and ac941ead01d5451a7a9fd4be4ba9b60b2d3e4138670ae868e655b3b393253227. Direct VT lookup confirms these are /var/log/auth.log.1.gz and /var/log/kern.log.1.gz, sandbox-host log archives the scripts touched during log-clearing tradecraft, NOT operator miner binaries. These hashes are excluded from detection rules and IOC feeds.
Prior public coverage calibration: The claim “first public documentation of GHOST kit” was retracted after user review. Censys (Mark Ellzey, 2026-04-07) is the primary public disclosure. This sub-report extends Censys coverage with: sibling host 77[.]110[.]125[.]145, byte-identical .so refuting per-victim compilation, full hide-string/hide-port inventory, Vova75Rus kit-author identity, OWNER Telegram bot supply-chain architecture, structured detection rules, and VT detection landscape snapshot (6-weeks post-Censys, AV community has still not shipped GHOST family signatures).
Detection Coverage Summary
GHOST is a commodity Linux cryptojacker kit distributed by kit-author Vova75Rus as a Bash-orchestrated installer suite (ghost[.]sh) with an LD_PRELOAD userland rootkit (libpam_cache[.]so), a Hysteria v2 covert-tunnel operator wrapper (hyst[.]sh), a miner-only installer with a kit-wide Telegram supply-chain callback (min1[.]sh), and a Python ComfyUI exploitation/persistence framework. This retiering pass re-sorts the original 30 rule objects (10 YARA, 12 Sigma, 8 Suricata alert objects across 6 published headings) into Detection/Hunting tiers, routes 5 atomic indicators already present in the IOC feed out of the rule set, and cuts 3 rule objects that fire on ubiquitous benign activity or were already retired.
| Rule Type | Detection | Hunting | MITRE Techniques Covered | Atomics → feed |
|---|---|---|---|---|
| YARA | 4 | 5 | T1014, T1574.006, T1564.001, T1059.004, T1611, T1480.002, T1102.002, T1496.001, T1059.006, T1595.002, T1554, T1543.002 | 1 |
| Sigma | 4 | 6 | T1574.006, T1027, T1014, T1554, T1571, T1059.004, T1543.002, T1036.005, T1222.002, T1620, T1572 | 1 |
| Suricata | 1 | 3 | T1059.004, T1574.006, T1105, T1572, T1571, T1102.002, T1496.001 | 3 |
Detection vs Hunting: Detection rules are high-fidelity and evasion-resilient, safe to alert on. Hunting rules are broader, for scoping and threat-hunting. Expect to review the hits.
Highest-confidence anchors:
/etc/ld.so.preloadwrite/create by a non-package-manager process (Sigma Detection): the single most durable signature in this file; the file’s modification is the persistent global-load trigger for GHOST’s LD_PRELOAD rootkit and has essentially no legitimate production-server use case.- The GHOST rootkit’s combined hook-export + hide-list-string + port-format-string + proc-hook fingerprint (YARA Detection): byte-identical across both known customer deployments, requiring a genuine recompile (not just a rename) to evade.
- The GHOST installer’s
_anti_hisanacompetitor-displacement function name (YARA Detection): unique to this kit family, confirmed via 16 cross-host Hunt.io hits.
Atomics routed to the IOC feed: the kit-author OWNER Telegram bot token prefix 8415540095 (and operator MIRROR bot 8315596543), the Kryptex/c3pool/nanopool mining-pool domains, and the Hysteria admin-panel host 77[.]110[.]96[.]200 were each the sole discriminator of one or more rules below; all five are already present in ghost-cryptojacker-vova75rus-77[.]110[.]96[.]200-iocs.json; no feed edits were required by this pass. Per the tiering rubric’s cryptojacker-specific guidance, a mining-pool domain or a kit-wide callback token is an atomic: a distinctive config/loader constant (like the rootkit’s hide-list array) is the durable anchor instead.
Retiering summary: 3 rule objects were cut outright: a pre-existing withdrawn Suricata signature (already retired 2026-06-19 for overbreadth), a redundant/misleadingly-labeled Telegram-SNI Suricata duplicate, and a Sigma inotify_add_watch rule that cannot express its intended path filter in a single detection block and as literally written fires on all inotify usage system-wide. One YARA rule (the dual-Telegram min1[.]sh wrapper) was salvaged via capability-abstraction: its condition no longer mandatorily gates on the kit-wide bot token, so it survives bot rotation. One Sigma rule (the ComfyUI PerformanceMonitor file-creation rule) was tightened to remove an overbroad selector branch that would have matched any legitimate custom-node installation, and was later re-tiered to Hunting because a benign extension of the same name still matches.
YARA Rules
/*
Yara Rule Set
Identifier: GHOST Cryptojacker Kit Family — Vova75Rus / 77.110.96.200
Author: The Hunters Ledger
Source: https://the-hunters-ledger.com/
License: CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/
*/
Detection Rules
MAL_Linux_GHOST_libpam_cache_Rootkit_Family
Tier: Detection
Robustness: 3
ATT&CK Coverage: T1014 (Rootkit), T1574.006 (Dynamic Linker Hijacking), T1564.001 (Hide Artifacts: Hidden Files and Directories)
Confidence: HIGH
Rationale: Byte-identical across all known GHOST kit customer deployments (SHA-256 eaaa10c8... on both 77[.]110[.]96[.]200 and 77[.]110[.]125[.]145). The combination of hook-function exports, hide-list array strings, and the hide-port format string is unique to this rootkit family and requires an actual recompile — not a rename — to evade. The ELF64 little-endian magic at offset 0 eliminates PE and script false positives; the rule does not test the ELF type (e_type), so an ELF64 executable carrying the same strings also passes.
False Positives: None known — the specific combination of readdir/fopen libc exports plus GHOST-specific hide-list strings (khugepaged_, nv_uvm_, inotify_guard, libpam_cache) does not appear in any legitimate shared library.
Blind Spots: A full kit-source recompile that renames every hide-list entry and hook export would evade; the rule targets the on-disk shared object, not a memory-only injected variant.
Validation: Scan the analyzed sample (hash1 below) — all clauses must match; a legitimate PAM module or unrelated shared library must NOT fire.
Deployment: Linux endpoint AV/EDR file scanning, auditd-triggered on-write scan of /lib/security/. Live process-memory scanning does not match: the condition’s filesize test is undefined there, so only files and saved dumps are scanned.
rule MAL_Linux_GHOST_libpam_cache_Rootkit_Family {
meta:
description = "Detects GHOST cryptojacker kit LD_PRELOAD rootkit libpam_cache.so — ELF64 file carrying the readdir and fopen hook exports (the 64-bit variants readdir64 and fopen64 are not tested) plus the hide-list strings used to hide miner processes, kit paths, and operator wallet prefixes from /proc listings; byte-identical across all known GHOST kit customer deployments"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
hash1 = "eaaa10c840de23335abae1a9ead0a6a7fb7be5187cd19ad05137feab12bb7301"
hash2 = "edafde0d33ff1a169c0c4eeaeec12d1759818c7cf4950fcee91c687e811e6cff"
hash3 = "296a800564111b0bad9fe63faf4e63ba"
family = "GHOST-cryptojacker-kit"
malware_type = "LD_PRELOAD Rootkit"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "ca987dcd-ca0e-5e71-a3b1-cab19fd7a851"
strings:
// Hook function exports — the four libc symbols this .so overrides
$export_readdir = "readdir" ascii fullword
$export_fopen = "fopen" ascii fullword
// GHOST-specific hide-list strings from H[] array — operator-deployment-path artifacts
$hide_khugepaged = "khugepaged_" ascii
$hide_nv_uvm = "nv_uvm_" ascii
$hide_inotify = "inotify_guard" ascii fullword
$hide_libpam_self = "libpam_cache" ascii
$hide_fontcpu = "fontconfig/.cpu" ascii
$hide_fontgpu = "fontconfig/.gpu" ascii
$hide_pid_guard = ".pid_guard" ascii
$hide_ghost_sh = "ghost.sh" ascii fullword
// LD_PRELOAD removal constructor — unsetenv called at load time
$unsetenv_preload = "LD_PRELOAD" ascii fullword
// Port-filter format string — uppercase hex zero-padded matching /proc/net/tcp native format
$port_fmt = ":%04X" ascii
// /proc hooking targets
$proc_net_tcp = "/proc/net/tcp" ascii
$proc_cmdline = "/proc/%s/cmdline" ascii
$proc_exe = "/proc/%s/exe" ascii
// ELF magic bytes for shared object detection (7f 45 4c 46 = ELF magic)
$elf_magic = { 7F 45 4C 46 02 01 01 00 }
condition:
// ELF64 little-endian file (magic + ELFCLASS64 + ELFDATA2LSB); e_type is not tested
$elf_magic at 0 and
// File size: 14,568 bytes exact for known sample; allow up to 50KB for compiled variants
filesize < 50KB and
// Require hook exports + multiple hide-list strings + port format string + proc hooks
($export_readdir and $export_fopen) and
$port_fmt and
($proc_net_tcp or $proc_cmdline or $proc_exe) and
($unsetenv_preload) and
3 of ($hide_*)
}
MAL_Linux_GHOST_libpam_cache_Source
Tier: Detection
Robustness: 3
ATT&CK Coverage: T1014 (Rootkit), T1574.006 (Dynamic Linker Hijacking)
Confidence: HIGH
Rationale: The 98-line C source libpam_cache.c is shipped alongside the compiled binary on the kit-author’s distribution server. Wording fix 2026-10-11: the Rationale used to list libc hook function names (readdir, fopen and the 64-bit forms) among the matched strings; the rule contains none, so they are removed from this sentence. The report says the source hooks those four functions, but the rule does not test for them. The combination matched is _GNU_SOURCE plus the RTLD_NEXT resolver plus the __attribute__((constructor)) and unsetenv("LD_PRELOAD") pattern plus the :%04X port format plus two of the three single-character helper declarations plus two of the three GHOST hide-list strings, which is unique and requires the same recompile-level effort to evade as Rule 1.
False Positives: None known — the specific combination of abbreviated single-char helper names (_sh, _ph, _fn) plus RTLD_NEXT resolver plus GHOST hide-list strings does not appear in legitimate PAM development.
Blind Spots: A rewritten source using different helper-function naming conventions and a fully rotated hide-list would evade; this rule only matches the source text, not the compiled binary (Rule 1 covers that).
Validation: Scan the analyzed sample (hash1 below) — all clauses must match; unrelated C source implementing RTLD_NEXT hooking (e.g., a legitimate LD_PRELOAD shim) without the GHOST hide-list strings must NOT fire.
Deployment: Linux endpoint file scanning, download directory scanning, web proxy content inspection.
rule MAL_Linux_GHOST_libpam_cache_Source {
meta:
description = "Detects GHOST cryptojacker kit LD_PRELOAD rootkit C source file libpam_cache.c — dense hand-written C with single-char helper declarations, an RTLD_NEXT resolver, an unsetenv LD_PRELOAD constructor, a port-format string and GHOST-specific hide-list contents (it does not test for the hooked libc function names); shipped alongside compiled .so on kit-author distribution server"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
modified = "2026-10-11"
hash1 = "edafde0d33ff1a169c0c4eeaeec12d1759818c7cf4950fcee91c687e811e6cff"
family = "GHOST-cryptojacker-kit"
malware_type = "LD_PRELOAD Rootkit Source"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "9f7d2a2c-c893-5f7f-a3c0-ab6fac644947"
strings:
// GNU source define enabling RTLD_NEXT
$gnu_source = "#define _GNU_SOURCE" ascii
// RTLD_NEXT hook resolution pattern
$rtld_next = "RTLD_NEXT" ascii fullword
// Constructor pattern — unsetenv called with LD_PRELOAD at constructor time
$constructor_attr = "__attribute__((constructor))" ascii
$unsetenv_call = "unsetenv(\"LD_PRELOAD\")" ascii
// Hook function identifiers (dense single-char style from this author's code)
$helper_sh = "static int _sh(" ascii
$helper_ph = "static int _ph(" ascii
$helper_fn = "static FILE *_fn(" ascii
// GHOST-specific hide-list entries in the H[] array
$hide_inotify = "inotify_guard" ascii fullword
$hide_khugepaged = "khugepaged_" ascii
$hide_ghost = "ghost.sh" ascii fullword
// Port filter format string
$port_fmt = ":%04X" ascii
condition:
// No ELF magic — this is C source text
filesize < 10KB and
$gnu_source and
$rtld_next and
$constructor_attr and
$unsetenv_call and
$port_fmt and
2 of ($helper_*) and
2 of ($hide_*)
}
MAL_Linux_GHOST_Kit_Shell_Installer
Tier: Detection
Robustness: 3
ATT&CK Coverage: T1059.004 (Unix Shell), T1611 (Escape to Host), T1480.002 (Mutual Exclusion), T1574.006 (Dynamic Linker Hijacking)
Confidence: HIGH
Rationale: The ghost[.]sh installer contains highly distinctive function names unique to the GHOST kit — particularly the container-escape suite (_container_escape, _escape_via_cgroup, _escape_via_mount, _escape_via_nsenter, _escape_via_socket), the competitor-displacement function _anti_hisana, and the rootkit-build function _compile_hide_so. These function names appear in no other known malware family and were confirmed via 16 Hunt.io cross-host hits.
False Positives: None known — the specific combination of _anti_hisana plus _container_escape-family functions plus _compile_hide_so/_install_preload plus the GHOST version banner is unique to GHOST kit deployments.
Blind Spots: A rebranded fork that renames the entire function inventory and drops the version banner would evade; the rule targets the installer script text, not runtime behavior.
Validation: Scan the analyzed sample (hash1 below) — all clauses must match; an unrelated Bash installer or container-escape PoC lacking the _anti_hisana function must NOT fire.
Deployment: Linux endpoint file scanning, download directory scanning, web proxy content inspection, email gateway.
rule MAL_Linux_GHOST_Kit_Shell_Installer {
meta:
description = "Detects GHOST cryptojacker kit primary Bash installer ghost.sh — 1338-line English-language Bash script containing GHOST v5.1/v6.0 codename banner, competitor-displacement function _anti_hisana, 4 container-escape variants, LD_PRELOAD rootkit build/install functions, and multi-vector persistence; function names unique to GHOST kit family"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
hash1 = "e943b58112f58517b95424dba9334bf97c5dc2dd2f069dca04b9e75b9fec56ba"
family = "GHOST-cryptojacker-kit"
malware_type = "Bash Installer/Orchestrator"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "e3af0826-0aba-54ee-90ae-f49c95fb66ba"
strings:
// GHOST kit version banners (in first-line comment of ghost.sh)
$banner_v51 = "GHOST v5.1" ascii
$banner_v60 = "GHOST v6.0" ascii
// Competitor-displacement function — kills Hisana kit (16 cross-host hits confirmed in Hunt.io)
$fn_anti_hisana = "_anti_hisana" ascii fullword
// Rootkit build/install functions
$fn_compile_so = "_compile_hide_so" ascii fullword
$fn_install_preload = "_install_preload" ascii fullword
// Container-escape suite — all 4 variants
$fn_container_esc = "_container_escape" ascii fullword
$fn_esc_cgroup = "_escape_via_cgroup" ascii fullword
$fn_esc_mount = "_escape_via_mount" ascii fullword
$fn_esc_nsenter = "_escape_via_nsenter" ascii fullword
$fn_esc_socket = "_escape_via_socket" ascii fullword
// Python kit builder function
$fn_build_py = "_build_python_fetcher" ascii fullword
// Resurrection watchdog function
$fn_resurrection = "_resurrection_loop" ascii fullword
condition:
filesize < 200KB and
($banner_v51 or $banner_v60) and
$fn_anti_hisana and
($fn_compile_so or $fn_install_preload) and
($fn_container_esc or ($fn_esc_cgroup and $fn_esc_mount) or ($fn_esc_nsenter and $fn_esc_socket)) and
($fn_build_py or $fn_resurrection)
}
MAL_Linux_GHOST_ComfyUI_Python_Kit
Tier: Detection
Robustness: 2
ATT&CK Coverage: T1059.006 (Python), T1595.002 (Active Scanning: Vulnerability Scanning), T1554 (Compromise Host Software Binary)
Confidence: HIGH
Rationale: The Python exploitation framework (py[.]py + scan[.]py) contains distinctive function names unique to the GHOST kit’s ComfyUI targeting component. _build_python_fetcher, the PerformanceMonitor fake-node class, and the PIP_PAYLOAD_REPO variable are not produced by legitimate ComfyUI development tooling, and the rule requires the class plus at least one config/registration marker plus a ComfyUI-specific fingerprint together.
False Positives: None known for the required combination; a single string (e.g. PerformanceMonitor alone, or 8188 alone) would carry meaningful FP risk in isolation, which is why none of them is a standalone anchor in the condition.
Blind Spots: A rebuild that renames PerformanceMonitor, drops PIP_PAYLOAD_REPO, and removes the ComfyUI port/stats fingerprint would evade.
Validation: Scan the analyzed sample (hash1/hash2/hash3 below) — must match; an unrelated legitimate ComfyUI custom node lacking the fetcher/config functions must NOT fire.
Deployment: Linux endpoint file scanning, ComfyUI custom_nodes directory scanning, download monitoring.
rule MAL_Linux_GHOST_ComfyUI_Python_Kit {
meta:
description = "Detects GHOST cryptojacker kit Python ComfyUI exploitation framework (py.py + scan.py) — Python scripts containing _build_python_fetcher downloader builder, PerformanceMonitor fake custom-node class, PIP_PAYLOAD_REPO GitHub URL config variable, and NODE_CLASS_MAPPINGS registration for ComfyUI persistence; 74KB+63KB kit shipped to both GHOST customer operators"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
hash1 = "dc232b55329d95fe2a47a8d637b7bffea06f18e3d8332ba94b042b1862213a1d"
hash2 = "9023734a70ee6a05d4ecd5466d0c5803f293601836deb00cc417a3add04bd93e"
hash3 = "6e5d897c7fd0060c7da2394ad1bb3584827c216f8aadac4f6ed41b2d915f0070"
family = "GHOST-cryptojacker-kit"
malware_type = "Python ComfyUI Exploitation Framework"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "a4d3ff71-b85c-58f2-9e0e-c6f9300289f1"
strings:
// Core exploitation functions unique to GHOST Python kit
$fn_build_fetcher = "_build_python_fetcher" ascii fullword
$fn_plant_node = "plant_backdoor_node" ascii fullword
$fn_find_nodes = "find_target_nodes" ascii fullword
// Fake custom-node class — persistence mechanism
$class_perfmon = "PerformanceMonitor" ascii fullword
// Kit supply-chain config variable
$pip_payload_repo = "PIP_PAYLOAD_REPO" ascii fullword
// ComfyUI node registration dicts
$node_mappings = "NODE_CLASS_MAPPINGS" ascii fullword
$node_display = "NODE_DISPLAY_NAME_MAPPINGS" ascii fullword
// ComfyUI targeting fingerprint
$comfyui_port = "8188" ascii
$comfyui_stats = "system_stats" ascii
condition:
filesize < 200KB and
($fn_build_fetcher or $fn_plant_node or $fn_find_nodes) and
$class_perfmon and
($pip_payload_repo or $node_mappings or $node_display) and
($comfyui_port or $comfyui_stats)
}
Hunting Rules
SUSP_Linux_ComfyUI_PerformanceMonitor_Node_Registration
Tier: Hunting (re-tiered from Detection 2026-09-13, see note below)
Robustness: 2
ATT&CK Coverage: T1554 (Compromise Host Software Binary), T1059.006 (Python), T1574.006 (Dynamic Linker Hijacking analog for Python runtime)
Confidence: MODERATE (downgraded from HIGH 2026-09-13)
Rationale: Wording fix 2026-10-11: the rule, its name (SUSP_Linux_ComfyUI_PerformanceMonitor_Node_Registration, was MAL_Linux_GHOST_ComfyUI_Fake_PerformanceMonitor_Node, with its UUIDv5 id) and its description called the match a fake or GHOST node, but the strings are the registration boilerplate that every ComfyUI extension uses, as the re-tiering note below says; it now names a PerformanceMonitor node registration. The static combination tested is class PerformanceMonitor and NODE_CLASS_MAPPINGS, plus either NODE_DISPLAY_NAME_MAPPINGS or the kit’s plant_backdoor_node function name, in a file under 500 KB. It matches the registration pattern the kit’s planted node uses wherever the file sits, but it is registration boilerplate and not malicious content, so hits are integrity-audit leads. Round 2 (2026-10-11): the earlier text called this a narrow detection of the malicious node and of post-compromise persistence, which the benign-node test below contradicts. Re-tiering note, 2026-09-13: confirmed by direct testing, not just reasoning, that a genuinely benign ComfyUI custom node (a real profiling extension named PerformanceMonitor, using the exact NODE_CLASS_MAPPINGS/NODE_DISPLAY_NAME_MAPPINGS boilerplate every legitimate ComfyUI extension must use) fires this rule with zero malicious content present. NODE_CLASS_MAPPINGS and NODE_DISPLAY_NAME_MAPPINGS are mandatory ComfyUI registration boilerplate, not something specific to this malware
False Positives: Confirmed, not merely Low. A synthetic benign ComfyUI custom node built specifically to test this (a real profiling class named PerformanceMonitor with no backdoor content) fires the rule. The rule’s own prior Blind Spots field already predicted this exact scenario; the tier and confidence now match that prediction instead of overriding it
Blind Spots: A legitimately-named “PerformanceMonitor” custom node from an unrelated, unvetted developer would still fire, treat a hit as a compromise indicator requiring publisher/source verification, not an automatic block
Validation: Scan a ComfyUI installation with the planted node present — must match; a stock ComfyUI installation with only official custom nodes must NOT fire. A benign extension that defines a class named PerformanceMonitor with the standard registration dictionaries also fires (confirmed 2026-09-13), so a hit needs publisher and source verification.
Deployment: ComfyUI custom_nodes directory file scan (scheduled or on-write), Linux endpoint EDR.
rule SUSP_Linux_ComfyUI_PerformanceMonitor_Node_Registration {
meta:
description = "Detects a file under 500 KB that defines class PerformanceMonitor and contains NODE_CLASS_MAPPINGS plus either NODE_DISPLAY_NAME_MAPPINGS or the kit function name plant_backdoor_node. This is the registration pattern the GHOST cryptojacker kit uses for its planted persistence node, but the rule tests no malicious content, so a benign ComfyUI extension of that name also matches (confirmed by test on 2026-09-13); use it as a hunt rule for ComfyUI custom-node integrity audits"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
modified = "2026-10-11"
family = "GHOST-cryptojacker-kit"
malware_type = "ComfyUI Custom Node Persistence Artifact"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "83b41b80-0cff-51a5-b77c-20831c55d118"
strings:
// Malicious custom-node class registration — both dict assignments required
$class_def = "class PerformanceMonitor" ascii
$node_class_reg = "NODE_CLASS_MAPPINGS" ascii fullword
$node_display_reg = "NODE_DISPLAY_NAME_MAPPINGS" ascii fullword
// Ghost kit function that installs the node
$fn_plant = "plant_backdoor_node" ascii fullword
condition:
filesize < 500KB and
$class_def and
$node_class_reg and
($node_display_reg or $fn_plant)
}
MAL_Linux_GHOST_Hysteria_Operator_Wrapper
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1572 (Protocol Tunneling), T1059.004 (Unix Shell), T1543.002 (Create or Modify System Process: Systemd Service)
Confidence: MODERATE
Rationale: Round 2 (2026-10-11): the meta description presented the match as the Russian-language operator wrapper with certificate generation and an admin callback; the condition needs none of those (a fixture of bing[.]com, two cache names and get[.]hy2[.]sh fires), so the description now says what the condition tests. Logic fix 2026-10-11: the installer string was named $hy2_installer, so the 2 of ($hy2_*) credential-cache clause also counted it, and one cache reference plus get[.]hy2[.]sh satisfied a clause this Rationale describes as two cache-file references. It is now $installer_hy2, outside that wildcard, and still counts in the last clause. A fixture with bing[.]com, one .hy2_ cache reference and get[.]hy2[.]sh matched the old rule and does not match the new one. Hysteria v2 is legitimate open-source software, and “bing[.]com” as an SNI-masquerade choice is a common domain-fronting convention used broadly across the censorship-circumvention tooling ecosystem — not unique to this operator. The rule’s real distinguishing power comes from requiring the mandatory bing[.]com string alongside two of the .hy2_password/.hy2_port/.hy2_uri credential-cache file references, but those cache filenames may originate from the upstream get[.]hy2[.]sh Hysteria installer itself rather than being GHOST-kit-bespoke, so a host that ran the vanilla Hysteria v2 installer for any legitimate tunneling purpose could plausibly satisfy this combination. Durable enough to hunt on, not tight enough to alert on.
False Positives: Legitimate Hysteria v2 deployments (VPN/censorship-circumvention use) that happen to use a bing[.]com-style SNI masquerade and are scanned alongside their own installer cache files; any host running the stock get[.]hy2[.]sh installer for non-malicious tunneling.
Deployment: Linux endpoint file scanning, download directory scanning; treat hits as a hunting lead requiring correlation with the operator wrapper’s Russian-language comments and the :3301 panel/api_vpn_report markers before escalation.
rule MAL_Linux_GHOST_Hysteria_Operator_Wrapper {
meta:
description = "Hunting rule for a file under 30 KB that contains bing.com, two of the three /tmp/.hy2_ cache file names, and one of the panel port 3301, get.hy2.sh, api_vpn_report or the Russian heading НАСТРОЙКИ. It was written from the GHOST kit Hysteria v2 operator wrapper hyst.sh, but it does not require Russian text, certificate generation or the panel callback (get.hy2.sh or the port alone satisfies the last clause), and bing.com SNI masquerade and the .hy2_ cache names are shared with legitimate Hysteria v2 deployments"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
modified = "2026-10-11"
hash1 = "822afb1fb29f22df8c951726d492021df2940223ed719881dafb40cda3894c5c"
family = "GHOST-cryptojacker-kit"
malware_type = "Hysteria v2 Installer Wrapper"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "13a9762c-4653-5feb-8227-fc15eea54a4a"
strings:
// Hysteria v2 bing.com SNI masquerade — common domain-fronting convention, not GHOST-exclusive
$sni_masquerade = "bing.com" ascii fullword
// Hysteria credential cache file pattern in /tmp
$hy2_password = ".hy2_password" ascii
$hy2_port = ".hy2_port" ascii
$hy2_uri = ".hy2_uri" ascii
// Admin panel port reference (3301 = Hysteria panel)
$panel_port = "3301" ascii
// Hysteria installer download source
$installer_hy2 = "get.hy2.sh" ascii
// Russian operator comments (Cyrillic — confirming operator-authored)
$ru_installs = "\xD0\x9D\xD0\x90\xD0\xA1\xD0\xA2\xD0\xA0\xD0\x99\xD0\x9A\xD0\x98" ascii // НАСТРОЙКИ
// Operator panel API callback function name
$api_vpn_report = "api_vpn_report" ascii fullword
condition:
filesize < 30KB and
$sni_masquerade and
2 of ($hy2_*) and
($panel_port or $installer_hy2 or $api_vpn_report or $ru_installs)
}
MAL_Linux_GHOST_min1_DualTelegram_Wrapper
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1102.002 (Web Service: Bidirectional Communication), T1059.004 (Unix Shell), T1496.001 (Resource Hijacking: Compute Hijacking)
Confidence: MODERATE
Rationale: Salvaged from the original condition. The prior version mandatorily gated on the kit-author OWNER Telegram bot token prefix 8415540095: — a single external identifier the kit author could rotate at zero cost, which would silently break detection for every future customer deployment (the bot token itself is an atomic, already carried in the IOC feed). This rewrite makes the bot token one of three independent paths: the token match (unchanged, still useful today), OR the paired bilingual Russian “TELEGRAM (OWNER)”/”TELEGRAM (MIRROR)” comment-label structure (a kit-authorship pattern independent of any specific bot ID), OR a function tg definition combined with a Kryptex pool domain or the install_xmrig function name. The rule now survives bot rotation; tiered Hunting rather than Detection because the salvage introduces a rewritten condition not independently goodware-validated, and two of the three paths (Kryptex pool domain, bot token) remain operator-configuration values rather than kit-structural artifacts.
False Positives: Low but not zero for the bot-token and pool-domain paths (both are operator/kit-author-controlled values that could theoretically appear in unrelated Telegram/mining tooling); the dual-comment-label path has no known legitimate collision but has not been validated against a broad goodware corpus.
Deployment: Linux endpoint file scanning, download directory scanning, email gateway, web proxy content inspection; corroborate a hit with the YARA rootkit/installer Detection rules above before treating as confirmed GHOST kit activity.
rule MAL_Linux_GHOST_min1_DualTelegram_Wrapper {
meta:
description = "Detects GHOST cryptojacker kit miner installer wrapper min1.sh via three independent paths: the kit-author OWNER Telegram bot token prefix 8415540095:, OR the paired bilingual Russian TELEGRAM (OWNER)/TELEGRAM (MIRROR) comment-label structure, OR a function tg definition combined with a Kryptex pool domain or install_xmrig; salvaged from a bot-token-only condition so detection survives bot-token rotation"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
hash1 = "008bc5ab73e75bb76131f91d68a3792d9e4393137c14afe8c44d44be2a2c46f6"
family = "GHOST-cryptojacker-kit"
malware_type = "Miner Installer / Dual-Telegram Supply-Chain Wrapper"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "8dc8ca76-896a-58b9-b88c-4ab6cf8c7e6c"
strings:
// Path 1: kit-author OWNER bot token prefix (atomic; already in IOC feed) — kept as one of three OR-paths, not the sole gate
$owner_bot_prefix = "8415540095:" ascii
// Path 2: dual-Telegram bilingual comment-label structure (Russian: OWNER + MIRROR) — kit-authorship pattern, bot-ID-independent
$tg_owner_comment = "TELEGRAM (\xD0\x92\xD0\x9B\xD0\x90\xD0\x94\xD0\x95\xD0\x9B\xD0\x95\xD0\xA6)" ascii // TELEGRAM (ВЛАДЕЛЕЦ)
$tg_mirror_comment = "TELEGRAM (\xD0\x97\xD0\x95\xD0\xA0\xD0\x9A\xD0\x90\xD0\x9B\xD0\x9E)" ascii // TELEGRAM (ЗЕРКАЛО)
// Path 3: function tg + Kryptex pool domain or install_xmrig function name
$pool_xmr_kryptex = "xmr.kryptex.network" ascii
$pool_etc_kryptex = "etc.kryptex.network" ascii
$fn_install_xmrig = "install_xmrig" ascii fullword
$fn_tg = "function tg" ascii
condition:
filesize < 30KB and
(
$owner_bot_prefix or
($tg_owner_comment and $tg_mirror_comment) or
($fn_tg and ($pool_xmr_kryptex or $pool_etc_kryptex or $fn_install_xmrig))
)
}
MAL_Linux_GHOST_check_comfyui_Scanner
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1595.002 (Active Scanning: Vulnerability Scanning), T1059.004 (Unix Shell)
Confidence: MODERATE
Rationale: The check_comfyui[.]sh scanner combines a ComfyUI port-8188 HTTP probe, /object_info/system_stats//queue endpoint checks, and a four-category output-file naming convention (sc_comfy, sc_manager, sc_nodes, sc_vuln) distinctive to this kit’s reconnaissance component — but basic ComfyUI health-check scripts exist in legitimate admin tooling, and MODERATE (not HIGH) confidence in the original assessment reflects that the differentiator (output filenames) is not a structural code artifact the way the rootkit hide-list is.
False Positives: Legitimate ComfyUI health-check or monitoring scripts that happen to use a similar port-probe pattern; the sc_* output-filename convention reduces but does not eliminate this.
Deployment: Linux endpoint file scanning, download directory scanning, web proxy content inspection.
rule MAL_Linux_GHOST_check_comfyui_Scanner {
meta:
description = "Detects GHOST cryptojacker kit ComfyUI target verification script check_comfyui.sh — Bash script probing port 8188 /system_stats and /queue for ComfyUI identification, classifying results into sc_comfy/sc_manager/sc_nodes/sc_vuln output files; Russian-language comments; scanning component of GHOST ComfyUI exploitation pipeline"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
hash1 = "9023734a70ee6a05d4ecd5466d0c5803f293601836deb00cc417a3add04bd93e"
family = "GHOST-cryptojacker-kit"
malware_type = "ComfyUI Target Scanner"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "39b7fb48-31ec-5b1d-b787-2935cad5a60e"
strings:
// ComfyUI probe endpoints
$probe_system_stats = "system_stats" ascii
$probe_object_info = "object_info" ascii
$probe_queue = "/queue" ascii
// GHOST-specific output file naming convention
$out_sc_comfy = "sc_comfy" ascii
$out_sc_manager = "sc_manager" ascii
$out_sc_nodes = "sc_nodes" ascii
$out_sc_vuln = "sc_vuln" ascii
// ComfyUI port
$port_8188 = "8188" ascii
condition:
filesize < 10KB and
$port_8188 and
($probe_system_stats or $probe_object_info or $probe_queue) and
2 of ($out_*)
}
MAL_Linux_GHOST_get_all_ranges_CloudEnumerator
Tier: Hunting
Robustness: 1
ATT&CK Coverage: T1595.002 (Active Scanning: Vulnerability Scanning), T1018 (Remote System Discovery), T1059.004 (Unix Shell)
Confidence: MODERATE
Rationale: The get_all_ranges[.]sh cloud IP-range scraper targets the bgpview[.]io public API with a specific set of cloud-provider ASN queries. The bgpview[.]io + bgpview[.]io/asn/ pair is effectively one signal expressed twice (not two independent anchors), and the provider name list (Lambda Labs, Nebius, Datacrunch, Contabo, Hetzner) consists of literal company names that could appear together in legitimate cloud-inventory, IaC, or network-documentation tooling. As explicitly assessed in the original analysis: false-positive risk is HIGH for any individual provider name and only LOW for the full combination of names in the sample. The rule fires on any two of the five names it lists plus the bgpview[.]io pair, so that LOW rating does not describe what the rule requires and its false-positive risk is moderate — a genuine but brittle signal.
False Positives: Legitimate cloud-inventory, asset-discovery, or infrastructure-as-code tooling that queries bgpview[.]io for the same or an overlapping set of cloud-provider ASNs, particularly ML/GPU-focused inventory scripts.
Deployment: Linux endpoint file scanning, download directory scanning; use as a scoping lead rather than an alert.
rule MAL_Linux_GHOST_get_all_ranges_CloudEnumerator {
meta:
description = "Detects GHOST cryptojacker kit cloud-provider IP-range enumeration script get_all_ranges.sh — text file under 15 KB naming bgpview.io, its /asn/ path and at least two of five cloud-provider names (Lambda Labs, Nebius, Datacrunch, Contabo, Hetzner); the sample queries 14+ providers including GPU-cloud ones, but any two of the five names satisfy the rule (Contabo and Hetzner alone do); reconnaissance prequel to ComfyUI exploitation pipeline targeting GPU-cloud environments"
license = "CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/"
author = "The Hunters Ledger"
reference = "https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/"
date = "2026-05-25"
family = "GHOST-cryptojacker-kit"
malware_type = "Cloud IP-Range Enumerator"
campaign = "OpenDirectory-GHOST-Cryptojacker-Vova75Rus-77.110.96.200"
id = "61f9da50-05bf-5c1c-933a-2a65a73eeae3"
strings:
// bgpview.io API source (used for ASN-to-IP-range lookups)
$bgpview_api = "bgpview.io" ascii
// Provider names from the sample's ASN list (the first three are GPU-cloud providers);
// any two of the five names satisfy the condition, so this is not a GPU-cloud-specific test
$provider_lambda = "Lambda Labs" ascii
$provider_nebius = "Nebius" ascii
$provider_datacrunch = "Datacrunch" ascii
// Additional providers from get_all_ranges.sh ASN list
$provider_contabo = "Contabo" ascii
$provider_hetzner = "Hetzner" ascii
// bgpview.io API structure specific to this script
$bgpview_ips_prefix = "bgpview.io/asn/" ascii
condition:
filesize < 15KB and
$bgpview_api and
$bgpview_ips_prefix and
2 of ($provider_*)
}
Sigma Rules
Detection Rules
Linux LD_PRELOAD Persistence File Modification
Tier: Detection
Robustness: 3
ATT&CK Coverage: T1574.006 (Dynamic Linker Hijacking)
Confidence: HIGH
Rationale: /etc/ld.so.preload is the single most durable signature in this file — its modification is the persistent global-load trigger for every process on the system, and it is rarely touched in legitimate production environments outside package-manager operations, which are explicitly excluded.
False Positives: System administrators manually adding a legitimate preload library for debugging or performance purposes (rare; verify path added to the file); package post-install scripts using ldconfig/update-alternatives to register new shared libraries (excluded by the filter, but confirm the filter is effective in your environment).
Blind Spots: A rootkit that writes this file through a process image renamed to match one of the excluded package-manager binaries would evade; memory-only variants that never persist via this file are not covered (see Rule 3 non-/etc/ld.so.preload variant coverage gap).
Validation: Trigger the rootkit’s install routine — the write/create event on /etc/ld.so.preload must match; a dpkg/apt/rpm package install that touches the same file must NOT fire.
Deployment: auditd + Sysmon for Linux (file_event on Linux).
title: Linux LD_PRELOAD Persistence File Modification
id: f67e016e-dcd7-4ee3-a2ee-9477ad7f75c2
status: experimental
description: >-
Detects write or create operations on /etc/ld.so.preload by non-package-manager
processes. The GHOST cryptojacker kit writes this file to globally load
libpam_cache.so into all system processes for LD_PRELOAD rootkit persistence.
Modification of this file by a shell, curl, or miner process is a high-confidence
indicator of LD_PRELOAD rootkit installation.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
- https://censys.com/ghost-cryptojacker-targeting-ai
author: The Hunters Ledger
date: 2026-05-25
tags:
- attack.persistence
- attack.stealth
- attack.execution
- attack.t1574.006
- detection.emerging-threats
logsource:
category: file_event
product: linux
detection:
selection_path:
TargetFilename: '/etc/ld.so.preload'
filter_pkg_mgr:
Image|endswith:
- '/dpkg'
- '/apt'
- '/apt-get'
- '/ldconfig'
- '/update-alternatives'
- '/rpm'
- '/yum'
- '/dnf'
condition: selection_path and not filter_pkg_mgr
falsepositives:
- >-
System administrators manually adding a legitimate preload library for
debugging or performance purposes (rare; verify path added to the file)
- Package post-install scripts using ldconfig or update-alternatives to
register new shared libraries
level: high
Suspicious Shared Library Created in PAM Security Directory
Tier: Detection
Robustness: 3
ATT&CK Coverage: T1574.006 (Dynamic Linker Hijacking), T1027 (Obfuscated Files or Information), T1014 (Rootkit)
Confidence: HIGH
Rationale: Legitimate PAM module installation is exclusively done through package managers; direct .so file creation in /lib/security/-family directories from a shell, curl, or wget is not a legitimate PAM deployment pattern under any normal operational scenario.
False Positives: Legitimate PAM module installation by package manager (filtered by the exclusion above — confirm the filter is working in your environment); manual PAM plugin deployment by a system administrator (require change-management verification).
Blind Spots: A rootkit dropped by a process image renamed to match an excluded package-manager binary would evade; a .so dropped under a non-standard PAM directory path outside the four listed prefixes is not covered.
Validation: Trigger the rootkit’s install routine — the .so creation event under /lib/security/ must match; a dpkg-driven PAM module install must NOT fire.
Deployment: auditd + Sysmon for Linux (file_event on Linux).
title: Suspicious Shared Library Created in PAM Security Directory
id: 21b2646a-7e0b-4d6c-8392-d976b8388fa3
status: experimental
description: >-
Detects creation of a .so shared library file in /lib/security/ or similar PAM
module directories by non-package-manager processes. The GHOST cryptojacker kit
drops libpam_cache.so into /lib/security/ using PAM-style filename camouflage as
a deceptive LD_PRELOAD rootkit. Legitimate PAM modules are always installed via
package management — direct file creation from a shell or download tool indicates
rootkit deployment.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
- https://censys.com/ghost-cryptojacker-targeting-ai
author: The Hunters Ledger
date: 2026-05-25
tags:
- attack.stealth
- attack.persistence
- attack.execution
- attack.t1574.006
- attack.t1014
- detection.emerging-threats
logsource:
category: file_event
product: linux
detection:
selection_path:
TargetFilename|startswith:
- '/lib/security/'
- '/lib/x86_64-linux-gnu/security/'
- '/usr/lib/security/'
- '/usr/lib/x86_64-linux-gnu/security/'
TargetFilename|endswith: '.so'
filter_pkg_mgr:
Image|endswith:
- '/dpkg'
- '/apt'
- '/apt-get'
- '/rpm'
- '/yum'
- '/dnf'
- '/ldconfig'
condition: selection_path and not filter_pkg_mgr
falsepositives:
- >-
Legitimate PAM module installation by package manager (filtered by
exclusion above — confirm filter is working)
- Manual PAM plugin deployment by system administrator (require change
management verification)
level: high
GHOST Kit Camouflage Name in a Created File Path (Systemd Unit Names and inotify_guard)
Tier: Detection
Robustness: 2
ATT&CK Coverage: T1543.002 (Create or Modify System Process: Systemd Service), T1036.005 (Masquerading: Match Legitimate Name or Location)
Confidence: HIGH
Rationale: These specific camouflage names are part of the kit’s structural hide-list/process-disguise inventory (the same array referenced by the YARA rootkit rule) — changing them requires a kit-level rebuild, not a per-deployment rename. No standard Linux distribution package is known to use these names, but that was not checked against package indexes, and the False Positives entry below names a desktop package that may provide gnome-shell-ext-updater.
False Positives: A custom legitimate service deployment using a similar name (extremely unlikely for fontconfig-cache.service or gnome-shell-ext-updater.service as systemd units); a desktop environment package that legitimately provides gnome-shell-ext-updater — verify package ownership via dpkg -S/rpm -qf before treating as confirmed.
Blind Spots: A future kit version that renames the entire camouflage-name inventory would evade; this rule inspects file creation by path name only, not runtime service state. The report evidences only fontconfig-cache.service as a unit file; the other .service names are the camouflage process and script names with a unit suffix, so whether the kit ever creates units under them is not established. inotify_guard is evidenced as a watchdog process name, not a unit, and matches any created path containing it. The kit’s systemd-journal-flush.service system unit is not listed because it shares its name with a real systemd unit.
Validation: Trigger the kit’s systemd persistence install — the creation event for fontconfig-cache.service under ~/.config/systemd/user/ must fire, as must a file created at any path containing one of the other listed names (including a non-unit file whose path contains inotify_guard); installation of an unrelated, differently-named systemd unit must NOT fire.
Deployment: Linux file_event monitoring (the rule has no directory test, so it also matches these names outside the systemd unit directories), auditd.
title: GHOST Kit Camouflage Name in a Created File Path (Systemd Unit Names and inotify_guard)
id: 16fce30a-b59f-461c-87fc-89ae2d736527
status: experimental
description: >-
Detects creation of a file whose path contains one of seven GHOST cryptojacker
kit camouflage names. Six are `.service` unit names (the kit installs
fontconfig-cache.service as user-level systemd persistence disguised as
fontconfig caching; operator processes are renamed to dbus-session-monitor
(xmrig) and gnome-shell-ext-updater (lolMiner)). The seventh, inotify_guard,
is the kit's watchdog process name; with no suffix or directory test it
matches any created file path that contains it. The rule has no process or
package-manager filter, so a package manager creating one of these files also
matches. The kit's system unit systemd-journal-flush.service uses the name of
a real systemd unit and is not matched.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
author: The Hunters Ledger
date: 2026-05-25
tags:
- attack.persistence
- attack.privilege-escalation
- attack.stealth
- attack.t1543.002
- attack.t1036.005
- detection.emerging-threats
- stp.3
logsource:
category: file_event
product: linux
detection:
selection_ghost_unit_names:
TargetFilename|contains:
- 'fontconfig-cache.service'
- 'inotify_guard'
- 'dbus-session-monitor.service'
- 'gnome-shell-ext-updater.service'
- 'archivist-daemon.service'
- 'journald-svc.service'
- 'systemd-guard.service'
condition: selection_ghost_unit_names
falsepositives:
- >-
Custom legitimate service deployments using similar names (extremely
unlikely for fontconfig-cache.service or gnome-shell-ext-updater.service
as systemd units)
- >-
Desktop environment package that legitimately provides
gnome-shell-ext-updater (verify package manager ownership with dpkg -S
or rpm -qf)
level: medium
Chattr Immutable Bit Set on Linux Persistence Target Paths
Tier: Detection
Robustness: 3
ATT&CK Coverage: T1222.002 (File and Directory Permissions Modification: Linux), T1574.006 (Dynamic Linker Hijacking)
Confidence: HIGH
Rationale: Setting the immutable bit on LD_PRELOAD-related or PAM-security-directory files is exclusively an anti-forensics/anti-removal technique with no legitimate use case in standard Linux operations — this is a technique chokepoint, not a family-specific artifact, so it survives any GHOST kit rebuild entirely.
False Positives: System hardening scripts that legitimately use chattr +i on selected configuration files (review CIS benchmark hardening scripts); container image build processes that lock certain system files (rare; typically not in /lib/security paths).
Blind Spots: A variant using an alternative anti-removal mechanism (e.g. a kernel-level rootkit hook rather than the filesystem immutable bit) would evade; this rule only covers the four listed sensitive-path prefixes.
Validation: Trigger the kit’s _lock_files routine — the chattr +i invocation against a sensitive path must match; a CIS-hardening script locking an unrelated configuration file must NOT fire.
Deployment: Linux process_creation monitoring (auditd EXECVE or Sysmon for Linux Event ID 1).
title: Chattr Immutable Bit Set on Linux Persistence Target Paths
id: f83a039f-885d-4759-a89c-2156a54e7ea5
status: experimental
description: >-
Detects chattr +i (set immutable bit) invoked against system persistence file
paths. The GHOST cryptojacker kit's _lock_files function uses chattr +i on
/etc/ld.so.preload, /lib/security/libpam_cache.so, and miner binary copies
to block rm operations by defenders and automated cleanup scripts. Setting the
immutable bit on LD_PRELOAD-related or PAM-security-directory files is
exclusively an anti-removal tradecraft technique — no legitimate use case exists.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
author: The Hunters Ledger
date: 2026-05-25
tags:
- attack.stealth
- attack.defense-impairment
- attack.persistence
- attack.execution
- attack.t1222.002
- attack.t1574.006
- detection.emerging-threats
logsource:
category: process_creation
product: linux
detection:
selection_chattr:
Image|endswith: '/chattr'
CommandLine|contains: '+i'
selection_sensitive_paths:
CommandLine|contains:
- '/etc/ld.so.preload'
- '/lib/security/'
- '/etc/init.d/'
- '/etc/systemd/system/'
condition: selection_chattr and selection_sensitive_paths
falsepositives:
- >-
System hardening scripts that legitimately use chattr +i on selected
configuration files (review CIS benchmark hardening scripts)
- >-
Container image build processes that lock certain system files (rare;
typically not in /lib/security paths)
level: high
Hunting Rules
Suspicious LD_PRELOAD Set to Non-Standard Library Path
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1574.006 (Dynamic Linker Hijacking), T1059.004 (Unix Shell)
Confidence: MODERATE
Rationale: LD_PRELOAD set to a non-standard path is a broad technique-level indicator — legitimate debugging (ltrace, faketime), performance tooling, and some container-runtime initialization patterns use exactly this pattern, so this is a scoping lead requiring analyst triage rather than an auto-alert.
False Positives: Debugging or performance-testing tools (ltrace, strace wrappers, faketime) using LD_PRELOAD with temporary paths; software build systems that test custom shared libraries from temp directories; some container runtimes that set LD_PRELOAD during container initialization.
Deployment: auditd PROCESS_TITLE (requires name_format=hex) or Sysmon for Linux (process_creation).
title: Suspicious LD_PRELOAD Set to Non-Standard Library Path
id: 5cd034e9-ac04-4178-8a16-95f291c5d805
status: experimental
description: >-
Detects Linux processes launched with LD_PRELOAD environment variable pointing to
non-standard shared library paths such as /tmp/, /var/tmp/, /home/, or custom
XDG cache paths. The GHOST cryptojacker kit's _compile_hide_so and _install_preload
functions may set LD_PRELOAD during rootkit deployment before writing the persistent
/etc/ld.so.preload entry. Legitimate LD_PRELOAD usage targets well-known system
library paths only.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
author: The Hunters Ledger
date: 2026-05-25
tags:
- attack.stealth
- attack.persistence
- attack.execution
- attack.t1574.006
- detection.emerging-threats
logsource:
category: process_creation
product: linux
detection:
selection_env:
CommandLine|contains:
- 'LD_PRELOAD=/tmp/'
- 'LD_PRELOAD=/var/tmp/'
- 'LD_PRELOAD=/home/'
- 'LD_PRELOAD=/root/'
- 'LD_PRELOAD=./lib'
- 'LD_PRELOAD=/dev/shm/'
condition: selection_env
falsepositives:
- >-
Debugging or performance testing tools (ltrace, strace wrappers,
faketime) using LD_PRELOAD with temporary paths
- >-
Software build systems that test custom shared libraries from temp
directories
- Some container runtimes that set LD_PRELOAD during container initialization
level: medium
Ncat Listener Creation on Linux Host
Tier: Hunting
Robustness: 1
ATT&CK Coverage: T1059.004 (Unix Shell), T1571 (Non-Standard Port)
Confidence: MODERATE
Rationale: Wording fix 2026-10-11: the title said high-frequency, but the rule is a single-event match and the threshold in the next sentence is not implemented here; it was dropped from the title. The report gives 83 ncat invocations in the operator’s bash history and no per-hour threshold, so none is added. ncat/nc/netcat are legitimate, widely-used administration tools, and an earlier analysis described a “high-frequency” qualifier (>20 invocations/hour); the report does not contain that threshold, so it is not claimed anywhere in this block and nothing implements it. As written, this fires on any single ncat -l invocation. It is a genuine scoping lead (heavy listener use is operator tradecraft recorded in this campaign’s bash history) that needs single-hit analyst review.
False Positives: Authorized network testing activities using ncat in controlled environments; security engineers running port-testing scripts on network infrastructure hosts.
Deployment: Linux process_creation monitoring (auditd EXECVE or Sysmon for Linux Event ID 1); a frequency view over these hits is possible in the SIEM but has no sourced threshold.
title: Ncat Listener Creation on Linux Host
id: 4639e400-9a7d-495f-b7a3-a06de5f3c7db
status: experimental
description: >-
Detects ncat -l listener creation on a Linux host. The GHOST cryptojacker
Operator-A showed 83 ncat invocations in bash history — the highest
command frequency — indicating chronic use of ncat for port testing, makeshift
backdoor channels, and lateral-movement probing. This rule matches any single
ncat -l invocation. The report gives the total count in the bash history and
no per-hour rate, so no frequency threshold is claimed or implemented here.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
author: The Hunters Ledger
date: 2026-05-25
modified: 2026-10-11
tags:
- attack.command-and-control
- attack.execution
- attack.t1059.004
- attack.t1571
- detection.emerging-threats
logsource:
category: process_creation
product: linux
detection:
selection_ncat_listener:
Image|endswith:
- '/ncat'
- '/nc'
- '/netcat'
CommandLine|contains: ' -l'
condition: selection_ncat_listener
falsepositives:
- Authorized network testing activities using ncat in controlled environments
- Security engineers running port testing scripts on network infrastructure hosts
level: medium
Hysteria Proxy Process Execution on Linux Server
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1572 (Protocol Tunneling)
Confidence: MODERATE
Rationale: Wording fix 2026-10-11: the title and description scoped the rule to Hysteria v2 over QUIC, but the selections test only the image name and the hysteria-server command-line text, so any Hysteria version matches. Hysteria v2 is legitimate dual-use software with real censorship-circumvention and VPN use cases; this rule fires on mere presence/execution of the Hysteria binary with no GHOST-specific qualifier (no SNI check, no specific port, no installation-path anchor). Demoted from the original level: high — an inflated level on a generic dual-use-tool selector — to medium/Hunting, reflecting that this is a “any Hysteria usage on a host type where it’s unexpected” lead, not a malware-specific detection.
False Positives: Legitimate Hysteria v2 usage for censorship circumvention by employees in restrictive-internet regions (rare in corporate GPU environments; verify with owner); authorized network testing using Hysteria for VPN/proxy research purposes.
Deployment: Linux process_creation monitoring (auditd EXECVE or Sysmon for Linux Event ID 1); scope to production GPU/ML hosts where Hysteria has no expected business purpose.
title: Hysteria Proxy Process Execution on Linux Server
id: e01c6689-1d47-4f6c-bf23-a71b32d88375
status: experimental
description: >-
Detects execution of a process whose image ends in /hysteria or whose command line
contains hysteria-server on a Linux host. The rule has no version or QUIC test, so
Hysteria 1 and Hysteria 2 both match. The GHOST cryptojacker
kit installs Hysteria v2 as a covert QUIC/UDP backdoor with bing.com SNI masquerade
(ports 14433/14444 UDP) using hyst.sh installer. Hysteria v2 is legitimate dual-use
software; execution on a production GPU server or ML workload host with no expected
business purpose is a scoping lead for GHOST kit compromise, not a malware-specific
signature on its own. The process is installed as systemd service
hysteria-server.service with binaries in /usr/local/bin/hysteria.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
- https://censys.com/ghost-cryptojacker-targeting-ai
author: The Hunters Ledger
date: 2026-05-25
modified: 2026-10-11
tags:
- attack.command-and-control
- attack.t1572
- detection.emerging-threats
logsource:
category: process_creation
product: linux
detection:
selection_hysteria:
Image|endswith: '/hysteria'
selection_hysteria_service:
CommandLine|contains: 'hysteria-server'
condition: selection_hysteria or selection_hysteria_service
falsepositives:
- >-
Legitimate Hysteria v2 usage for censorship circumvention by employees
in restrictive-internet regions (rare in corporate GPU environments;
verify with owner)
- Authorized network testing using Hysteria for VPN / proxy research purposes
level: medium
memfd_create Syscall Outside a Java, Browser and Node Filter on Linux Server
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1620 (Reflective Code Loading), T1496.001 (Resource Hijacking: Compute Hijacking)
Confidence: MODERATE
Rationale: Round 2 (2026-10-11): the selector expected the symbolic name memfd_create where raw auditd writes the number, and the deployment line offered Sysmon for Linux with no mapping to this record; the selection now accepts the name or the x86_64 number 319, the logsource states the profile, and the Sysmon claim is withdrawn. Wording fix 2026-10-11: the title said high-frequency, which the next sentences already say the rule does not implement; it also said non-JVM while the filter excludes browsers and Node as well. The title now describes the filter. memfd_create is used by a broad legitimate ecosystem beyond the JVM/browser/Node filter in this rule — systemd, container runtimes, sandboxing tools (bubblewrap, firejail), and various self-updating or FFI-based tooling all use it for anonymous memory regions. Like the ncat rule above, the “high-frequency” framing is described in prose but not implemented as a correlation/threshold in the detection logic — as written, this fires on any single non-JVM/browser memfd_create call.
False Positives: JVM-based applications (Java, Kotlin, Groovy) using memfd_create for native library loading not captured by the filter’s exact substrings; Python FFI libraries (ctypes, cffi) using memfd_create for anonymous shared memory; container runtimes, sandboxing tools, and other legitimate fileless-deployment tooling not covered by the filter.
Deployment: auditd syscall monitoring only (requires -a always,exit -F arch=b64 -S memfd_create -k fileless_exec; raw logs carry syscall 319 on x86_64, interpreted logs carry the name); no Sysmon for Linux form of this record is provided. Tune with process-ancestry filters for the expected parent-process chain on your GPU servers before treating hits as actionable.
title: memfd_create Syscall Outside a Java, Browser and Node Filter on Linux Server
id: 3d5c184d-4937-4ab0-93d6-778760e59b9c
status: experimental
description: >-
Detects a memfd_create() syscall record on a Linux server whose exe does not
contain java, chrome, chromium, firefox or node. The rule matches a single
event and has no frequency threshold. The GHOST cryptojacker kit's _memfd_exec function uses
memfd_create to create anonymous in-memory file descriptors for fileless xmrig and
lolMiner execution via execveat(), bypassing on-disk file scanning. Requires
auditd syscall monitoring with "-a always,exit -F arch=b64 -S memfd_create -k
fileless_exec" rule active; raw auditd records the syscall as the number 319
on x86_64, so the selection accepts the name or that number. memfd_create is also used by a broad legitimate
ecosystem (systemd, container runtimes, sandboxing tools, FFI libraries) beyond
the JVM/browser/Node filter below, so this is a scoping lead requiring
process-ancestry tuning rather than an auto-alert.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
author: The Hunters Ledger
date: 2026-05-25
modified: 2026-10-11
tags:
- attack.stealth
- attack.t1620
- detection.emerging-threats
logsource:
product: linux
service: auditd
definition: 'Requires auditd SYSCALL records for memfd_create from the audit rule named in the description. Raw auditd logs the syscall as a number (319 on x86_64) with the executable in the same record; an interpreted profile (ausearch -i, or an ingestion that translates syscall numbers) logs the name. The rule matches both forms, 319 is the x86_64 number only, and no Sysmon for Linux mapping to this record exists.'
detection:
selection_memfd:
type: 'SYSCALL'
syscall:
- 'memfd_create'
- 319
filter_expected:
exe|contains:
- 'java'
- 'chrome'
- 'chromium'
- 'firefox'
- 'node'
condition: selection_memfd and not filter_expected
falsepositives:
- >-
JVM-based applications (Java, Kotlin, Groovy) using memfd_create for
native library loading — excluded by filter above
- >-
Python FFI libraries (ctypes, cffi) using memfd_create for anonymous
shared memory
- Legitimate fileless deployment tools used by authorized DevOps processes
level: medium
Auditd - PAM Security Library Directory File Creation by Non-Package-Manager
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1574.006 (Dynamic Linker Hijacking), T1014 (Rootkit)
Confidence: LOW
Rationale: Round 2 re-tier (2026-10-11, Detection to Hunting): the selector read type: PATH, the watch key and the exe filter from one event, but raw auditd keeps the pathname and nametype in the PATH record and the watch key and executable in the SYSCALL record, and no joined or normalized profile is declared or demonstrated; it also never tested the pathname. The selection now tests name under /lib/security/, drops the record-type test, and the logsource states the joined profile it needs; because that profile is assumed and not shown, the rule is Hunting at confidence LOW, and the Sysmon file-event sibling above is the Detection-tier form of the same behaviour. Logic fix 2026-10-11: the description said PATH records with an open-for-write flag or CREATE, but the selection matched nametype CREATE or DELETE, so a file removal also fired. It is now CREATE only, which is what a new rootkit drop produces; an overwrite of an existing PAM module (a different nametype) is not covered. Auditd PATH-record equivalent of the Sysmon file-event rule above, for environments running auditd without Sysmon for Linux. Same precision rationale — legitimate PAM module writes to this directory only occur through package managers, which are excluded.
False Positives: Package manager post-install hooks installing legitimate PAM modules (filtered above); a system administrator manually copying a verified PAM module during maintenance.
Blind Spots: Requires the -w /lib/security -p wa -k pam_module_write auditd rule to be active and the PATH and SYSCALL records joined per event; without it, this rule produces no events at all (a silent gap, not a false negative on a specific evasion).
Validation: Confirm the auditd watch rule is active, then, with the PATH and SYSCALL records of one event joined, trigger the rootkit’s install routine — the joined event must match; a package-manager-driven PAM install must NOT fire.
Deployment: auditd with the PATH and SYSCALL records of one event joined into one document (see the logsource definition); raw per-record auditd logs cannot evaluate this rule.
title: Auditd - PAM Security Library Directory File Creation by Non-Package-Manager
id: f26bb12b-dca1-4b62-adf1-9186d5d31560
status: experimental
description: >-
Detects an auditd PATH record with nametype CREATE (a new file created) under
/lib/security/. Requires auditd rule "-w /lib/security -p wa -k pam_module_write"
to be active, and joined PATH and SYSCALL record fields (see the definition). The
GHOST cryptojacker kit writes libpam_cache.so to this directory using PAM-style
filename camouflage; a new file there from a non-package-manager process is a
strong lead for a rootkit drop. The rule does not test an open-for-write
flag (a PATH record carries no such flag), and an overwrite of an existing file,
which carries another nametype, is not matched.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
author: The Hunters Ledger
date: 2026-05-25
modified: 2026-10-11
tags:
- attack.stealth
- attack.persistence
- attack.execution
- attack.t1574.006
- attack.t1014
- detection.emerging-threats
logsource:
product: linux
service: auditd
definition: 'Requires auditd events in which the PATH record fields (name, nametype) and the SYSCALL record fields (key, exe) of one event are joined into one document, for example by ausearch -i output keyed on the event serial or an ingestion that merges records. Raw auditd keeps them in separate records: PATH carries name and nametype, SYSCALL carries the watch key and exe. No joined profile has been demonstrated for this rule.'
detection:
selection_key:
key: 'pam_module_write'
name|contains: '/lib/security/'
nametype: 'CREATE'
filter_pkg_mgr:
exe|endswith:
- '/dpkg'
- '/rpm'
- '/ldconfig'
- '/update-alternatives'
condition: selection_key and not filter_pkg_mgr
falsepositives:
- Package manager post-install hooks installing legitimate PAM modules (filtered above)
- System administrator manually copying a verified PAM module during maintenance
level: medium
ComfyUI Custom Node Python File With a PerformanceMonitor Path Prefix Created
Tier: Hunting
Robustness: 1
ATT&CK Coverage: T1554 (Compromise Host Software Binary)
Confidence: LOW
Rationale: Wording and tier fix 2026-10-11: the rule matches a created .py file whose path contains /custom_nodes/PerformanceMonitor, nothing more. That is a path-prefix test, not a filename test: .../custom_nodes/PerformanceMonitor[.]py, .../custom_nodes/PerformanceMonitorOther[.]py and .../custom_nodes/PerformanceMonitor/pkg[.]py all match. The report names the PerformanceMonitor class and the plant_backdoor_node routine but not the planted file’s name, so the prefix is a lead, not the kit’s file. Its YARA sibling above (SUSP_Linux_ComfyUI_PerformanceMonitor_Node_Registration) was confirmed by direct testing to fire on a genuine, benign ComfyUI extension named PerformanceMonitor, and this path test has the same property: a legitimately named extension matches, and the kit’s node can be renamed. It keys on one path prefix, so it is Robustness 1 and Hunting tier, level medium, and the earlier title (“Fake … Planted”) and the claim that it detects the kit’s persistence were withdrawn. Tightened from the original selector. The prior version matched TargetFilename|contains against EITHER the specific /custom_nodes/PerformanceMonitor substring OR the generic /ComfyUI/custom_nodes/ directory path — the second branch would fire on the creation of ANY .py file anywhere under a ComfyUI custom-node directory, which is exactly what happens every time a user installs any legitimate custom node. That branch has been removed; the rule now requires the distinctive /custom_nodes/PerformanceMonitor path component specifically.
False Positives: Confirmed for the sibling content rule and true by construction here: a legitimately-named custom node literally called “PerformanceMonitor” installed by an authorized user (verify publisher and source repository before dismissing); development environments where a test node happens to share this name.
Blind Spots: A rebuild that renames the planted node file would evade, and so would a planted file whose path does not begin PerformanceMonitor; this rule inspects the file path only, not the file’s content (the YARA rule above inspects content — the class definition — for a stronger anchor).
Validation: A created .py file under custom_nodes/ whose path begins PerformanceMonitor must match (PerformanceMonitor[.]py, PerformanceMonitorOther[.]py and a file inside a PerformanceMonitor directory all do); a .py file whose path under custom_nodes/ does not contain /custom_nodes/PerformanceMonitor must NOT fire. A benign custom node that is itself named PerformanceMonitor WILL fire. Whether the file written by plant_backdoor_node() has a name beginning PerformanceMonitor is NOT CHECKED: the report does not give it.
Deployment: Linux file_event telemetry that carries the created file’s full path as TargetFilename (Sysmon for Linux file-create events, or an EDR file feed). Raw auditd records put the path in a separate PATH record, so auditd needs a pipeline that joins it into TargetFilename before this rule can match.
title: ComfyUI Custom Node Python File With a PerformanceMonitor Path Prefix Created
id: df247923-595c-4760-9a97-f0722dbf664d
status: experimental
description: >-
Detects creation of a Python file whose path contains
/custom_nodes/PerformanceMonitor, a path-prefix match that also accepts
PerformanceMonitorOther.py and files inside a PerformanceMonitor directory. The GHOST Python kit's plant_backdoor_node()
function registers a PerformanceMonitor class in the victim's ComfyUI custom_nodes/
directory (the report does not give the planted file's name), and a legitimate extension with the same name prefix creates the same
event, so a hit needs publisher and source verification. Tightened from an earlier selector that also matched
any .py file under a ComfyUI custom_nodes/ path regardless of filename, which
would have fired on every legitimate custom-node installation.
references:
- https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/
- https://censys.com/ghost-cryptojacker-targeting-ai
author: The Hunters Ledger
date: 2026-05-25
tags:
- attack.persistence
- attack.t1554
- detection.emerging-threats
- stp.2
logsource:
category: file_event
product: linux
detection:
selection_comfyui_node:
TargetFilename|contains: '/custom_nodes/PerformanceMonitor'
TargetFilename|endswith: '.py'
condition: selection_comfyui_node
falsepositives:
- >-
Legitimate custom ComfyUI node named PerformanceMonitor installed by
authorized user (verify publisher and source repository before dismissing)
- >-
Development environments where a test custom node happens to share this
name (scope exclusion for known dev hosts recommended)
level: medium
Suricata Signatures
Detection Rules
GHOST Kit Distribution File Download from AEZA Hosting Range
Tier: Detection
Robustness: 2
ATT&CK Coverage: T1059.004 (Unix Shell), T1574.006 (Dynamic Linker Hijacking), T1105 (Ingress Tool Transfer)
Confidence: HIGH
Rationale: The URI filename set (libpam_cache[.]so, ghost[.]sh, hyst[.]sh, min1[.]sh, libpam_cache.c) is a durable kit-structural artifact — these names are consistent across the toolkit’s architecture and don’t rotate per-victim — combined with a destination restriction to the /16 hosting range where both confirmed GHOST operator servers reside. No legitimate use of a .so file literally named libpam_cache exists on this hosting range.
False Positives: None known — these specific URI paths have no legitimate usage on AEZA hosting infrastructure.
Blind Spots: If GHOST kit distribution moves off the 77[.]110[.]0[.]0/16 range, the destination restriction requires updating even though the filename pattern itself would still be valid; a customer serving these files from a different hosting range would evade until the CIDR is refreshed.
Validation: Replay a PCAP of a victim downloading ghost[.]sh from an in-range host — must alert; an unrelated .sh/.so download from the same range must NOT fire.
Deployment: Network IDS/IPS at perimeter, HTTP proxy inspection.
alert http $HOME_NET any -> 77.110.0.0/16 any (msg:"THL DETECT GHOST Cryptojacker Kit Distribution File Download from AEZA Hosting Range"; flow:established,to_server; http.uri; pcre:"/\/(libpam_cache\.so|ghost\.sh|hyst\.sh|min1\.sh|libpam_cache\.c)$/"; reference:url,the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/; classtype:trojan-activity; sid:9100104; rev:3; metadata:author The_Hunters_Ledger, date 2026-05-25, tag Dropper, tag GHOST_kit;)
Hunting Rules
GHOST Cryptojacker Kit QUIC v1 Initial Egress to Candidate Hysteria Operator Ports 14433 to 14444
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1572 (Protocol Tunneling), T1571 (Non-Standard Port)
Confidence: MODERATE
Rationale: As of rev 4 the rule no longer matches the port range alone. It matches the first packet of a QUIC v1 connection (RFC 9000 long header, Initial type, version 0x00000001, UDP payload of at least 1200 bytes, which RFC 9000 requires of every client Initial) leaving the protected network toward UDP 14433 through 14444. Hysteria v2 runs over QUIC, so a Hysteria client’s opening datagram has this shape unless Salamander obfuscation is enabled, but which end of the tunnel sits inside the protected network is not established, and the Blind Spots below record the evidence on both sides. The kit’s Hysteria listeners use 14433 and 14444 with a bing[.]com SNI masquerade, but those ports are this operator’s configuration choice, not a kit-wide constant, so the rule stays durability-limited and stays Hunting/Robustness 2. The anchor is a raw byte shape rather than the quic keyword or quic.sni because the sensor’s QUIC parser is not engaged on these ports (see the 2026-09-30 note), so nothing that depends on the parser can fire here. The rule cannot confirm Hysteria specifically: any QUIC v1 client sending a full-size Initial to these ports matches, which is why it remains a lead that needs corroboration. The msg of this egress rule (sid 9100103) still reads “Hysteria v2 QUIC Initial”: it is left unchanged because local exceptions and triage records already refer to that text, and the heading above states the narrower claim.
False Positives: Any legitimate QUIC v1 client (HTTP/3 browsers and apps, or another Hysteria, MASQUE or QUIC-based VPN or tunnel product) that sends a client Initial to a server listening in UDP 14433 through 14444. That is uncommon but not impossible, and it is the residual FP class by design, since the traffic shape is the behavior being hunted. The threshold limits alert volume to one alert per source per hour. The port-only rules produced 140 alerts in 41 days (139 at rev 3 and 1 at rev 2), all from benign local causes: a VLAN40 camera (10[.]0[.]40[.]101) and two WireGuard peers. Of the 140, 137 went to AWS relay addresses, 2 went to the protected network’s own WAN address (a hairpin), and 1 was internal (the rev 2 alert). The destination ports observed were UDP 14434, 14437, 14442, 14443 and 14444. That traffic is small WireGuard-style or camera keepalive datagrams, averaging 43 to 105 bytes per packet on the wire, and rev 4 does not match it (see the 2026-09-30 note for the measurement). A hairpin-NAT case remains possible in principle: a road-warrior or full-tunnel VPN client that speaks QUIC to its own gateway’s WAN address on a port in this range would still be scoped as EXTERNAL_NET traffic. Add a local exception for your own WAN address or VPN client subnet if it fires.
Blind Spots: Hysteria v2 with Salamander obfuscation enabled sends packets that do not carry the QUIC long-header shape, so the rule is blind to it. A client whose first datagram is not a standard QUIC v1 Initial (a different QUIC version, a first packet split or reordered so the Initial is not seen, a probe or handshake preceding the Initial, or a Hysteria fork with a modified first packet) is also missed. A different port choice by the operator is missed. A server that answers without the client ever sending a full-size Initial from the protected network is missed. Only the client-to-server direction is inspected. The direction of the tunnel is not settled by the evidence, and this rule covers only a client Initial leaving the protected network toward ports 14433 through 14444, which is the egress reading. stage1-summary.json line 207 describes egress to 77[.]110[.]96[.]200 on ports 14433 and 14444, and that is the evidence this rule rests on. The HP[] hide-port array (8029, 3333, 8027, 4444, 5555, 7777, 9999, 14433, 14444) belongs to the LD_PRELOAD rootkit that runs on the victim and hides matching entries from /proc/net/tcp there. Hysteria runs over UDP, which is listed in /proc/net/udp, and the analysis did not establish whether the rootkit also filters that table, so the presence of 14433 and 14444 in the array shows the operator associates those ports with the kit rather than proving what the rootkit hides for Hysteria. The array includes the miner’s outbound pool ports 3333 and 4444, so it hides victim-side connections by port in either role and does not settle direction. On its own it supports a victim-hosted Hysteria listener on 14433 or 14444 (inbound operator connections) as well as victim egress to those ports. hyst[.]sh installs hysteria-server.service on the victim (stage1-malware-analyst[.]md around lines 373 to 384, and stage2-infrastructure[.]md line 72; generate_free_port may be a fallback), which supports a victim-hosted listener from the kit’s own installer. That reading is now covered by the inbound sibling rule on UDP 14433 through 14444 (sid 9100109 locally), which is documented in the next section. The remaining blind spots for the direction question are a victim-hosted listener on a generated port outside 14433 through 14444, and server replies. QUIC v2 (version 0x6b3343cf) and draft versions do not match, because the rule pins version 1. Stock Hysteria’s pinned quic-go fork dials v1 first and pads its Initial to 1280 bytes (per a reading of apernet/quic-go commit 73339f7edbb9, transport.go line 277), so a stock client should be matched, though no real client capture was replayed, and a modified client that dials another version could evade. QUIC on this sensor cannot be inspected through the quic keywords on these ports, so SNI-based confirmation has to come from a capture or from a sensor that has the QUIC parser engaged on the port.
Validation: Replaying a synthesized QUIC v1 Initial (1252 bytes, built to RFC 9001 and not captured from a real Hysteria client) to UDP 14433 fires sid 9100103. No capture of a real Hysteria client Initial was available, so the match on a genuine client is an inference from the RFC and the client source, not a replay. The same Initial to UDP 443, or to UDP 14445, does not. Small non-QUIC UDP datagrams to 14434, 14442 and 14443, a full-size datagram with a wrong version, a full-size long-header packet with a 0-RTT type, and a short-header packet do not fire.
Deployment: Network IDS/IPS at perimeter, server egress monitoring; hunt-tune before alerting, and corroborate with the AEZA-range Detection rule above before escalating. Confirm EXTERNAL_NET is defined as !$HOME_NET on your sensor rather than the literal any, or the egress scoping below has no effect.
FP remediation note (2026-08-20): two authoring defects, fixed together in rev 3.
The msg claimed “Backdoor Egress”, meaning outbound to the internet, while the rule matched $HOME_NET any -> any 14433:14444. Suricata’s any is an unrestricted wildcard that ignores the $HOME_NET/$EXTERNAL_NET partition, so internal-to-internal traffic matched a rule describing egress. That is what fired in production: one internal host to another, part of a UDP spray across 347 distinct destination ports of which 99.3 percent were dropped at the firewall, with port 14444 catching 24 events purely by coincidence of range. No tunnel, no cryptojacking. Scoping the destination to $EXTERNAL_NET costs nothing, because a Hysteria tunnel to operator infrastructure is external by architecture and there is no legitimate internal-to-internal case to preserve.
The second defect is the classification. This rule was already tiered Hunting/Robustness 2 above, and its own rationale concedes that “no content/host anchor is possible since this is opaque QUIC traffic”. Despite that it shipped as classtype:trojan-activity, which reads to a subscriber exactly like the genuinely high-confidence AEZA-range Detection rule earlier in this file, with no machine-readable tier signal to distinguish them. The sibling Telegram-egress hunting rule in this same file correctly uses classtype:policy-violation; this rule was the outlier. Rev 3 aligns it and adds signature_severity Minor, so the tiering judgment already made upstream now survives into the artifact an analyst actually receives.
A port range with no behavioural anchor cannot reach Detection tier and should not be expected to. The port pair is, in this file’s own words, “this operator’s specific configuration choice, not a kit-wide structural constant”, and it is trivially changed. The stronger signal already documented in the campaign IOC feed, multi-port egress combining TCP 3333 and 4444 with UDP 14433/14444 and contact with the kit’s mining-pool domain inside five minutes, is a genuine chokepoint and would justify Detection tier, but it is a correlation rule that does not exist yet rather than an edit to this one. Until it does, treat a hit here as a lead requiring corroboration.
FP remediation note (2026-09-07): measured, not re-tuned. Its conclusion that no anchor is possible is superseded by the 2026-09-30 note below. Every historical alert for this signature was pulled and accounted for. There are 28 emitted alerts across this signature’s entire operational life to date (authored 2026-08-07, first fired 2026-08-18), cross-validated against three separate indices: the raw logs-suricata-* data stream, its concrete backing index .ds-logs-suricata-default-*, and the long-retention .alerts-security.alerts-default alert copy, which independently covers the rule’s whole life with no ILM delete phase and shows the identical count. Zero of the 28 carry any corroborating GHOST, Hysteria v2, mining-pool, or other malicious signal. One is the already-documented pre-rev-3 internal-to-internal defect above. The remaining 27 trace to exactly two benign local causes, a road-warrior VPN client hairpinning to its own network’s WAN address, and a local IoT camera device’s cloud-relay session landing on a port inside this range, both handled by local network exceptions rather than a rule change.
A flow:established gate was tested as a possible content-free anchor, since the VPN-hairpin instance was fully one-directional (no reply packets seen). It was rejected. The camera-relay instance is also one-directional in its own flow record, while a second flow to the identical destination inside the same already-confirmed-benign event showed one reply packet, so bidirectionality is inconsistent even within a single benign case, and the gate would behave unpredictably rather than reliably separating benign from malicious traffic.
The sensor’s own HOME_NET/EXTERNAL_NET variables were checked directly on the live sensor rather than assumed. HOME_NET is [10[.]0[.]0[.]0/8] and EXTERNAL_NET is !$HOME_NET, the correct standard convention, not the literal any warned about in the Deployment line above. The apparent paradox of a subscriber’s own WAN address reading as EXTERNAL_NET is not a sensor misconfiguration. It is hairpin NAT meeting an address-group model that has no vocabulary for an address’s identity, only its topology. No change to the rule’s match logic follows from any of this; the port range and the $HOME_NET any -> $EXTERNAL_NET scoping below are unchanged from rev 3.
FP remediation note (2026-09-30): fixed in rev 4, superseding the 2026-09-07 note’s conclusion that no anchor is possible.
Rev 3 was a bare UDP 14433 through 14444 egress match. Over its 41 days in production (first alert 2026-08-18, last 2026-09-27) the port-only rules produced 140 alerts (139 at rev 3 and 1 at rev 2), every one from a VLAN40 camera (10[.]0[.]40[.]101) or one of two WireGuard peers (10[.]0[.]100[.]2, 10[.]0[.]100[.]3). Of the 140, 137 went to AWS relay addresses, 2 went to the protected network’s own WAN address (a hairpin) and 1 was internal, and the destination ports were UDP 14434, 14437, 14442, 14443 and 14444. Suricata’s application-layer detection failed on all 140 (app_proto: failed), and the traffic averaged 43 to 105 bytes per packet on the wire. None of it was QUIC, and none of it was the kit. The 2026-09-07 note concluded that opaque QUIC traffic offers no content anchor and left the rule unchanged. That was wrong about the anchor: a QUIC v1 client Initial is not opaque at its first bytes, because the long header, the version field and the 1200-byte minimum datagram size are all sent in the clear (header protection masks only the low four bits of the first byte).
A quic-keyword rule was tried first and rejected on measurement. An alert quic ... quic.sni; content:"bing[.]com" variant was replayed on the sensor (Suricata 8.0.6) against a synthesized RFC 9001 Initial, built to the RFC and not captured from a real Hysteria client. On UDP 443 the control was parsed and alerted. The identical packet on UDP 14433 produced no QUIC record and incremented app_layer.flow.failed_udp, so the parser is not engaged on that port and no quic keyword can fire there. The sensor has no detection-ports override for QUIC, and adding one is a sensor configuration change outside the scope of a published rule.
Rev 4 therefore anchors on the raw shape of the datagram, parser-free: dsize:>=1200, first byte’s top four bits equal to 0xC (long header bit, fixed bit, packet type Initial), and bytes 1 to 4 equal to 00 00 00 01 (QUIC version 1). The type test uses byte_test:1,=,0xC,0,bitmask 0xF0, because a plain & test passes when either the 0x80 or the 0x40 bit alone is set and would not pin the packet type. The threshold changes from five events per minute to one alert per source per hour, since one Initial is sufficient to raise the lead and repeats add nothing.
Replay on the sensor with an offline instance (12 packets, decoder.pkts 12 confirmed): the valid Initial to 14433 fires; small random datagrams of 60 and 150 bytes to 14434 and 14443 do not, including ones with the first byte 0xC0 or 0xC3 and a non-v1 version, and one 150-byte v1-shaped packet; 1252-byte random, wrong-version, 0-RTT-type (0xDC) and short-header (0x40) datagrams to 14433 do not; the valid Initial to UDP 443 and to UDP 14445 do not. A port-only control matched all 10 in-range packets, which shows every packet was evaluated, and three further controls, each with one condition removed, fired on exactly the packets that condition is meant to exclude (the 150-byte v1 packet without the size gate, the 0-RTT and short-header packets without the type test, the wrong-version packet without the version match). That shows each condition is doing work rather than the negatives passing by accident.
Historical measurement against the 140 historical alerts: the alert records carry no payload, so the test could be answered only as a bound. Each alert records the flow’s cumulative to-server packet and byte counters. A QUIC Initial is a flow’s first packet, and the first alert of each of the 12 distinct flows was raised at packet 1 or 2 for 3 flows and at packet 5 for the other 9, so every first alert snapshot includes packet one. At that point the largest possible first packet was 202 wire bytes against the roughly 1242 needed for a 1200-byte UDP payload. Across all 140 alerts, taking the growth between consecutive alerts of the same flow, the largest single packet that could exist anywhere in the 689 to-server packets covered was 1042 wire bytes, still below the 1242 threshold. So zero of the 140 historical alerts would match rev 4. What this cannot show is the content of packets after each flow’s last alert (at most four per flow) or the exact first bytes, so it bounds the answer on size and does not inspect the header itself.
The rule remains Hunting, Robustness 2. It is now specific to QUIC-shaped traffic to the operator’s ports and no longer fires on non-QUIC traffic that happens to land in the range.
alert udp $HOME_NET any -> $EXTERNAL_NET 14433:14444 (msg:"THL HUNT GHOST Cryptojacker Kit Hysteria v2 QUIC Initial on Operator Ports (Hunt Lead, Corroborate Before Escalating)"; dsize:>=1200; byte_test:1,=,0xC,0,bitmask 0xF0; content:"|00 00 00 01|"; offset:1; depth:4; threshold:type limit,track by_src,count 1,seconds 3600; reference:url,the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/; classtype:policy-violation; sid:9100103; rev:5; metadata:author The_Hunters_Ledger, date 2026-05-25, modified 2026-09-30, signature_severity Minor, tag Backdoor, tag GHOST_kit, tag Hysteria_v2;)
GHOST Cryptojacker Kit QUIC v1 Initial Inbound to Candidate Hysteria Listener Ports 14433 to 14444
Tier: Hunting
Robustness: 2
ATT&CK Coverage: T1572 (Protocol Tunneling), T1571 (Non-Standard Port)
Confidence: LOW
Rationale: This is the inbound sibling of the egress rule above, added 2026-09-30 because the direction evidence supports both readings. hyst[.]sh installs hysteria-server.service on the victim, and the rootkit’s HP[] hide-port array (which includes 14433 and 14444 alongside the miner’s outbound pool ports 3333 and 4444) hides victim-side connections by port whichever role the victim plays. A victim-hosted Hysteria listener would therefore receive the operator’s QUIC client Initial from outside the protected network, and the egress rule cannot see that. The match is byte-for-byte the same parser-free anchor as sid 9100103 rev 4: a datagram of at least 1200 bytes (the RFC 9000 minimum for a client Initial), first byte’s top four bits equal to 0xC (long header, fixed bit, Initial type), and bytes 1 to 4 equal to 00 00 00 01 (QUIC version 1). Only the direction, the alert threshold key and the msg differ. The threshold tracks by destination, so a victim-hosted listener raises one alert per victim host per hour regardless of how many operator addresses connect. The confidence is LOW rather than MODERATE because this reading rests on the kit’s own installer and hide list, not on an observed inbound connection, and the port range is this operator’s configuration choice rather than a kit-wide constant, which keeps the rule at Hunting and Robustness 2. It cannot confirm Hysteria specifically: any QUIC v1 client sending a full-size Initial to a listener in this range matches, which is why the heading and the msg of this rule say QUIC v1 Initial on candidate ports and do not name Hysteria as the matched protocol.
False Positives: Any legitimate QUIC v1 client (HTTP/3 browsers and apps, or another Hysteria, MASQUE or QUIC-based VPN or tunnel product) that connects from outside the protected network to a service you host on UDP 14433 through 14444. That is uncommon but not impossible, and it is the residual FP class by design. An internet-wide scanner that sends QUIC v1 Initial probes to a port in this range would also match, although QUIC scanners normally target UDP 443. The inbound false-positive rate could not be measured, because no source of inbound flow data on this stack answered the question (see Validation): the rule has no production history yet. The threshold caps volume at one alert per destination per hour. Small non-QUIC datagrams to these ports, such as WireGuard-style or camera keepalives, are not matched, because they fail the 1200-byte size gate.
Blind Spots: Hysteria v2 with Salamander obfuscation enabled does not carry the QUIC long-header shape and is missed. A client whose first datagram is not a standard QUIC v1 Initial (a different QUIC version, a split or reordered first packet, a handshake preceding the Initial, or a Hysteria fork with a modified first packet) is also missed. A victim-hosted listener on a generate_free_port port outside 14433 through 14444 is missed, and so are server replies, since only the client-to-server direction is inspected. The rule needs EXTERNAL_NET defined as !$HOME_NET and the victim inside HOME_NET, and an operator connecting through a NAT or proxy that the sensor sees inside HOME_NET would not match. QUIC v2 and draft versions do not match. The quic keywords cannot confirm SNI on these ports because the sensor’s QUIC parser is not engaged there (see the 2026-09-30 note under the egress rule), so SNI-based confirmation has to come from a capture.
Validation: Offline replay on the sensor (10 packets, decoder.pkts 10 confirmed) of a synthesized QUIC v1 Initial (1252 bytes, built to RFC 9001, not captured from a real Hysteria client) from 203[.]0[.]113[.]10 to 10[.]0[.]10[.]8 on UDP 14433 fires this rule and not sid 9100103. The synthesized outbound Initial from 10[.]0[.]10[.]8 to 203[.]0[.]113[.]10 on UDP 14433 fires sid 9100103 and not this rule. Nothing else in the replay fired. Inbound datagrams that do not match: 60 and 150 byte random payloads to 14434 and 14443, a 1252 byte random payload to 14443, the valid Initial to UDP 443 and to UDP 14445, and 1252 byte packets with a wrong version, a 0-RTT type or a short-header first byte to 14433. The inbound false-positive estimate is NOT CHECKED. logs-suricata-* holds no flow events at all in the last 30 days (3,949,631 documents, all with event.action of tls, http, ssh, anomaly or alert), and the netflow index (logs-netflow.log-*, 253,032 documents, 70,317 of them UDP, covering only the last 14 days) shows 0 inbound UDP flows to ports 14433 through 14444. That zero is not believed: the control failed, because the 111 rev 3 alerts raised since netflow began (destination ports 14434, 14442 and 14443, from the camera and the two WireGuard peers) have no netflow record on those ports, although the camera host has 18,941 netflow documents. The netflow byte and packet fields were therefore not used to bound packet sizes.
Deployment: Network IDS/IPS at the perimeter, monitoring inbound traffic to servers that have no reason to accept UDP on these ports; hunt-tune before alerting, and corroborate with the AEZA-range Detection rule and the egress rule above before escalating. Confirm EXTERNAL_NET is defined as !$HOME_NET on your sensor rather than the literal any.
alert udp $EXTERNAL_NET any -> $HOME_NET 14433:14444 (msg:"THL HUNT GHOST Cryptojacker Kit QUIC v1 Initial Inbound to Candidate Hysteria Listener Ports 14433-14444 (Hunt Lead, Corroborate Before Escalating)"; dsize:>=1200; byte_test:1,=,0xC,0,bitmask 0xF0; content:"|00 00 00 01|"; offset:1; depth:4; threshold:type limit,track by_dst,count 1,seconds 3600; reference:url,the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/; classtype:policy-violation; sid:9100109; rev:3; metadata:author The_Hunters_Ledger, date 2026-09-30, signature_severity Minor, tag Backdoor, tag GHOST_kit, tag Hysteria_v2;)
Telegram API TLS SNI Egress from an Internal Host (Reporting Channel Used by the GHOST Kit, Not Specific to It)
Tier: Hunting
Robustness: 1
ATT&CK Coverage: T1102.002 (Web Service: Bidirectional Communication), T1496.001 (Resource Hijacking: Compute Hijacking)
Confidence: LOW–MODERATE
Rationale: Round 2 (2026-10-11, rev 5): the match was endswith api[.]telegram[.]org, which also matches evilapi[.]telegram[.]org or any name ending in those characters without a dot boundary; it is now startswith and endswith together, an exact match on the api[.]telegram[.]org server name, so a subdomain of it is not matched either. Wording fix 2026-10-11 (rev 4): the title and msg named the GHOST kit, a production server and a covert mining report, but the rule matches TLS SNI api[.]telegram[.]org from any $HOME_NET host, five or more times in 300 seconds. They now say that. Consolidated from two near-duplicate rules. The original file carried two tls.sni rules matching api[.]telegram[.]org — one (sid 9100107) labeled “Critical” and titled as an “OWNER Telegram Bot Token” indicator despite its own inline comment admitting the bot-token specificity is unachievable over TLS SNI and the logic only matches generic Telegram API contact; the other (sid 9100108, kept here) carried the same logic with an honest title and a noise-reducing threshold. TLS SNI to api[.]telegram[.]org is a weak indicator on its own — legitimate applications also use the Telegram Bot API — so this is a scoping lead for production/GPU-server hosts with no expected Telegram business use, not an alerting-grade signature.
False Positives: Any legitimate monitoring, alerting, or chatbot integration on the same host that uses the Telegram Bot API for unrelated purposes.
Deployment: TLS-decryption-capable inline IDS/IPS or proxy with DLP inspection for genuine bot-token-level specificity; this SNI-only fallback should be scoped to production server IP ranges with no expected Telegram use and treated as a hunting lead, not an alert.
alert tls $HOME_NET any -> any any (msg:"THL HUNT Telegram API TLS SNI Egress from an Internal Host (Reporting Channel Used by the GHOST Kit, Not Specific to It)"; tls.sni; content:"api.telegram.org"; startswith; endswith; nocase; threshold:type threshold,track by_src,count 5,seconds 300; reference:url,the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/; classtype:policy-violation; sid:9100108; rev:5; metadata:author The_Hunters_Ledger, date 2026-05-25, tag GHOST_kit, tag Telegram_reporting;)
Coverage Gaps
Rules cut or routed to the IOC feed in this retiering pass
Atomics routed to the IOC feed (5 total; no feed edits required, all already present). Per the tiering rubric’s cryptojacker-specific guidance, a mining-pool domain or a kit-wide callback token is an atomic, not a rule anchor:
- Kit-author OWNER Telegram bot token
8415540095: previously the sole rule (YARAMAL_GHOST_OWNER_Telegram_Bot_Token_Indicator) and a mandatory co-anchor in themin1[.]shwrapper rule. Removing the token from the standalone rule left only generic Telegram-API context (api[.]telegram[.]org) or a single generic Russian word with no independent GHOST-specific signal, nothing behavioral survives, so the standalone rule is cut. Already present in the IOC feed’stelegram_bot_idsarray. - Operator MIRROR Telegram bot token
8315596543: same disposition; already in the feed. - Kryptex/c3pool/nanopool mining-pool domains (
xmr[.]kryptex[.]network,etc[.]kryptex[.]network,cfx[.]kryptex[.]network,auto[.]c3pool[.]org,cfx-asia1[.]nanopool[.]org): previously two rules (SigmaDNS Query to GHOST Cryptojacker Mining Pool Domainsand Suricata sid 9100101/9100102) matched these domains with no other behavioral qualifier. Already present in the feed’snetwork_indicators[.]domainswith per-domain false-positive annotations (kryptex domains: low FP; c3pool/nanopool: medium FP, both are legitimate public mining pools also used by non-malicious miners). - Hysteria admin-panel host
77[.]110[.]96[.]200: the SuricataHysteria Admin Panel Callbackrule (sid 9100106) keyed on this single IP plus the generic/api/URI prefix; removing the IP leaves “any HTTP request starting with /api/ to any destination,” which is meaningless. Already present in the feed’snetwork_indicators.ipv4with role “Hysteria admin panel.”
Cut: Sigma Inotify Watch Created on LD_PRELOAD Persistence File (id d89cc92a-b3e0-4760-93cd-54d4b609c837). The rule’s own inline comment admits that auditd’s SYSCALL record type does not carry the watched path directly; that requires correlating with a separate PATH record, which a single Sigma selection cannot express. As literally written, the condition (selection_inotify_preload) matches inotify_add_watch calls system-wide with no path filter at all, an operation used constantly by desktop environments, IDEs, file-sync clients, log-tailing tools, and build systems. This fires on ubiquitous benign activity with zero discriminating value, which fails the precision gate even for a Hunting tier (there is no pivot value in reviewing thousands of daily inotify events). What would enable a rule: a Sigma correlation construct joining the SYSCALL record (syscall=inotify_add_watch) with the subsequent PATH record naming /etc/ld.so.preload, which requires confirming the exact auditd PATH-record field schema in the target environment before authoring.
Cut: Suricata sid 9100107 (Telegram SNI, “OWNER Telegram Bot Token” title). Duplicate of sid 9100108’s detection logic (both match tls.sni on api[.]telegram[.]org) but titled and severity-labeled as though it retained bot-token-level specificity; the rule’s own inline comment says otherwise (“The bot-token specificity is lost… this is a WEAK indicator”). Consolidated into sid 9100108, which carries an honest title, a noise-reducing threshold, and is tiered Hunting rather than presented as a Critical-severity signature.
Cut: Suricata sid 9100105 (pre-existing withdrawal, carried forward unchanged). This rule (a tls.sni match on raw[.]githubusercontent[.]com intended to catch GHOST Python kit payload fetches) was already withdrawn 2026-06-19, prior to this retiering pass, because TLS SNI cannot see the (encrypted) repository path the rule needed, and the SNI is shared by all raw[.]githubusercontent[.]com traffic. This retiering pass carries that withdrawal forward as a Cut rather than reintroducing it.
Technique-level gaps (from the original investigation; unchanged by this retiering pass)
The following MITRE ATT&CK techniques observed in the GHOST kit analysis could not be covered with high-confidence rules, along with the evidence gaps that prevent rule creation:
T1611 (Escape to Host): container-escape behavioral rules not written. The four escape variants (_escape_via_cgroup, _escape_via_mount, _escape_via_nsenter, _escape_via_socket) are documented in ghost[.]sh source but behavioral detection requires runtime monitoring of the specific syscall sequences (e.g., writes to /sys/fs/cgroup/.../release_agent, bind-mount namespace operations). Container-escape detection is also highly environment-specific (Falco/kube-bench/sysdig are the appropriate tools, not generic Sigma rules). The function names in ghost[.]sh are covered as a proxy by the YARA Kit_Shell_Installer Detection rule above.
T1552.004 (Unsecured Credentials: Private Keys): SSH key harvest rule not written. The ghost[.]sh _harvest_keys function reads ~/.ssh/known_hosts and SSH private key files for lateral movement. A generic Sigma rule for SSH key file access is high-FP (legitimate SSH tools access the same files constantly), and no specific command-line pattern distinguishes the GHOST kit’s harvest from legitimate SSH client activity. What would raise confidence: a specific variable name or grep pattern unique to ghost[.]sh’s key-harvest code.
T1021.004 (Remote Services: SSH): lateral movement Sigma rule not written. The ghost[.]sh _lateral_move, _discover_targets, and _spread_to_host functions implement SSH lateral movement using harvested keys. Detection requires correlating SSH connections from a known-compromised host to new targets combined with the kit’s specific StrictHostKeyChecking=no flag pattern, multi-event SIEM logic beyond a single Sigma rule’s scope, with a high FP rate from legitimate StrictHostKeyChecking=no admin usage absent additional context.
Censys JA3/JA3S/JA4 fingerprint: TLS fingerprint Suricata rule not written. The Censys disclosure (2026-04-07) referenced general infrastructure fingerprints (JARM/JA4X) for 77[.]110[.]96[.]200, but the specific JA3/JA3S hash values were not captured in this investigation’s artifact set. What would enable a rule: a live TLS connection to 77[.]110[.]96[.]200 with capture and ja3/ja3s analysis to extract the exact hash values.
T1685.006 / T1070.003 (Clear Linux Logs / Clear Command History): log-clearing rule not written. The ghost[.]sh _cloak function touches or clears /var/log/{auth,boot,cron,daemon,kern,messages,secure,syslog}.log and runs history -c. A Sigma rule for log truncation would fire on every legitimate logrotate event; distinguishing GHOST kit log clearing would require detecting rapid sequential truncation of multiple log files in a short window, a SIEM aggregation query, not a Sigma rule. What would enable a rule: a log-clearing command pattern in _cloak more specific than the generic log-file paths.
ComfyUI exploitation CVE/mechanism: no exploit-signature rule possible. The specific CVE or vulnerability mechanism that py[.]py’s find_target_nodes() exploits for initial code execution in ComfyUI has not been identified. What would enable a rule: ComfyUI-side analysis identifying which API endpoint or deserialization vulnerability the kit exploits for initial payload execution.
Operator-B behavioral indicators: insufficient unique signatures. Operator-B (77[.]110[.]125[.]145) is confirmed abandoned (40+ days inactive, last on-chain activity 2026-04-12). New_scanner[.]py contains distinctive Cyrillic strings, but no unique behavioral indicator beyond the shared kit-level rules was identified. If reactivated, the kit-level YARA and Sigma rules in this file will catch the deployment.
memfd_create/execveat fileless execution: incomplete coverage. The Hunting-tier memfd_create rule detects the syscall but cannot distinguish GHOST kit miner execution from legitimate use of the same pattern without process-ancestry correlation (see the rule’s own Deployment note above).
License
Detection rules are licensed under Creative Commons Attribution 4.0 International (CC BY 4.0).
Free to use, including commercially, with attribution to The Hunters Ledger.
Harrison, J. (2026). Detection Rules — GHOST Cryptojacker Kit Family (Vova75Rus / 77[.]110[.]96[.]200). The Hunter's Ledger. https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/. Published 25 May 2026.
BibTeX
@misc{hunters-ledger-ghost-cryptojacker-vova75rus-77-110-96-200-detections,
author = {Harrison, Joseph},
title = {Detection Rules — GHOST Cryptojacker Kit Family (Vova75Rus / 77[.]110[.]96[.]200)},
howpublished = {The Hunter's Ledger},
year = {2026},
month = {may},
url = {https://the-hunters-ledger.com/hunting-detections/ghost-cryptojacker-vova75rus-77.110.96.200-detections/},
note = {Published 25 May 2026. Licensed CC BY 4.0.}
}