2. 系统调用基础:系统调用的概念、用户态与内核态切换、常见系统调用分类

系统调用(System Call)是用户空间程序请求内核服务的唯一合法入口。在 Linux 安全审计中,每一次系统调用都可能成为攻击者留下的足迹。理解系统调用的本质、切换机制与分类,是进行安全事件溯源的前提。

2.1 系统调用的概念

系统调用是操作系统内核提供给用户空间程序的一组标准接口,用于执行特权操作(如读写文件、创建进程、网络通信)。用户程序不能直接访问内核空间,必须通过系统调用陷入内核,由内核代表用户完成操作。

关键特征:
  • 原子性:系统调用在内核态执行,不会被用户态信号中断。
  • 特权分离:用户态无法直接操作硬件或内核数据结构。
  • 审计锚点:所有安全审计工具(如 auditd、sysdig)均基于系统调用拦截。
对比维度 系统调用 库函数(如 glibc) Shell 命令
执行层级 内核态 用户态(可能封装系统调用) 用户态(调用库函数)
直接审计 是(auditd 直接捕获) 否(需跟踪到内部系统调用) 否(需解析进程行为)
性能开销 较高(上下文切换) 较低(无切换) 高(进程创建)
安全溯源价值 最高(原始行为记录) 中等(需反推) 低(已高度抽象)
安全提示: 攻击者即使使用混淆后的二进制文件或加密 shell,最终仍会触发系统调用。因此,系统调用审计是溯源攻击链的“不可绕过”层。

2.2 用户态与内核态切换

CPU 通过特权级别(Ring 0 ~ Ring 3)隔离用户态与内核态。Linux 使用 Ring 3 运行用户程序,Ring 0 运行内核。系统调用触发时,CPU 必须完成一次完整的上下文切换。

2.2.1 切换流程

  1. 触发陷阱:用户程序执行 syscall(x86-64)或 int 0x80(x86)指令。
  2. 保存上下文:CPU 自动将用户态寄存器(RIP、CS、RSP、SS、EFLAGS)压入内核栈。
  3. 切换栈:从用户栈切换到内核栈(每个进程对应一个内核栈)。
  4. 查找系统调用表:根据系统调用号(如 __NR_read = 0)索引 sys_call_table。
  5. 执行内核函数:调用对应处理函数(如 sys_read)。
  6. 返回用户态:恢复上下文,执行 sysret 或 iret 指令。
用户态与内核态切换流程 用户态 (Ring 3) 应用程序 调用 read() 库函数 执行 syscall 指令 内核态 (Ring 0) 保存用户态寄存器 切换至内核栈 执行 sys_read() syscall 指令 上下文切换 sysret 指令 恢复上下文 切换开销与安全影响 • 每次系统调用约 100~200 纳秒(现代 CPU) • 攻击者可能利用“熔断”“幽灵”漏洞绕过隔离 • 审计日志记录系统调用号、参数、返回值、时间戳 • 高频系统调用(如 I/O)是性能瓶颈,也是攻击高频区域
安全关注点: 系统调用切换是 CPU 级事件,无法被用户态代码隐藏。即使攻击者使用 rootkit 修改了系统调用表,切换过程本身仍会被硬件记录(如 Intel PT),这是高级溯源的突破口。

2.3 常见系统调用分类

Linux 提供约 300~400 个系统调用(版本不同有差异)。从安全审计角度,可将其分为三大核心类别:文件操作、进程控制、网络通信。每一类都对应典型的攻击行为模式。

2.3.1 文件系统调用

文件系统调用是审计日志中出现频率最高的类别。攻击者读取配置文件、写入恶意脚本、修改权限等行为均通过此类调用完成。

系统调用 功能 典型攻击场景 审计关键字段
open / openat 打开或创建文件 读取 /etc/shadow、写入 webshell 文件名、标志位(O_RDONLY/O_WRONLY)
read / write 读写文件内容 窃取数据库文件、写入后门 文件描述符、字节数
chmod / fchmod 修改文件权限 将恶意脚本设为可执行(+x) 新权限模式(如 0755)
unlink / rename 删除或重命名文件 清除日志、替换系统二进制文件 旧路径、新路径
mmap 内存映射文件 加载恶意共享库、绕过文件扫描 映射地址、保护标志

2.3.2 进程系统调用

