用 systemd 给老程序加防护:一份不依赖内核的缓解清单
来源:clehaxze.tw — 2026-11-04
📋 概述
clehaxze 应读者追问,把「不依赖内核补丁、不需要重新编译程序」的 Linux 缓解措施写成可操作指南。核心原则只有一句:假设你的程序是恶意的,然后夺走它能碰到的东西。按投入产出比排序:加固分配器(hardened_malloc 首选,mimalloc secure 与 scudo 备选,越界一字节就在 free 时 canary 崩溃);用 systemd 的 SystemCallFilter 禁掉 @mount、@module、io_uring、bpf、execve、fork 等,让攻击者无法起 shell;用 ProtectSystem/ProtectHome/PrivateTmp/InaccessiblePaths 限制文件系统;或用 TemporaryFileSystem=/:ro 加 BindReadOnlyPaths 反做成白名单;用 NoExecPaths 只允许特定二进制被执行;按用户写 iptables 规则限制出网;NoNewPrivileges 与 MemoryDenyWriteExecute(Node/.NET/Java/PHP8/PCRE 因 JIT 不能开);CET 影子栈防 ROP;最后是自编译 glibc 让攻击者手里的偏移失效,以及 PHP-FPM 的 deepbind shim。
🔑 核心要点
- 加固分配器是最划算的一刀:不依赖新内核,直接对付堆溢出与 use-after-free。
- 越界一字节在 glibc 下平安无事,在 hardened_malloc 下 free 时直接 canary corrupted。
- 禁掉 execve 与 fork,攻击者拿到 RCE 也起不了 shell,这是收益最高的一组 syscall 过滤。
- 白名单比黑名单稳:TemporaryFileSystem=/:ro 加 BindReadOnlyPaths,再逐个把路径加回来。
- MemoryDenyWriteExecute 会打死所有 JIT:Node、.NET、Java、PHP 8+、PCRE 都不能开。
- 影子栈要显式打开:GLIBC_TUNABLES=glibc.cpu.hwcaps=SHSTK,且所有加载的二进制都得兼容。
- 自编译 glibc 的价值是让 system() 的偏移对攻击者未知,属于最后一道而非第一道防线。
💡 金句
加缓解措施时的核心原则是:假设你的程序是恶意的,然后通过夺走它能碰到的东西来限制它能做的恶。
👍 0
👎 0
← 返回 Lobsters 首页