共享内存段未清理易被恶意复用导致本地提权,需通过ipcs/ipcrm识别清理孤儿段、限制shmall/shmmax配额、强制0600权限、敏感数据即时清零、优先使用memfd_create加密封印,并审计shmget调用。

共享内存段(Shared Memory Segment)若未及时清理,可能被恶意进程复用或篡改,成为本地提权(LPE)的攻击面。关键在于控制生命周期、限制访问权限、避免敏感数据残留。
识别并清理残留共享内存段
Linux 系统中,ipcs -m 可列出所有 System V 共享内存段。重点关注 lpid(最后操作进程 ID)为 0、nattch(当前附加数)为 0 且长期存在(如数小时以上)的段——这类段通常属于已崩溃或异常退出的进程,未被主动释放。
- 手动清理:用 ipcrm -m
删除指定 ID 的段;批量清理可结合 ipcs -m | awk '$5 == 0 && $6 == 0 {print $2}' | xargs -r ipcrm -m - 自动化防护:在服务启动脚本或 systemd unit 文件中添加 ExecStartPre=/bin/sh -c 'ipcs -m | awk \"$5 == 0 && $6 == 0 {print \$2}\" | xargs -r ipcrm -m',确保每次启动前清空孤儿段
限制共享内存段创建权限
默认情况下,普通用户可通过 shmget() 创建共享内存段。攻击者可借此分配大量段耗尽资源,或利用未设权限的段注入代码。需从内核和应用层双重约束:
- 启用 kernel.shmall 和 kernel.shmmax 限制:例如 sysctl -w kernel.shmall=2097152(单位页)、kernel.shmmax=8388608(单位字节),防止滥用内存配额
- 在应用调用 shmget() 时,必须显式设置 0600 权限(仅属主读写),禁止使用 0666;若需跨用户通信,应通过明确授权的 IPC 机制(如 Unix domain socket + credential passing)替代
避免敏感数据驻留共享内存
共享内存不自动清零,进程退出后内容仍保留在物理页中,可能被新进程映射读取。尤其当段用于传递密钥、令牌、凭证等信息时风险极高。
- 敏感数据写入后立即调用 shmctl(shmid, IPC_STAT, &buf) 获取段信息,再用 memset() 清零对应地址空间;退出前再次清零并调用 shmdt() 分离
- 优先使用 memfd_create()(配合 MFD_CLOEXEC | MFD_ALLOW_SEALING)替代传统 shmget(),支持加密封印(sealing)防止写入或重映射,更适合作为安全临时缓冲区
监控异常共享内存行为
定期审计共享内存使用模式有助于发现潜在提权尝试。可结合 auditd 或 eBPF 工具捕获可疑调用:
- 配置 audit 规则:auditctl -a always,exit -F arch=b64 -S shmget -F key=shm_access,记录所有 shmget 调用及调用者 UID/PID
- 关注非预期用户(如低权限服务账户)创建大尺寸(>1MB)、高权限(0666)或频繁重建的段;此类行为常见于利用 CVE-2021-3156(sudo heap-based overflow)等漏洞后的横向驻留阶段










