rule VoidLink_FleetAgent
{
meta:
author = "cyfar / boredchilada"
date = "2026-06-10"
description = "VoidLink (aka Fleet) DDoS-for-hire botnet agent - Go binary, all builds"
reference = "https://code.cyfar.ca/cyfar/detonation-lab (private)"
hash_abe412b = "e2f064892cfe10b5856bbf4285de9248d2f8d7e1b6ea21d6db943ade8b20d0ad"
hash_ad9ce0f = "31f48c774b15"
tlp = "amber"
family = "VoidLink"
actor = "Polly"
strings:
// Go module path (stable across all 29 builds - the strongest anchor)
$mod = "fleet-agent/internal/agent" ascii
// Source file paths (compiled into every build via pclntab)
$src_ws = "fleet-agent/internal/agent/ws_client.go" ascii
$src_ddos = "fleet-agent/internal/agent/jobs_ddos.go" ascii
$src_hide = "fleet-agent/internal/agent/hidepid_linux.go" ascii
$src_stealth = "fleet-agent/internal/agent/stealth_linux.go" ascii
$src_crypto = "fleet-agent/internal/agent/crypto.go" ascii
// Function names unique to this family (not in any legit Go project)
$fn_enroll = "fleet-agent/internal/agent.EnsureEnrollment" ascii
$fn_heartbt = "fleet-agent/internal/agent.(*wsClient).sendHeartbeat" ascii
$fn_result = "fleet-agent/internal/agent.(*wsClient).sendResult" ascii
$fn_hidepid = "fleet-agent/internal/agent.InitHidePids" ascii
$fn_memfd = "fleet-agent/internal/agent.memfdCreateExecutable" ascii
$fn_hulk = "fleet-agent/internal/agent.runDdosHulk" ascii
$fn_l4 = "fleet-agent/internal/agent.runDdosL4" ascii
$fn_l7 = "fleet-agent/internal/agent.runDdosL7" ascii
$fn_mtproto = "fleet-agent/internal/agent.runDdosMtprotoProxy" ascii
$fn_masked = "fleet-agent/internal/agent.runMaskedTool" ascii
// DDoS command key prefixes (stable across builds)
$cmd_udp = "ddos-udp" ascii
$cmd_tcp = "ddos-tcp" ascii
$cmd_hulk = "ddos-hul" ascii
$cmd_http = "ddos-htt" ascii
$cmd_ack = "ddos-ack" ascii
$cmd_byp = "ddos-byp" ascii
$cmd_aut = "ddos-aut" ascii
// Persistence / rootkit paths
$path_hide = ".hidepids" ascii
$path_jenv = ".journal.env" ascii
$path_jstat = ".journal.state" ascii
// C2 protocol strings
$proto_ws = "/ws/agent" ascii
$proto_enr = "/api/agents/enroll" ascii
$proto_hb = "/api/agents/heartbeat" ascii
// Env var names unique to this bot
$env_server = "FLEET_SERVER_URL" ascii
$env_token = "FLEET_ENROLLMENT_TOKEN" ascii
$env_mode = "FLEET_AGENT_MODE" ascii
$env_key = "FLEET_TRANSPORT_KEY" ascii
$env_sudo = "FLEET_ALLOWED_SUDO" ascii
// User-Agent spoof
$ua = "curl/7.68.0" ascii
condition:
uint32(0) == 0x464C457F // ELF magic
and filesize > 4MB and filesize < 12MB
and $mod
and (
// strong match: module path + any 3 source files
(3 of ($src_*))
or
// strong match: module path + any 3 function names
(3 of ($fn_*))
or
// medium match: module path + 4 DDoS command keys + 2 env vars
(4 of ($cmd_*) and 2 of ($env_*))
or
// medium match: module path + C2 protocol + persistence paths
(2 of ($proto_*) and 2 of ($path_*))
)
}
rule VoidLink_FleetAgent_Bootstrap
{
meta:
author = "cyfar / boredchilada"
date = "2026-06-10"
description = "VoidLink bootstrap/dropper script (installs fleet-agent + libhide rootkit)"
family = "VoidLink"
strings:
$svc_name = "systemd-network-monitor" ascii
$svc_path = "/usr/local/bin/.systemd-network-monitor" ascii
$hide_lib = "libhide" ascii
$preload = "/etc/ld.so.preload" ascii
$state_dir = "/var/cache/systemd-network" ascii
$env_file = ".journal.env" ascii
$fleet_url = "FLEET_SERVER_URL" ascii
$fleet_token = "FLEET_ENROLLMENT_TOKEN" ascii
$reset_fail = "systemctl reset-failed" ascii
condition:
filesize < 50KB
and 4 of them
}
rule VoidLink_LibHide_Rootkit
{
meta:
author = "cyfar / boredchilada"
date = "2026-06-10"
description = "VoidLink libhide.so LD_PRELOAD rootkit (hides agent PIDs)"
family = "VoidLink"
strings:
$hidepids = ".hidepids" ascii
$preload = "/etc/ld.so.preload" ascii
$readdir = "readdir" ascii
$dlsym = "dlsym" ascii
$proc_stat = "/proc/%s/stat" ascii
$legacy_pid = ".hidepid" ascii
$cache_dir = "/var/cache/systemd-network" ascii
condition:
uint32(0) == 0x464C457F // ELF
and filesize < 100KB
and 5 of them
}Host / EDR
YARA rules for the VoidLink second-stage agent, its bootstrap dropper, and its userland rootkit. The Go module path `fleet-agent/internal/agent` is the strongest anchor; it is stable across all builds and appears in no legitimate Go project.