653 lines
21 KiB
Plaintext
653 lines
21 KiB
Plaintext
/*
|
|
* perfctl.yar — YARA rules for perfctl/perfcc Linux userland rootkit family
|
|
* and adjacent threats commonly seen on the same compromised hosts
|
|
* (cryptominers, proxyjacking agents, LD_PRELOAD rootkits, SSH backdoors).
|
|
*
|
|
* Usage with clean.sh:
|
|
* YARA_RULES=/srv/perfctl.yar ROOTFS=/vz/root/101 ./clean.sh
|
|
*
|
|
* Or standalone:
|
|
* yara -r /srv/perfctl.yar /mnt/target-rootfs/
|
|
*
|
|
* SOURCES:
|
|
* - Aqua Nautilus, "perfctl: A Stealthy Malware Targeting Millions of Linux
|
|
* Servers" (October 2024) — full IoC table: file paths, hashes, IPs,
|
|
* domains, env vars. https://www.aquasec.com/blog/perfctl-a-stealthy-
|
|
* malware-targeting-millions-of-linux-servers/
|
|
* - Florian Roth / Nextron Systems, signature-base, XMRig + cryptominer
|
|
* rules. https://github.com/Neo23x0/signature-base — DRL 1.1 licensed,
|
|
* attribution retained in meta.
|
|
* - Yara-Rules community repo (MALW_XMRIG_Miner).
|
|
* https://github.com/Yara-Rules/rules
|
|
* - bleepingcomputer / thehackernews / darkreading perfctl writeups
|
|
* (Oct 2024) for independent IoC confirmation.
|
|
* - Remaining rules (proxyjacking agents, PAM stealer, LKM names,
|
|
* perfctl-specific binary rules) written for this file based on the
|
|
* published IoCs — no equivalent public rules exist as of April 2026.
|
|
*/
|
|
|
|
import "hash"
|
|
|
|
// =========================================================================
|
|
// perfctl / perfcc rootkit family — specific rules
|
|
// =========================================================================
|
|
|
|
rule perfctl_known_hashes
|
|
{
|
|
meta:
|
|
description = "File matches a known perfctl/perfcc MD5 from Aqua IoC table"
|
|
author = "clean.sh incident response"
|
|
family = "perfctl"
|
|
severity = "critical"
|
|
reference = "https://www.aquasec.com/blog/perfctl-a-stealthy-malware-targeting-millions-of-linux-servers/"
|
|
|
|
condition:
|
|
// main malware
|
|
hash.md5(0, filesize) == "656e22c65bf7c04d87b5afbe52b8d800" or
|
|
// cryptominer
|
|
hash.md5(0, filesize) == "6e7230dbe35df5b46dcd08975a0cc87f" or
|
|
// rootkit (libgcwrap.so)
|
|
hash.md5(0, filesize) == "835a9a6908409a67e51bce69f80dd58a" or
|
|
// trojanized ldd
|
|
hash.md5(0, filesize) == "cf265a3a3dd068d0aa0c70248cd6325d" or
|
|
// trojanized top
|
|
hash.md5(0, filesize) == "da006a0b9b51d56fa3f9690cf204b99f" or
|
|
// wizlmsh persistence binary
|
|
hash.md5(0, filesize) == "ba120e9c7f8896d9148ad37f02b0e3cb"
|
|
}
|
|
|
|
rule perfctl_libgcwrap_rootkit
|
|
{
|
|
meta:
|
|
description = "perfctl userland rootkit — LD_PRELOAD shared object"
|
|
author = "clean.sh incident response"
|
|
family = "perfctl"
|
|
severity = "critical"
|
|
reference = "https://www.aquasec.com/blog/perfctl-a-stealthy-malware-targeting-millions-of-linux-servers/"
|
|
|
|
strings:
|
|
$soname = "libgcwrap.so"
|
|
// operator-bypass env vars (from Aqua IoC table)
|
|
$env1 = "AAZHDE"
|
|
$env2 = "FPROF"
|
|
$env3 = "A2ZNODE"
|
|
$env4 = "VEI"
|
|
$env5 = "ABWTRX"
|
|
$hide1 = "perfctl"
|
|
$hide2 = "perfcc"
|
|
$hook1 = "readdir"
|
|
$hook2 = "readdir64"
|
|
$hook3 = "__xstat"
|
|
$hook4 = "__lxstat"
|
|
$hook5 = "getdents"
|
|
$hook6 = "getdents64"
|
|
$preload = "/etc/ld.so.preload"
|
|
|
|
condition:
|
|
uint32(0) == 0x464C457F and
|
|
filesize < 5MB and
|
|
(
|
|
$soname or
|
|
( 1 of ($env*) and 3 of ($hook*) ) or
|
|
( any of ($hide*) and $preload )
|
|
)
|
|
}
|
|
|
|
rule perfctl_perfcc_installer
|
|
{
|
|
meta:
|
|
description = "perfctl main installer / dropper binary (perfcc)"
|
|
author = "clean.sh incident response"
|
|
family = "perfctl"
|
|
severity = "critical"
|
|
|
|
strings:
|
|
$n1 = "perfcc"
|
|
$n2 = "perfctl"
|
|
$n3 = "libgcwrap"
|
|
$d1 = "/tmp/.xdiag"
|
|
$d2 = "/tmp/.perf.c"
|
|
$d3 = "/tmp/.dmesg"
|
|
$d4 = "/tmp/smpr"
|
|
$d5 = "/root/.config/cron/perfcc"
|
|
$p1 = "ld.so.preload"
|
|
$p2 = "AAZHDE"
|
|
$p3 = "FPROF"
|
|
$p4 = "A2ZNODE"
|
|
$p5 = "ABWTRX"
|
|
|
|
condition:
|
|
uint32(0) == 0x464C457F and
|
|
filesize < 50MB and
|
|
( 2 of ($n*) or (1 of ($n*) and any of ($d*)) or (any of ($p*) and any of ($d*)) )
|
|
}
|
|
|
|
rule perfctl_wizlmsh_suid_backdoor
|
|
{
|
|
meta:
|
|
description = "perfctl SUID backdoor (wizlmsh / kkbush / zipgrepjournalctl)"
|
|
author = "clean.sh incident response"
|
|
family = "perfctl"
|
|
severity = "critical"
|
|
|
|
strings:
|
|
$n1 = "wizlmsh"
|
|
$n2 = "kkbush"
|
|
$n3 = "zipgrepjournalctl"
|
|
$s1 = "setuid"
|
|
$s2 = "execve"
|
|
$s3 = "/bin/sh"
|
|
|
|
condition:
|
|
uint32(0) == 0x464C457F and
|
|
filesize < 5MB and
|
|
any of ($n*) and 2 of ($s*)
|
|
}
|
|
|
|
rule perfctl_dropper_paths_in_any_file
|
|
{
|
|
meta:
|
|
description = "File of any type references known perfctl dropper paths"
|
|
author = "clean.sh incident response"
|
|
family = "perfctl"
|
|
severity = "high"
|
|
|
|
strings:
|
|
$p1 = "/tmp/.xdiag"
|
|
$p2 = "/tmp/.perf.c"
|
|
$p3 = "/tmp/.apid"
|
|
$p4 = "/tmp/gd.sh"
|
|
$p5 = "/tmp/ccrl"
|
|
$p6 = "/tmp/javax64"
|
|
$p7 = "/tmp/kubeupd"
|
|
$p8 = "/tmp/wttwe"
|
|
$p9 = "/tmp/smpr"
|
|
$p10 = "/dev/shm/libfsnldev.so"
|
|
$p11 = "libfsnldev.so"
|
|
$p12 = "libfsnkdev.so" // variant spelling seen in Aqua IoC
|
|
$p13 = "libpprocps.so"
|
|
$p14 = "/root/.config/cron/perfcc"
|
|
|
|
condition:
|
|
filesize < 20MB and 2 of them
|
|
}
|
|
|
|
rule perfctl_cron_persistence
|
|
{
|
|
meta:
|
|
description = "Cron job referencing perfctl/perfcc persistence"
|
|
author = "clean.sh incident response"
|
|
family = "perfctl"
|
|
severity = "high"
|
|
|
|
strings:
|
|
$c1 = "perfcc"
|
|
$c2 = "perfctl"
|
|
$c3 = "perfclean"
|
|
$c4 = "libgcwrap"
|
|
$c5 = "AAZHDE"
|
|
$c6 = "FPROF"
|
|
$c7 = "A2ZNODE"
|
|
$c8 = "ABWTRX"
|
|
$cron1 = "* * * * *"
|
|
$cron2 = "@reboot"
|
|
$cron3 = "@hourly"
|
|
$cron4 = "@daily"
|
|
|
|
condition:
|
|
filesize < 100KB and
|
|
1 of ($cron*) and 1 of ($c*)
|
|
}
|
|
|
|
rule perfctl_known_filenames
|
|
{
|
|
meta:
|
|
description = "File matches a known perfctl IoC filename (catch-all)"
|
|
author = "clean.sh incident response"
|
|
family = "perfctl"
|
|
severity = "critical"
|
|
|
|
strings:
|
|
$n1 = "libgcwrap.so"
|
|
$n2 = "libfsnldev.so"
|
|
$n3 = "libfsnkdev.so"
|
|
$n4 = "libpprocps.so"
|
|
$n5 = "wizlmsh"
|
|
$n6 = "kkbush"
|
|
$n7 = "kubeupd"
|
|
$n8 = "perfcc"
|
|
$n9 = "perfctl"
|
|
$n10 = "perfclean"
|
|
$n11 = "zipgrepjournalctl"
|
|
$n12 = "javax64"
|
|
|
|
condition:
|
|
filesize < 100MB and any of them
|
|
}
|
|
|
|
rule perfctl_network_indicators
|
|
{
|
|
meta:
|
|
description = "Binary or script references published perfctl IPs / C2 domains"
|
|
author = "clean.sh incident response"
|
|
family = "perfctl"
|
|
severity = "high"
|
|
reference = "Aqua Nautilus IoC table (Oct 2024)"
|
|
|
|
strings:
|
|
// C2 / download servers
|
|
$ip1 = "211.234.111.116"
|
|
$ip2 = "46.101.139.173"
|
|
$ip3 = "104.183.100.189"
|
|
$ip4 = "198.211.126.180"
|
|
// Tor relay nodes the malware connects to
|
|
$ip5 = "80.67.172.162"
|
|
$ip6 = "176.10.107.180"
|
|
$ip7 = "78.47.18.110"
|
|
$ip8 = "95.217.109.36"
|
|
$ip9 = "145.239.41.102"
|
|
// proxyjacking SaaS domains the malware installs clients for
|
|
$d1 = "bitping.com"
|
|
$d2 = "earn.fm"
|
|
$d3 = "speedshare.app"
|
|
$d4 = "repocket.com"
|
|
|
|
condition:
|
|
// require ELF or shebang — rule is IoC-aware, not a plain grep
|
|
( uint32(0) == 0x464C457F or uint16(0) == 0x2123 ) and
|
|
filesize < 10MB and any of them
|
|
}
|
|
|
|
// =========================================================================
|
|
// XMRig / cryptominer — Neo23x0 signature-base (DRL 1.1, Florian Roth)
|
|
// =========================================================================
|
|
|
|
rule XMRIG_Monero_Miner : HIGHVOL
|
|
{
|
|
meta:
|
|
description = "Detects Monero mining software (XMRig)"
|
|
license = "Detection Rule License 1.1 https://github.com/Neo23x0/signature-base/blob/master/LICENSE"
|
|
author = "Florian Roth (Nextron Systems)"
|
|
reference = "https://github.com/xmrig/xmrig/releases"
|
|
date = "2018-01-04"
|
|
modified = "2022-11-10"
|
|
hash1 = "5c13a274adb9590249546495446bb6be5f2a08f9dcd2fc8a2049d9dc471135c0"
|
|
hash2 = "08b55f9b7dafc53dfc43f7f70cdd7048d231767745b76dc4474370fb323d7ae7"
|
|
hash3 = "f3f2703a7959183b010d808521b531559650f6f347a5830e47f8e3831b10bad5"
|
|
hash4 = "0972ea3a41655968f063c91a6dbd31788b20e64ff272b27961d12c681e40b2d2"
|
|
id = "71bf1b9c-c806-5737-83a9-d6013872b11d"
|
|
|
|
strings:
|
|
$s1 = "'h' hashrate, 'p' pause, 'r' resume" fullword ascii
|
|
$s2 = "--cpu-affinity" ascii
|
|
$s3 = "set process affinity to CPU core(s), mask 0x3 for cores 0 and 1" ascii
|
|
$s4 = "password for mining server" fullword ascii
|
|
$s5 = "XMRig/%s libuv/%s%s" fullword ascii
|
|
|
|
condition:
|
|
( uint16(0) == 0x5a4d or uint16(0) == 0x457f ) and filesize < 10MB and 2 of them
|
|
}
|
|
|
|
rule XMRIG_Monero_Miner_Config
|
|
{
|
|
meta:
|
|
description = "XMRig config.json file"
|
|
license = "Detection Rule License 1.1"
|
|
author = "Florian Roth (Nextron Systems)"
|
|
reference = "https://github.com/xmrig/xmrig/releases"
|
|
date = "2018-01-04"
|
|
id = "374efe7f-9ef2-5974-8e24-f749183ab2d0"
|
|
|
|
strings:
|
|
$s2 = "\"cpu-affinity\": null, // set process affinity to CPU core(s), mask \"0x3\" for cores 0 and 1" fullword ascii
|
|
$s5 = "\"nicehash\": false // enable nicehash/xmrig-proxy support" fullword ascii
|
|
$s8 = "\"algo\": \"cryptonight\", // cryptonight (default) or cryptonight-lite" fullword ascii
|
|
|
|
condition:
|
|
( uint16(0) == 0x0a7b or uint16(0) == 0x0d7b ) and filesize < 5KB and 1 of them
|
|
}
|
|
|
|
rule PUA_LNX_XMRIG_CryptoMiner
|
|
{
|
|
meta:
|
|
description = "Detects XMRIG CryptoMiner (Linux ELF)"
|
|
license = "Detection Rule License 1.1"
|
|
author = "Florian Roth (Nextron Systems)"
|
|
reference = "Internal Research"
|
|
date = "2018-06-28"
|
|
modified = "2023-01-06"
|
|
hash1 = "10a72f9882fc0ca141e39277222a8d33aab7f7a4b524c109506a407cd10d738c"
|
|
id = "bbdeff2e-68cc-5bbe-b843-3cba9c8c7ea8"
|
|
|
|
strings:
|
|
$x1 = "number of hash blocks to process at a time (don't set or 0 enables automatic selection o" fullword ascii
|
|
$s2 = "'h' hashrate, 'p' pause, 'r' resume, 'q' shutdown" fullword ascii
|
|
$s3 = "* THREADS: %d, %s, aes=%d, hf=%zu, %sdonate=%d%%" fullword ascii
|
|
$s4 = ".nicehash.com" ascii
|
|
|
|
condition:
|
|
uint16(0) == 0x457f and filesize < 8000KB and ( 1 of ($x*) or 2 of them )
|
|
}
|
|
|
|
rule SUSP_XMRIG_String
|
|
{
|
|
meta:
|
|
description = "Suspicious XMRIG string in executable"
|
|
license = "Detection Rule License 1.1"
|
|
author = "Florian Roth (Nextron Systems)"
|
|
date = "2018-12-28"
|
|
modified = "2026-04-18 (clean.sh — require ELF/PE magic to reduce FP)"
|
|
id = "8c6f3e6e-df2a-51b7-81b8-21cd33b3c603"
|
|
|
|
strings:
|
|
$x1 = "xmrig.exe" fullword ascii
|
|
$x2 = "XMRig" fullword ascii
|
|
|
|
condition:
|
|
// only flag executables, not arbitrary text files
|
|
( uint16(0) == 0x457f or uint16(0) == 0x5a4d ) and
|
|
filesize < 10MB and 1 of them
|
|
}
|
|
|
|
rule CoinMiner_Strings : SCRIPT HIGHVOL
|
|
{
|
|
meta:
|
|
description = "Detects mining pool protocol strings in executable"
|
|
license = "Detection Rule License 1.1"
|
|
author = "Florian Roth (Nextron Systems)"
|
|
reference = "https://minergate.com/faq/what-pool-address"
|
|
date = "2018-01-04"
|
|
modified = "2021-10-26"
|
|
id = "ac045f83-5f32-57a9-8011-99a2658a0e05"
|
|
|
|
strings:
|
|
$sa1 = "stratum+tcp://" ascii
|
|
$sa2 = "stratum+udp://" ascii
|
|
$sa3 = "stratum+ssl://" ascii
|
|
$sb1 = "\"normalHashing\": true,"
|
|
|
|
condition:
|
|
filesize < 3000KB and 1 of them
|
|
}
|
|
|
|
rule PUA_CryptoMiner_cpuminer
|
|
{
|
|
meta:
|
|
description = "cpuminer-style crypto miner"
|
|
license = "Detection Rule License 1.1"
|
|
author = "Florian Roth (Nextron Systems)"
|
|
date = "2019-01-31"
|
|
hash1 = "ede858683267c61e710e367993f5e589fcb4b4b57b09d023a67ea63084c54a05"
|
|
id = "aebfdce9-c2dd-5f24-aa25-071e1a961239"
|
|
|
|
strings:
|
|
$s1 = "Stratum notify: invalid Merkle branch" fullword ascii
|
|
$s2 = "-t, --threads=N number of miner threads (default: number of processors)" fullword ascii
|
|
$s3 = "User-Agent: cpuminer/" ascii
|
|
$s4 = "hash > target (false positive)" fullword ascii
|
|
$s5 = "thread %d: %lu hashes, %s khash/s" fullword ascii
|
|
|
|
condition:
|
|
filesize < 5000KB and 1 of them
|
|
}
|
|
|
|
rule PUA_Crypto_Mining_CommandLine_Indicators : SCRIPT
|
|
{
|
|
meta:
|
|
description = "Command-line flags used by crypto miners"
|
|
license = "Detection Rule License 1.1"
|
|
author = "Florian Roth (Nextron Systems)"
|
|
reference = "https://www.poolwatch.io/coin/monero"
|
|
date = "2021-10-24"
|
|
id = "afe5a63a-08c3-5cb7-b4b1-b996068124b7"
|
|
|
|
strings:
|
|
$s01 = " --cpu-priority="
|
|
$s02 = "--donate-level=0"
|
|
$s03 = " -o pool."
|
|
$s04 = " -o stratum+tcp://"
|
|
$s05 = " --nicehash"
|
|
$s06 = " --algo=rx/0 "
|
|
// base64'd versions
|
|
$se1 = "LS1kb25hdGUtbGV2ZWw9"
|
|
$se2 = "0tZG9uYXRlLWxldmVsP"
|
|
$se3 = "tLWRvbmF0ZS1sZXZlbD"
|
|
$se4 = "c3RyYXR1bSt0Y3A6Ly"
|
|
$se5 = "N0cmF0dW0rdGNwOi8v"
|
|
$se6 = "zdHJhdHVtK3RjcDovL"
|
|
$se7 = "c3RyYXR1bSt1ZHA6Ly"
|
|
$se8 = "N0cmF0dW0rdWRwOi8v"
|
|
$se9 = "zdHJhdHVtK3VkcDovL"
|
|
|
|
condition:
|
|
filesize < 5000KB and 1 of them
|
|
}
|
|
|
|
rule linux_miner_pool_urls
|
|
{
|
|
meta:
|
|
description = "Binary or config references known Monero mining pools"
|
|
author = "clean.sh incident response"
|
|
family = "cryptominer"
|
|
severity = "medium"
|
|
|
|
strings:
|
|
$p1 = "pool.supportxmr.com"
|
|
$p2 = "xmr.nanopool.org"
|
|
$p3 = "xmr.2miners.com"
|
|
$p4 = "xmrpool.eu"
|
|
$p5 = "monerohash.com"
|
|
$p6 = "monero.crypto-pool.fr"
|
|
$p7 = "minexmr.com"
|
|
$p8 = "moneroocean.stream"
|
|
$p9 = "pool.hashvault.pro"
|
|
$p10 = "c3pool.com"
|
|
$p11 = "solscan.io"
|
|
$p12 = "pool.minexmr.com"
|
|
$p13 = "gulf.moneroocean.stream"
|
|
$p14 = "auto.c3pool.org"
|
|
|
|
condition:
|
|
filesize < 50MB and any of them
|
|
}
|
|
|
|
// =========================================================================
|
|
// Proxyjacking agents (residential-proxy SaaS abused for bandwidth theft)
|
|
// =========================================================================
|
|
|
|
rule linux_proxyjacking_agents
|
|
{
|
|
meta:
|
|
description = "Proxyjacking agent binary or install script (requires ELF or shell-script magic)"
|
|
author = "clean.sh incident response"
|
|
family = "proxyjacking"
|
|
severity = "high"
|
|
reference = "Aqua Nautilus perfctl report + Akamai/Sysdig proxyjacking writeups"
|
|
|
|
strings:
|
|
$a1 = "peer2profit" nocase
|
|
$a2 = "traffmonetizer" nocase
|
|
$a3 = "repocket" nocase
|
|
$a4 = "earnapp" nocase
|
|
$a5 = "honeygain" nocase
|
|
$a6 = "packetstream" nocase
|
|
$a7 = "bitping" nocase
|
|
$a8 = "speedshare" nocase
|
|
$a9 = "earnfm" nocase
|
|
$a10 = "earn.fm" nocase
|
|
$a11 = "IPRoyal" nocase
|
|
$a12 = "mysterium" nocase
|
|
$a13 = "urnetwork" nocase
|
|
$a14 = "proxyrack" nocase
|
|
$a15 = "pawns.app" nocase
|
|
$a16 = "traffmonetizer.com"
|
|
|
|
condition:
|
|
// require ELF binary or shell/python shebang — reject plain text
|
|
( uint32(0) == 0x464C457F or uint16(0) == 0x2123 ) and
|
|
filesize < 100MB and any of them
|
|
}
|
|
|
|
rule linux_proxyjacking_container_images
|
|
{
|
|
meta:
|
|
description = "Docker/container config referencing proxyjacking images"
|
|
author = "clean.sh incident response"
|
|
family = "proxyjacking"
|
|
severity = "high"
|
|
|
|
strings:
|
|
$i1 = "xmrig/xmrig" nocase
|
|
$i2 = "minerd" nocase
|
|
$i3 = "bitpinger" nocase
|
|
$i4 = "peer2profit/p2pclient" nocase
|
|
$i5 = "repocket/repocket" nocase
|
|
$i6 = "traffmonetizer" nocase
|
|
$i7 = "packetstream/psclient" nocase
|
|
$i8 = "honeygain/honeygain" nocase
|
|
$i9 = "iproyal/pawns" nocase
|
|
$cfg1 = "\"Image\":"
|
|
$cfg2 = "config.v2.json"
|
|
$cfg3 = "\"Cmd\":"
|
|
|
|
condition:
|
|
filesize < 10MB and any of ($i*) and any of ($cfg*)
|
|
}
|
|
|
|
// =========================================================================
|
|
// Generic LD_PRELOAD rootkit indicators (beyond perfctl-specific)
|
|
// =========================================================================
|
|
|
|
rule linux_ldpreload_rootkit_generic
|
|
{
|
|
meta:
|
|
description = "Generic LD_PRELOAD userland rootkit traits (tight condition to avoid libc FP)"
|
|
author = "clean.sh incident response"
|
|
family = "rootkit.ldpreload"
|
|
severity = "high"
|
|
|
|
strings:
|
|
$h1 = "readdir"
|
|
$h2 = "readdir64"
|
|
$h3 = "getdents"
|
|
$h4 = "getdents64"
|
|
$h5 = "__xstat"
|
|
$h6 = "__lxstat"
|
|
$d1 = "RTLD_NEXT"
|
|
$d2 = "dlsym"
|
|
$p1 = "/etc/ld.so.preload"
|
|
// distinctive rootkit config-string markers that do NOT appear in libc
|
|
$c1 = "HIDE_PROC" fullword
|
|
$c2 = "HIDE_FILE" fullword
|
|
$c3 = "MAGIC_STRING" fullword
|
|
$c4 = "hide_pid" fullword
|
|
$c5 = "hide_port" fullword
|
|
$c6 = "HIDE_TCP" fullword
|
|
$c7 = "HIDE_UDP" fullword
|
|
|
|
condition:
|
|
uint32(0) == 0x464C457F and
|
|
filesize < 5MB and
|
|
// require at least one distinctive rootkit marker — libc has the hook
|
|
// names and dlsym but not these config keywords
|
|
( 2 of ($h*) and any of ($d*) and any of ($c*) ) or
|
|
( 2 of ($h*) and $p1 and any of ($c*) )
|
|
}
|
|
|
|
rule linux_ldpreload_config_file
|
|
{
|
|
meta:
|
|
description = "ld.so.preload file pointing at known rootkit (tight — matches only known malicious SO names)"
|
|
author = "clean.sh incident response"
|
|
family = "rootkit.ldpreload"
|
|
severity = "critical"
|
|
|
|
strings:
|
|
$s1 = "libgcwrap"
|
|
$s2 = "libfsnldev"
|
|
$s3 = "libfsnkdev"
|
|
$s4 = "libpprocps"
|
|
|
|
condition:
|
|
filesize < 1KB and any of them
|
|
}
|
|
|
|
// =========================================================================
|
|
// SSH backdoors and credential stealers
|
|
// =========================================================================
|
|
|
|
rule linux_ssh_backdoor_authorized_keys_in_binary
|
|
{
|
|
meta:
|
|
description = "Binary contains embedded SSH public key (credential implant)"
|
|
author = "clean.sh incident response"
|
|
family = "backdoor.ssh"
|
|
severity = "high"
|
|
|
|
strings:
|
|
$k1 = "ssh-rsa AAAA"
|
|
$k2 = "ssh-ed25519 AAAA"
|
|
$k3 = "ecdsa-sha2-nistp256 AAAA"
|
|
$path1 = ".ssh/authorized_keys"
|
|
$path2 = "/root/.ssh"
|
|
|
|
condition:
|
|
uint32(0) == 0x464C457F and
|
|
filesize < 20MB and
|
|
any of ($k*) and any of ($path*)
|
|
}
|
|
|
|
rule linux_pam_credential_stealer
|
|
{
|
|
meta:
|
|
description = "PAM module that logs plaintext credentials to disk"
|
|
author = "clean.sh incident response"
|
|
family = "backdoor.pam"
|
|
severity = "critical"
|
|
|
|
strings:
|
|
$sym1 = "pam_sm_authenticate"
|
|
$sym2 = "pam_get_item"
|
|
$sym3 = "PAM_AUTHTOK"
|
|
$w1 = "fopen"
|
|
$w2 = "fprintf"
|
|
$w3 = "/tmp/"
|
|
$w4 = "/var/tmp/"
|
|
$w5 = "/dev/shm/"
|
|
$d1 = ".passwd"
|
|
$d2 = ".creds"
|
|
$d3 = ".log"
|
|
$d4 = "passwords.txt"
|
|
|
|
condition:
|
|
uint32(0) == 0x464C457F and
|
|
filesize < 2MB and
|
|
2 of ($sym*) and any of ($w*) and any of ($d*)
|
|
}
|
|
|
|
// =========================================================================
|
|
// LKM rootkit name match (cold-disk: filename-content only)
|
|
// =========================================================================
|
|
|
|
rule linux_lkm_rootkit_known_names
|
|
{
|
|
meta:
|
|
description = "Known Linux LKM rootkit by filename or symbol"
|
|
author = "clean.sh incident response"
|
|
family = "rootkit.lkm"
|
|
severity = "critical"
|
|
|
|
strings:
|
|
$n1 = "diamorphine"
|
|
$n2 = "reptile_module" nocase
|
|
$n3 = "suterusu" nocase
|
|
$n4 = "nuk3gh0st" nocase
|
|
$n5 = "kbeast" nocase
|
|
$n6 = "module_hide"
|
|
$n7 = "module_hidden"
|
|
$n8 = "adore-ng" nocase
|
|
|
|
condition:
|
|
filesize < 10MB and any of them
|
|
}
|