进程控制类系统调用直接反映攻击者的横向移动、权限提升、持久化等行为。

系统调用 功能 典型攻击场景 审计关键字段
fork / clone 创建子进程/线程 挖矿程序批量派生进程 子进程 PID、标志位
execve / execveat 执行新程序 反弹 shell、运行恶意二进制 程序路径、参数列表
kill / tkill 发送信号 终止安全进程(如 kill -9 agent) 目标 PID、信号编号
ptrace 进程跟踪/调试 注入代码、内存修改 被跟踪进程 PID、请求类型
setuid / setgid 设置用户/组 ID 提权至 root 新 UID/GID

2.3.3 网络系统调用

网络系统调用是远程攻击、数据外泄、C2 通信的直接证据。

系统调用 功能 典型攻击场景 审计关键字段
socket 创建套接字 建立反向连接、监听端口 协议族(AF_INET)、类型(SOCK_STREAM)
connect 发起连接 反弹 shell 连接 C2 服务器 目标 IP、端口
bind / listen 绑定端口并监听 植入后门监听 4444 端口 本地端口、地址
sendto / recvfrom 发送/接收数据 外泄敏感数据、接收指令 数据长度、对端地址
setsockopt 设置套接字选项 设置超时、复用地址(SO_REUSEADDR) 选项名、选项值
系统调用分类与攻击溯源映射 系统调用审计 文件系统调用 进程系统调用 网络系统调用 文件攻击场景 • 读取 /etc/shadow • 写入 webshell • 删除审计日志 • 修改 SSH 密钥 进程攻击场景 • 反弹 shell (execve) • 提权 (setuid) • 代码注入 (ptrace) • 挖矿进程 (fork) 网络攻击场景 • C2 通信 (connect) • 端口监听 (bind) • 数据外泄 (sendto) • DNS 隧道 (socket)

2.4 系统调用号与审计日志格式

每个系统调用在 sys_call_table 中对应唯一的系统调用号。审计日志(如 auditd 的 ausearch 输出)会记录系统调用号及其参数。

# 查看 x86-64 系统调用号(部分)
# /usr/include/asm/unistd_64.h

#define __NR_read           0
#define __NR_write          1
#define __NR_open           2
#define __NR_close          3
#define __NR_stat           4
#define __NR_fstat          5
#define __NR_lstat          6
#define __NR_poll           7
#define __NR_lseek          8
#define __NR_mmap           9
#define __NR_mprotect      10
#define __NR_munmap        11
#define __NR_brk           12
#define __NR_rt_sigaction  13
#define __NR_rt_sigprocmask 14
#define __NR_rt_sigreturn  15
#define __NR_ioctl         16
#define __NR_pread64       17
#define __NR_pwrite64      18
#define __NR_readv         19
#define __NR_writev        20
审计日志示例(auditd):
type=SYSCALL msg=audit(1700000000.123:456):
  arch=c000003e syscall=2   # __NR_open
  success=yes exit=3
  a0=7ffe12345678 a1=0 a2=1b6 a3=0
  items=1 ppid=1234 pid=5678
  auid=1000 uid=0 gid=0
  comm="bash" exe="/usr/bin/bash"
  key="file_monitor"

关键字段解析:syscall=2 表示 open 系统调用;a0 为文件路径指针;success=yes 表示调用成功;uid=0 表示以 root 身份执行。

2.5 系统调用与安全审计的关联

系统调用是安全审计的“原子事件”。每一次攻击行为,无论多么隐蔽,最终都会表现为一系列系统调用的组合。理解这种映射关系,是构建溯源规则的基础。

攻击阶段 典型系统调用序列 审计检测策略
信息收集 open(/etc/passwd) → read → close 监控敏感文件读取
权限提升 setuid(0) → execve(/bin/sh) 检测非授权 UID 切换
持久化 open(/etc/cron.d/malware) → write → chmod 监控 cron 目录写入
横向移动 socket(AF_INET) → connect(10.0.0.5:22) → fork → execve(ssh) 检测异常 SSH 连接
数据外泄 open(/var/lib/mysql/data.sql) → read → socket → sendto(8.8.8.8:53) 检测大流量 DNS 查询
实践建议: 在搭建审计规则时,不要只监控单个系统调用,而应关注“系统调用序列模式”。例如,open + write + chmod 的组合比单独的 open 更具威胁指示性。