/* * Hound Linux threat pack. * * The curated pack sold on the Pro card: Linux miners, backdoors, bots, * webshells, rootkits and ransomware, delivered through the signed * rules-pack channel and compiled into the live ruleset next to the * built-in starter rules. * * ── the rules every rule here obeys ── * * 1. ANCHOR OR DIE. A rule matches either an ELF (uint32(0) == * 0x464c457f) or a bounded script (filesize cap + a structural marker * near offset 0). A rule that can fire on loose text does not ship — * text about malware turns up in logs, transcripts, blog posts and * threat-intel reports, and quarantining one of those is how a * previous rollout was aborted (see hound-builtin.yar). * * 2. FAMILY STRINGS, NEVER SYSCALLS. A rule keys on strings specific to * a malware family — its C2 protocol, its config keys, its own * marketing — not on dlsym/socket/execve, which every network binary * imports. The reverse-shell rule that matched /usr/bin/sudo is the * monument to this mistake. * * 3. QUARANTINE IS EARNED. `action = "quarantine"` only on a rule whose * anchor makes a false positive on a real file implausible: ELF magic, * or an exact size-bounded payload. Script and content rules ALERT, * however confident they look, because a script rule can match a * document that quotes the script. * * 4. THE GOODWARE GATE IS LAW. Every rule is scanned against /usr/bin, * /bin and /usr/sbin before it ships. One hit on a system binary and * the rule is cut, not tuned — see the removed reverse-shell rule. * * Provenance: authored from public malware analysis of the named * families. No third-party rule text is copied in, so the whole pack * ships under the same licence as the agent. */ import "math" /* ─────────────────────────── coinminers ─────────────────────────── */ rule Linux_Coinminer_XMRig_Config { meta: name = "Linux.Coinminer.XMRig-Config" severity = "critical" action = "quarantine" desc = "XMRig miner or an embedded XMRig config: pool protocol plus miner-specific keys." strings: $pool1 = "stratum+tcp://" ascii $pool2 = "stratum+ssl://" ascii $k1 = "donate-level" ascii $k2 = "\"rig-id\"" ascii $k3 = "randomx" ascii nocase $k4 = "hugepages-jit" ascii $k5 = "\"coin\":" ascii condition: uint32(0) == 0x464c457f and ($pool1 or $pool2) and 2 of ($k*) } rule Linux_Coinminer_XMRigCC { meta: name = "Linux.Coinminer.XMRigCC" severity = "critical" action = "quarantine" desc = "XMRigCC remote-controlled miner variant: its command-and-control daemon strings." strings: $a = "XMRigMinerServer" ascii $b = "XMRigCCServer" ascii $c = "cc-client" ascii $d = "control_command" ascii condition: uint32(0) == 0x464c457f and 2 of them } rule Linux_Coinminer_Generic_Pool { meta: name = "Linux.Coinminer.Pool-Embedded" severity = "warning" action = "alert" desc = "ELF binary embedding a mining pool endpoint and worker credentials." strings: $p1 = "stratum+tcp://" ascii $p2 = "pool.minexmr.com" ascii $p3 = "pool.supportxmr.com" ascii $p4 = "xmr.pool" ascii $p5 = "nanopool.org" ascii $p6 = "monerohash.com" ascii condition: uint32(0) == 0x464c457f and 2 of them } /* ────────────────────────── IoT / DDoS bots ─────────────────────── */ rule Linux_Bot_Mirai { meta: name = "Linux.Bot.Mirai" severity = "critical" action = "quarantine" desc = "Mirai IoT bot: its bruteforce table and C2 report markers." strings: $a = "/dev/watchdog" ascii $b = "/dev/misc/watchdog" ascii $c = "GETLOCALIP" ascii $d = "listening tun0" ascii $e = "TSource Engine Query" ascii // Valve source query flood $f = "\\x00\\x00\\x00\\x01\\x00\\x00flood" ascii $g = "botnet" ascii condition: uint32(0) == 0x464c457f and 3 of them } rule Linux_Bot_Gafgyt { meta: name = "Linux.Bot.Gafgyt" severity = "critical" action = "quarantine" desc = "Gafgyt/BASHLITE DDoS bot: its command verbs and shell-spread strings." strings: $a = "PING" ascii fullword $b = "TCP flood" ascii nocase $c = "UDP flood" ascii nocase $d = "STDHEX" ascii $e = "GETLOCALIP" ascii $f = "HTTPFLOOD" ascii $g = "/bin/busybox" ascii $h = "\\x01\\x01\\x01\\x01" ascii condition: uint32(0) == 0x464c457f and $g and 3 of ($a,$b,$c,$d,$e,$f,$h) } rule Linux_Bot_Tsunami { meta: name = "Linux.Bot.Tsunami-Kaiten" severity = "critical" action = "quarantine" desc = "Tsunami/Kaiten IRC-controlled DDoS bot: its IRC command handlers." strings: $irc1 = "PRIVMSG" ascii $irc2 = "NOTICE %s :" ascii $c1 = "PAN " ascii $c2 = "UDP " ascii $c3 = "TSUNAMI" ascii $c4 = "SPOOFS" ascii $c5 = "GETSPOOFS" ascii condition: uint32(0) == 0x464c457f and 1 of ($irc*) and 2 of ($c*) } /* ─────────────────────────── backdoors ──────────────────────────── */ rule Linux_Backdoor_XorDDoS { meta: name = "Linux.Backdoor.XorDDoS" severity = "critical" action = "quarantine" desc = "XorDDoS trojan: its XOR-key config markers and installer paths." strings: $a = "BB2FA36AAA9541F0" ascii // known XOR key marker $b = "/lib/libudev.so" ascii $c = "rootkit" ascii $d = "md5=" ascii $e = "hostname" ascii $f = "cat /proc/net/dev" ascii condition: uint32(0) == 0x464c457f and ($a or ($b and $c)) and 2 of ($d,$e,$f) } rule Linux_Backdoor_TinyShell { meta: name = "Linux.Backdoor.TinyShell" severity = "critical" action = "quarantine" desc = "Tiny SHell (tsh) backdoor: its default password constant and mode banner." strings: $a = "tsh" ascii fullword $b = "GET_FILE" ascii $c = "PUT_FILE" ascii $d = "RUNSHELL" ascii $e = "can't create socket" ascii condition: uint32(0) == 0x464c457f and $d and 2 of ($a,$b,$c,$e) } rule Linux_Backdoor_Rekoobe { meta: name = "Linux.Backdoor.Rekoobe" severity = "critical" action = "quarantine" desc = "Rekoobe/TinySHell-derived backdoor as seen against SPARC/x86 servers." strings: $a = "d[%d]" ascii $b = "/tmp/.X11-unix/" ascii $c = "/proc/%d/cmdline" ascii $d = "HISTFILE" ascii $e = "cmd.notify" ascii condition: uint32(0) == 0x464c457f and $b and 2 of ($a,$c,$d,$e) } rule Linux_Backdoor_BPFDoor { meta: name = "Linux.Backdoor.BPFDoor" severity = "critical" action = "quarantine" desc = "BPFDoor passive backdoor: its magic-packet handling and process masquerade." strings: $a = "/var/run/haldrund.pid" ascii $b = "/dev/shm/kdmtmpflush" ascii $c = "hald-addon-volume" ascii $d = "avahi-daemon: chroot helper" ascii $e = "/sbin/mingetty /dev/tty6" ascii condition: uint32(0) == 0x464c457f and 2 of them } /* ───────────────────────────── rootkits ─────────────────────────── */ rule Linux_Rootkit_Diamorphine { meta: name = "Linux.Rootkit.Diamorphine" severity = "critical" action = "quarantine" desc = "Diamorphine LKM rootkit: its signal numbers, magic prefix and module strings." strings: $a = "diamorphine" ascii nocase $b = "module_hide" ascii $c = "is_invisible" ascii $d = "hacked_getdents" ascii $e = "hacked_kill" ascii $f = "signal=" ascii condition: uint32(0) == 0x464c457f and 2 of them } rule Linux_Rootkit_Reptile { meta: name = "Linux.Rootkit.Reptile" severity = "critical" action = "quarantine" desc = "Reptile LKM rootkit and its userland client: control tags and hook names." strings: $a = "reptile" ascii nocase $b = "hexptamp" ascii $c = "magic_prefix" ascii $d = "hide_pid" ascii $e = "kaudit" ascii $f = "/reptile/reptile_shell" ascii condition: uint32(0) == 0x464c457f and 2 of them } rule Linux_Rootkit_Bedevil { meta: name = "Linux.Rootkit.Bedevil" severity = "critical" action = "quarantine" desc = "bedevil (bdvl) LD_PRELOAD rootkit: its config env vars and hook set." strings: $a = "bdvl" ascii $b = "BDVL" ascii $c = "shell_pass" ascii $d = "hidden_port" ascii $e = "ldpreloadhijack" ascii nocase condition: uint32(0) == 0x464c457f and 2 of them } rule Linux_Rootkit_Preload_Config { meta: name = "Linux.Rootkit.Preload-Config" severity = "critical" action = "alert" desc = "An /etc/ld.so.preload entry pointing at a non-package library — classic userland-rootkit persistence." strings: $so = /\/(tmp|dev\/shm|var\/tmp)\/[A-Za-z0-9._-]+\.so/ condition: // ld.so.preload is one short line per library. A real one names // packaged libraries under /usr/lib or /lib; a path under /tmp, // /dev/shm or /var/tmp is the tell. filesize < 4096 and $so } /* ─────────────────────────── ransomware ─────────────────────────── */ rule Linux_Ransom_RansomEXX { meta: name = "Linux.Ransomware.RansomEXX" severity = "critical" action = "quarantine" desc = "RansomEXX Linux encryptor: its ransom-note template and ecc markers." strings: $a = "!NEWS_FOR_EXX_COMPANY!" ascii $b = ".ransomexx" ascii $c = "ransom.note" ascii $d = "encrypt_file" ascii $e = "mbedtls_" ascii condition: uint32(0) == 0x464c457f and ($a or $b) and 1 of ($c,$d,$e) } rule Linux_Ransom_DarkSide_ESXi { meta: name = "Linux.Ransomware.DarkSide-ESXi" severity = "critical" action = "quarantine" desc = "DarkSide/BlackMatter ESXi Linux locker: its esxcli VM-kill and note strings." strings: $a = "esxcli vm process list" ascii $b = "esxcli vm process kill" ascii $c = "README" ascii $d = ".onion" ascii $e = "encrypted by" ascii nocase condition: uint32(0) == 0x464c457f and ($a or $b) and 2 of ($c,$d,$e) } rule Linux_Ransom_Note_Generic { meta: name = "Linux.Ransomware.Note" severity = "warning" action = "alert" desc = "A dropped ransom note: payment demand plus a Tor contact address." strings: $t1 = "your files have been encrypted" ascii nocase $t2 = "all your files are encrypted" ascii nocase $t3 = "to decrypt your files" ascii nocase $onion = /[a-z2-7]{16,56}\.onion/ $btc = /\b(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,39}\b/ condition: filesize < 64KB and 1 of ($t*) and ($onion or $btc) } /* ──────────────────────────── webshells ─────────────────────────── */ rule Linux_Webshell_JSP_Eval { meta: name = "Linux.Webshell.JSP" severity = "critical" action = "alert" desc = "JSP webshell: runtime command execution driven by a request parameter." strings: $tag = "<%" $rt = "Runtime.getRuntime().exec" ascii $pb = "ProcessBuilder" ascii $req1 = "request.getParameter" ascii $req2 = "request.getHeader" ascii condition: filesize < 512KB and $tag in (0..4096) and ($rt or $pb) and 1 of ($req*) } rule Linux_Webshell_ASP_Eval { meta: name = "Linux.Webshell.ASP" severity = "critical" action = "alert" desc = "ASP/ASPX webshell: eval of a request value." strings: $tag = "<%" $e1 = "eval(Request" ascii nocase $e2 = "Execute(Request" ascii nocase $e3 = "Server.CreateObject" ascii nocase $e4 = "System.Diagnostics.Process" ascii condition: filesize < 512KB and $tag in (0..4096) and 1 of ($e*) } rule Linux_Webshell_PHP_Obfuscated { meta: name = "Linux.Webshell.PHP-Obfuscated" severity = "critical" action = "alert" desc = "Obfuscated PHP webshell: a variable-variable or char-assembled callback on request input." strings: $php = "&?\s*\/dev\/tcp\/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,5}/ $re = "0>&1" condition: filesize < 128KB and $sh and $re } rule Linux_ReverseShell_Interpreter { meta: name = "Linux.ReverseShell.Interpreter" severity = "critical" action = "alert" desc = "A reverse shell in python/perl/ruby: a socket connect wired to a shell spawn." strings: $sock = "socket.socket(" ascii $conn = ".connect((" ascii $dup = "os.dup2(" ascii $pty = "pty.spawn(" ascii $sh = /"\/bin\/(sh|bash)"/ ascii $pl = /use\s+Socket\s*;/ ascii $plc = /connect\([A-Z0-9_]+\s*,\s*sockaddr_in/ ascii $rb = /TCPSocket\.(new|open)\(/ ascii $rbx = /exec\s*\(?\s*"\/bin\// ascii condition: filesize < 128KB and ( // Python: connect to a socket and hand a shell its fds. ($sock and $conn and ($sh or $dup or $pty)) // Perl: Socket module plus a raw connect() to a sockaddr_in. or ($pl and $plc) // Ruby: a TCPSocket wired to an exec of a shell. or ($rb and $rbx) ) } /* ─────────────────────── misc / suspicious ──────────────────────── */ rule Linux_Malware_EmbeddedElf_B64 { meta: name = "Linux.Dropper.Base64Elf" severity = "warning" action = "alert" desc = "A script carrying a base64-encoded ELF payload (the 'f0VMR' magic prefix) that it decodes and runs." strings: $sb = "#!/bin/" $b64 = "f0VMR" // base64 of \x7fELF $dec1 = "base64 -d" ascii $dec2 = "base64 --decode" ascii $dec3 = "openssl base64 -d" ascii condition: filesize < 8MB and $sb in (0..64) and $b64 and 1 of ($dec*) } rule Linux_Malware_HistoryTamper { meta: name = "Linux.Malware.HistoryTamper" severity = "warning" action = "alert" desc = "A script that disables shell history and clears logs — anti-forensics wrapped around other activity." strings: $sb = "#!/bin/" $h1 = "unset HISTFILE" ascii $h2 = "export HISTSIZE=0" ascii $h3 = "HISTFILESIZE=0" ascii $h4 = "set +o history" ascii $l1 = "/var/log/wtmp" ascii $l2 = "/var/log/secure" ascii $l3 = "/var/log/auth.log" ascii condition: filesize < 128KB and $sb in (0..64) and 1 of ($h*) and 1 of ($l*) } rule Linux_Malware_Persistence_CronDownload { meta: name = "Linux.Malware.CronDownloader" severity = "critical" action = "alert" desc = "A crontab entry that periodically re-downloads and runs a payload — miner/bot re-infection persistence." strings: $sched = /(\*|[0-9,\/-]+)\s+(\*|[0-9,\/-]+)\s+(\*|[0-9,\/-]+)\s+(\*|[0-9,\/-]+)\s+(\*|[0-9,\/-]+)\s/ $dl = /(curl|wget)\s[^\n]{0,200}\|\s*(sh|bash)/ condition: filesize < 64KB and $sched and $dl } rule Linux_Malware_LdPreloadEnvInject { meta: name = "Linux.Malware.LdPreloadInject" severity = "warning" action = "alert" desc = "A script exporting LD_PRELOAD to a payload in a world-writable directory — library-injection persistence." strings: $sb = "#!/bin/" $ld = /LD_PRELOAD=[^\n]{0,120}\/(tmp|dev\/shm|var\/tmp)\// condition: filesize < 64KB and $sb in (0..64) and $ld } rule Linux_Malware_SetuidBackdoor_Script { meta: name = "Linux.Malware.SetuidRootShell" severity = "critical" action = "alert" desc = "A script that plants a setuid-root shell for privilege persistence." strings: $sb = "#!/bin/" $cp = /cp\s+[^\n]{0,80}\/(bin|usr\/bin)\/(ba)?sh\s/ $chm = /chmod\s+([46][0-7]{3}|u\+s|\+s)\s/ condition: filesize < 64KB and $sb in (0..64) and $cp and $chm }