1. 从“切用户”到“提权”Linux权限体系的底层逻辑先聊个真实场景。你刚装好一台Linux服务器用root登录折腾完一轮然后习惯性敲了个useradd建了个普通账号。接下来问题就来了普通用户想装个软件、改个系统配置动不动就Permission denied。这时候你就得在“切用户”和“sudo提权”之间来回倒腾。很多新手把这两个操作混为一谈实际上它们解决的是两个完全不同的需求用户切换su/login换一个身份重新登录本质是“变成另一个人”。sudo提权sudo以当前用户身份执行某条命令但临时借用root或其他用户的权限本质是“借用一下别人的工牌”。前者是“换人”后者是“借权”。这两个概念背后是Linux安全模型里最核心的东西——用户、组、权限位。理解不透这两招你后面看什么/etc/passwd、/etc/sudoers、sudo -i、su -都会是一团浆糊。这篇文章不打算抄man手册我就按实际运维和日常使用的场景把用户切换与sudo提权的原理、配置、坑、面试题一次聊透。你会看到为什么su和su -有区别sudo为什么默认要ttysudoers里那几行配置到底在说什么以及很多教程没告诉你的“提权后环境变量丢了”这类隐蔽问题。内容偏向Debian/Ubuntu系但原理在CentOS/Rocky上通用。涉及用户管理的操作我尽量给全命令同时标注哪些需要root。2. 用户切换详解su、su -、login到底差在哪2.1 用户切换的本质不仅仅是换名字Linux里的“用户”不是一个简单字符串它对应着一整套身份信息UID、GID用户组ID、家目录、Shell、环境变量、umask、当前工作目录等等。当我们说“切换到某个用户”实际是让当前Shell进程的身份标识主要是UID/GID发生变化同时重置一整套运行环境。su命令的完整形态是su [选项] [用户名]不带用户名时默认切换到root。但重点在于选项尤其是那个-或者写成-l/--login。看个对比实验。我在一台Ubuntu机器上用普通用户alice执行# 不带横杠保留当前环境 aliceserver:~$ su root 密码: rootserver:/home/alice# pwd /home/alice rootserver:/home/alice# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin这个Shell虽然UID变成0了但当前目录还在/home/alice$PATH还是普通用户的$HOME也没变。这意味着什么意味着你“名义上是root生活半径还是alice”。再试带横杠的版本aliceserver:~$ su - root 密码: rootserver:~# pwd /root rootserver:~# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin rootserver:~# echo $HOME /rootsu -会模拟一次完整的登录过程切到目标用户家目录、读取目标用户的profile/bashrc、重置环境变量。这才是“真正变成另一个人”。实际工作中如果你只是临时想看一眼root能看的文件不带横杠的su问题不大。但如果要执行一系列管理操作强烈建议用su -否则你可能会在一个 PATH 不完整的环境里遇到“明明root却找不到命令”的诡异现象。2.2 为什么有时候 su 切不过去Debian系的root账户默认是没有密码的。什么意思root这个账户存在但是密码字段是!锁定状态。这时候你su -输入任何密码都过不去除非你事先用sudo passwd root给root设了密码。这也是很多教程提倡“用sudo而不是su”的原因之一——你根本不需要知道root密码只需要自己账户的密码就能执行特权命令。从审计角度也好root密码越少人知道越安全。另一个常见问题是目标用户如果设置了nologin作为Shell比如系统账户rootserver:~# grep alice /etc/passwd alice:x:1001:1001::/home/alice:/usr/sbin/nologin这时候su alice会直接提示This account is currently not available。这不是密码错误而是Shell策略禁止登录。想看系统账户能不能切先grep一下Shell字段或者chsh修改目标用户的Shell。2.3 su 的安全风险密码共享与审计缺失团队协作场景里如果每个人都用su -切到root意味着root密码要在所有人之间传递。有人离职就得改密码改完还要通知所有人这是运维最头疼的事情之一。更麻烦的是一旦出了问题你根本查不到“是哪个人在什么时间执行了哪条root命令”——因为大家共用一套身份。sudo的出现本质上是把“共享root密码”变成了“每个人用自己的密码临时借权”并且sudo的所有执行记录都会写进日志通常是/var/log/auth.logCentOS上是/var/log/secure。这也是企业安全基线的常见要求root密码密封在保险柜里日常操作全部走sudo。3. sudo提权原理、配置与常用玩法3.1 sudo的基本工作流程sudo全称是 “superuser do”但它并不是简单地把你的UID改成0然后执行命令。完整流程大概是你执行sudo cmd系统先检查调用者是否在sudoers里有权限。确认有权限后提示输入你自己的密码不是目标用户的密码。密码验证通过后在一个短时间内默认15分钟记住结果后续sudo不再重复输密码。以目标用户身份默认root执行命令。这里有个关键点sudo是命令级别的提权不是Shell级别的。它只提权你指定的那一条命令。你执行sudo cat /etc/shadow可以但紧接着执行cat /etc/shadow还是会被拒绝——因为第二条命令没有sudo前缀。3.2 看懂 /etc/sudoers语法与安全配置/etc/sudoers是sudo的核心配置文件。不要直接编辑它用visudo命令后者会做语法检查防止你写坏配置把自己锁在门外。一个最简单的授权把用户alice加入sudo组实际上等价于sudoers里有这么一行# 允许sudo组成员执行任何命令 %sudo ALL(ALL:ALL) ALL这行的含义拆开看是四个字段字段含义示例中的值第一列被授权的用户或组组以%开头%sudo第二列在哪些主机上生效ALL第三列可以以哪个用户身份执行(ALL:ALL)第四列可以执行哪些命令ALL所以%sudo ALL(ALL:ALL) ALL的意思是sudo组的成员在任何主机上实际就这一台能以任何用户身份执行任何命令。这是最宽泛的授权。如果你只想给某个用户有限的提权比如只允许他重启服务不给他改密码的权限# 允许deploy用户以root身份执行 systemctl restart/stop/start 和 reboot deploy ALL(root) /usr/bin/systemctl restart *, /usr/bin/systemctl stop *, /usr/bin/systemctl start *, /sbin/reboot这样写的好处是deploy用户没法执行sudo systemctl edit也没法sudo passwd root权限被牢牢圈在指定命令里。但注意命令路径要写绝对路径防止PATH劫持类攻击。为什么如果sudoers里写的是systemctl而不是/usr/bin/systemctl攻击者可以在deploy的PATH前置目录里放一个同名的恶意脚本sudo就可能执行到它。路径写全直接封死这个口子。还有一类特殊配置是无密码执行。比如CI/CD流水线里自动化用户经常需要免密重启服务# 允许jenkins用户免密执行systemctl命令 jenkins ALL(root) NOPASSWD: /usr/bin/systemctl restart *, /usr/bin/systemctl stop *, /usr/bin/systemctl start *NOPASSWD必须放在命令列表前面它只对紧跟其后的命令生效。如果后续还有其他需要密码的命令要单独再写一行。3.3 常见sudo配置场景整理场景配置写法sudoers片段说明把用户加入管理员组useradd -G sudo alice或写到/etc/sudoers.d/最常用一行命令搞定仅允许执行单个命令ops ALL(root) /usr/bin/tail /var/log/nginx/*.log查日志专用免密执行一组命令ci ALL(root) NOPASSWD: /usr/bin/systemctl restart *适合自动化禁止执行某些命令alice ALL(ALL) ALL, !/usr/bin/passwd root排除法授权为某个命令设置别名Cmnd_Alias SERVICES /usr/bin/systemctl *然后alice ALL(root) SERVICES便于多处引用需要特别提醒sudoers里“后出现的规则会覆盖前面的规则”而且越具体的规则优先级越高。所以上面那种“先ALL再排除”的写法在某些sudo版本里排除可能不生效。如果你要封禁某个命令更稳妥的做法是单独建文件放到/etc/sudoers.d/并靠文件后缀排序来控制优先级或者干脆不给那条命令的权限而不是给了再排除。还有个小坑sudo的“本机hostname”匹配是精确字符串匹配。如果你在sudoers第二列写了主机名但系统hostname解析有问题sudo可能直接拒绝。省心的写法就是写ALL。3.4 sudo -i、sudo -s、sudo su的区别网上的说法五花八门我按实际效果给你理清命令实际效果主要使用场景sudo cmd以root身份执行单条命令不切换Shell日常执行特权命令sudo -i以root身份模拟登录Shell家目录在/root加载完整root环境想进入root交互环境时首选sudo -s以root身份启动Shell但不加载root环境变量保留当前目录和环境需要root权限但不想环境被重置时sudo su等价于“先sudo到root再su”实际效果接近sudo -i但不完全一致老式写法部分脚本里常见sudo su -以root身份完整登录Shell和sudo -i基本相同个人建议日常直接sudo -i别再用sudo su这种叠罗汉写法了。它虽然能用但会产生一层多余的子Shell日志记录里看起来也更混乱。3.5 为什么默认要密码却又要配置tty有阵子网上很多人问“sudo需要tty”是什么意思。这其实是sudoers里Defaults requiretty这条配置在起作用。它要求sudo必须在有终端的环境里执行禁止在纯后台比如cron、远程命令里直接sudo。为什么要这么干因为sudo本身要交互式输入密码如果没有tty密码就没法正常交互而且攻击者也可以用脚本在后台静默执行sudo。开了requiretty等于强制让sudo操作“暴露在明面上”降低自动化攻击的成功率。但副作用也很明显你写个定时任务想sudo重启服务会因为“sudo: sorry, you must have a tty to run sudo”而失败。排查方法是先确认是不是requiretty在作祟sudo grep requiretty /etc/sudoers如果确实开了要么给特定用户加上Defaults:jenkins !requiretty要么在命令里加-t参数强制分配伪终端。这两个做法要权衡放开tty限制意味着自动化脚本可以静默执行sudo需要确保sudoers里的命令范围足够窄。4. 第三方工具与提权相关的那些“月虹”和“提权助手”4.1 为什么市面上会出现“提权助手”类工具热词里出现了“月虹提权助手”这种名字顺便聊一下。这类工具通常出现在Windows/APT渗透测试或CTF语境里目标是在拿到一个低权限Shell后通过各种系统漏洞或配置缺陷把权限提升为管理员/root。Linux方向的“提权工具”大多围绕这几类方向内核漏洞利用脏牛、OverlayFS、CVE-2022-0847等。工具内部尝试加载对应exp。错误配置利用sudoers配置错误、可写的PATH目录、SUID文件、定时任务、可写的/etc/passwd等。凭据获取从内存、日志、shell历史、内存镜像里找密码或密钥。但从运维/防护视角看关注点完全不同提权工具本身不可怕可怕的是你系统里有它可利用的条件。比如sudo授权过宽、某个二进制文件设置了SUID位、PATH里存在可写的目录这些才是真实风险。我看到热词里“月虹提权助手”这种工具大概率是商业化或半商业化的提权辅助工具常用于红队评估或防火墙规则验证。但这里必须讲清楚任何提权类工具在没有授权的情况下使用都是违规甚至违法的。运维人员了解这类工具重点是为了防守——知道攻击者拿到低权限后会做什么才能针对性加固。4.2 从“提权助手”反推安全加固措施既然聊到提权我干脆把Linux安全加固里跟权限强相关的几板斧列出来。这几条每一条都是实战里被“提权助手”反复利用的入口加固项具体做法防的是什么sudoers最小化命令用绝对路径避免ALL授权防止sudo权限滥用禁用root密码登录/etc/ssh/sshd_config里PermitRootLogin no防止暴力破解root严格SUID排查find / -perm -4000 -type f 2/dev/null定期审计防止SUID提权内核补丁及时打关注发行版安全通告用apt upgrade或dnf update防止内核漏洞利用PATH目录权限检查确保/usr/local/bin等目录组用户不可写防止PATH劫持定时任务权限收紧cron目录和任务文件属主为root且不可写防止定时任务投毒日志监控持续监控/var/log/auth.log里的sudo记录及时发现异常提权行为很多“提权助手”跑起来依赖的恰恰是这些没做好的项。你把这些项处理干净工具自然没得玩了。运维圈有句话“加固不是跑一次扫描就完事而是把攻击路径一条条封死。”5. 实操实录创建用户、加入sudo组、验证提权、输出审计5.1 完整案例从零创建一个可sudo的运维用户假设机器是Debian 12我们要创建一个叫ops的用户给它sudo权限并验证权限边界。全程用root执行# 1. 创建用户并指定家目录和Shell useradd -m -d /home/ops -s /bin/bash ops # 2. 设置密码 passwd ops # 3. 把用户加入sudo组 usermod -aG sudo ops # 4. 验证 su - ops sudo whoami # 输出: root到这里一个标准的可sudo用户就建好了。但如果我不希望这个用户能随便sudo -i后为所欲为我可以在/etc/sudoers.d/ops-limited里单独配置visudo -f /etc/sudoers.d/ops-limited写入# ops用户只能执行系统管理和日志相关命令 ops ALL(root) /usr/bin/systemctl status *, /usr/bin/tail /var/log/syslog, /usr/bin/cat /var/log/auth.log这里用了visudo -f直接编辑子文件好处是不动主配置避免写坏影响全局。文件写完记得检查语法visudo -c如果输出parsed OK说明配置没问题。然后你就可以用su - ops切过去测试了。我实测过这种场景ops用户执行sudo systemctl restart ssh立刻提示不在允许命令列表中执行sudo cat /var/log/auth.log正常输出日志。这就叫权限边界清晰。5.2 踩坑实录sudo命令路径被拒有一个特别常见的坑在sudoers里写了允许执行systemctl结果执行时报sudo: systemctl: command not found。原因基本是sudoers里没写绝对路径而sudo执行时会用固定的PATH去找命令如果这个PATH里没有systemctl就会失败。解决方法是改成绝对路径。另一个更隐蔽的坑sudoers里写的命令路径和你系统里实际命令路径不一致。比如有的系统systemctl在/usr/bin/systemctl有的在/bin/systemctl还有的发行版把它放在/usr/bin但做了符号链接。最稳妥的排查方式是先确定真实路径which systemctl然后把输出结果原样写进sudoers。别凭记忆写路径我就是因为想当然写了/sbin/systemctl结果在实际验证时才发现在我这个系统里它在/usr/bin下白折腾半天。5.3 sudo日志怎么排查一条命令定位谁在搞事团队环境里有人跑了sudo rm -rf第二天数据库没了第一时间要查日志。Debian系的sudo日志在/var/log/auth.log用grep sudo过滤sudo grep sudo /var/log/auth.log | tail -n 50会看到类似Nov 12 14:30:22 server sudo: ops : TTYpts/0 ; PWD/home/ops ; USERroot ; COMMAND/usr/bin/cat /var/log/auth.log这行信息量很大执行者、终端、工作目录、提权目标用户、执行的完整命令都有。如果机器上没有/var/log/auth.log比如某些精简镜像可以检查/etc/sudoers里是否配置了Defaults logfile或者在syslog里搜。CentOS/Rocky上则是/var/log/secure命令一样sudo grep sudo /var/log/secure | tail -n 506. sudo提权的隐藏坑环境变量、PATH与ssh告别6.1 为什么 sudo 后环境变量丢了很多人在脚本里执行sudo echo $JAVA_HOME结果输出为空百思不得其解。原因是sudo默认会重置环境变量——它只保留少数白名单变量如HOME、LOGNAME、PATH的默认值其余全清掉。这就是安全设计防止普通用户通过环境变量注入恶意代码到root环境里。如果你确实需要保留部分环境变量在sudoers里加Defaults env_keep JAVA_HOME或者在命令行用sudo VARvalue command但要注意这等于把环境变量注入root进程前提是你信任这个变量的来源。不推荐在管理环境里大规模放开env_keep除非你清楚那个变量是安全的。6.2 sudo 提权后 ssh-agent 失效日常开发场景里另一个经常遇到的问题本地有ssh密钥用ssh-agent管理。在普通用户下ssh连服务器一切正常但sudo ssh或sudo git pull会提示找不到身份。原因还是环境变量重置——SSH_AUTH_SOCK 这个环境变量在sudo环境里被清掉了ssh自然连接不上ssh-agent。解决方式是逐步缓解的要么不用sudo执行git要么在sudoers里保留SSH_AUTH_SOCKDefaults env_keep SSH_AUTH_SOCK但我更推荐前者——非必要不sudo。你想git pull这种操作本身就不需要特权错误使用sudo只会带来更多的安全隐患。7. 面试与实战场景Linux权限问题的标准应对路径高频面试题“Linux如何把普通用户加入sudo权限组”标准答案其实是两种路径命令行操作usermod -aG sudo alice然后alice重新登录生效。sudoers文件操作visudo添加alice ALL(ALL:ALL) ALL或放在/etc/sudoers.d/alice。注意-aG里的-a是append的意思不加-a的话会把用户从其他附属组里剔掉造成权限意外缩小或扩大。这个细节经常被忽略但出问题就是大问题。再一个面试高频考点sudo和su的区别。简洁版回答su需要知道目标用户密码提供目标用户的Shell环境。sudo需要的是自己的密码按sudoers规则按命令提权有日志审计。推荐组合是禁止root密码登录 普通用户sudo 审计日志。8. 个人实操心得如何优雅管理一台多用户机器的权限最后分享几个我在真实环境里沉淀下来的习惯谈不上方法论但能让你少踩很多坑。第一永远有一个非root的应急账号。有的管理员当天脑子一热把root密码改了结果第二天忘了密码服务器直接失联。我有一次就是这样最后只能通过带外管理重置折腾两小时。备份一个非root的sudo账号这类事故永远不会发生。第二/etc/sudoers.d/ 里的每个文件都做到“一条命令一个文件”。文件命名带上用户/业务名比如jenkins-service内容只写该账号真正需要的命令。这样团队交接时看一眼文件名就能知道整个权限设计脉络。第三sudo命令本身也值得配置别名。常用sudo -i可以设置成alias rootsudo -i减少敲击次数也避免在交互Shell里频繁误输密码。第四定期做权限审计。我通常是每月一次命令就三行# 列出所有可登录用户 grep -E sh$ /etc/passwd # 检查有多少sudo用户 grep -E sudo|wheel /etc/group # 检查异常SUID文件 find / -perm -4000 -type f 2/dev/null每次只要输出里出现意外的名字就立刻查。Linux用户切换和sudo提权说白了是一套权限管理的艺术——不是单纯“会用命令”而是能在正确的时间、给正确的人、刚刚好的权限。这东西越早想明白后面出的事故越少。 ## 1. 从“切用户”到“提权”Linux权限体系的底层逻辑先聊个真实场景。你刚装好一台Linux服务器用root登录折腾完一轮然后习惯性敲了个useradd建了个普通账号。接下来问题就来了普通用户想装个软件、改个系统配置动不动就Permission denied。这时候你就得在“切用户”和“sudo提权”之间来回倒腾。很多新手把这两个操作混为一谈实际上它们解决的是两个完全不同的需求用户切换su/login换一个身份重新登录本质是“变成另一个人”。sudo提权sudo以当前用户身份执行某条命令但临时借用root或其他用户的权限本质是“借用一下别人的工牌”。前者是“换人”后者是“借权”。这两个概念背后是Linux安全模型里最核心的东西——用户、组、权限位。理解不透这两招你后面看什么/etc/passwd、/etc/sudoers、sudo -i、su -都会是一团浆糊。这篇文章不打算抄man手册我就按实际运维和日常使用的场景把用户切换与sudo提权的原理、配置、坑、面试题一次聊透。你会看到为什么su和su -有区别sudo为什么默认要ttysudoers里那几行配置到底在说什么以及很多教程没告诉你的“提权后环境变量丢了”这类隐蔽问题。内容偏向Debian/Ubuntu系但原理在CentOS/Rocky上通用。涉及用户管理的操作我尽量给全命令同时标注哪些需要root。2. 用户切换详解su、su -、login到底差在哪2.1 用户切换的本质不仅仅是换名字Linux里的“用户”不是一个简单字符串它对应着一整套身份信息UID、GID用户组ID、家目录、Shell、环境变量、umask、当前工作目录等等。当我们说“切换到某个用户”实际是让当前Shell进程的身份标识主要是UID/GID发生变化同时重置一整套运行环境。su命令的完整形态是su [选项] [用户名]不带用户名时默认切换到root。但重点在于选项尤其是那个-或者写成-l/--login。看个对比实验。我在一台Ubuntu机器上用普通用户alice执行# 不带横杠保留当前环境 aliceserver:~$ su root 密码: rootserver:/home/alice# pwd /home/alice rootserver:/home/alice# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin这个Shell虽然UID变成0了但当前目录还在/home/alice$PATH还是普通用户的$HOME也没变。这意味着什么意味着你“名义上是root生活半径还是alice”。再试带横杠的版本aliceserver:~$ su - root 密码: rootserver:~# pwd /root rootserver:~# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin rootserver:~# echo $HOME /rootsu -会模拟一次完整的登录过程切到目标用户家目录、读取目标用户的profile/bashrc、重置环境变量。这才是“真正变成另一个人”。实际工作中如果你只是临时想看一眼root能看的文件不带横杠的su问题不大。但如果要执行一系列管理操作强烈建议用su -否则你可能会在一个 PATH 不完整的环境里遇到“明明root却找不到命令”的诡异现象。2.2 为什么有时候 su 切不过去Debian系的root账户默认是没有密码的。什么意思root这个账户存在但是密码字段是!锁定状态。这时候你su -输入任何密码都过不去除非你事先用sudo passwd root给root设了密码。这也是很多教程提倡“用sudo而不是su”的原因之一——你根本不需要知道root密码只需要自己账户的密码就能执行特权命令。从审计角度也好root密码越少人知道越安全。另一个常见问题是目标用户如果设置了nologin作为Shell比如系统账户rootserver:~# grep alice /etc/passwd alice:x:1001:1001::/home/alice:/usr/sbin/nologin这时候su alice会直接提示This account is currently not available。这不是密码错误而是Shell策略禁止登录。想看系统账户能不能切先grep一下Shell字段或者chsh修改目标用户的Shell。2.3 su 的安全风险密码共享与审计缺失团队协作场景里如果每个人都用su -切到root意味着root密码要在所有人之间传递。有人离职就得改密码改完还要通知所有人这是运维最头疼的事情之一。更麻烦的是一旦出了问题你根本查不到“是哪个人在什么时间执行了哪条root命令”——因为大家共用一套身份。sudo的出现本质上是把“共享root密码”变成了“每个人用自己的密码临时借权”并且sudo的所有执行记录都会写进日志通常是/var/log/auth.logCentOS上是/var/log/secure。这也是企业安全基线的常见要求root密码密封在保险柜里日常操作全部走sudo。3. sudo提权原理、配置与常用玩法3.1 sudo的基本工作流程sudo全称是 “superuser do”但它并不是简单地把你的UID改成0然后执行命令。完整流程大概是你执行sudo cmd系统先检查调用者是否在sudoers里有权限。确认有权限后提示输入你自己的密码不是目标用户的密码。密码验证通过后在一个短时间内默认15分钟记住结果后续sudo不再重复输密码。以目标用户身份默认root执行命令。这里有个关键点sudo是命令级别的提权不是Shell级别的。它只提权你指定的那一条命令。你执行sudo cat /etc/shadow可以但紧接着执行cat /etc/shadow还是会被拒绝——因为第二条命令没有sudo前缀。3.2 看懂 /etc/sudoers语法与安全配置/etc/sudoers是sudo的核心配置文件。不要直接编辑它用visudo命令后者会做语法检查防止你写坏配置把自己锁在门外。一个最简单的授权把用户alice加入sudo组实际上等价于sudoers里有这么一行# 允许sudo组成员执行任何命令 %sudo ALL(ALL:ALL) ALL这行的含义拆开看是四个字段字段含义示例中的值第一列被授权的用户或组组以%开头%sudo第二列在哪些主机上生效ALL第三列可以以哪个用户身份执行(ALL:ALL)第四列可以执行哪些命令ALL所以%sudo ALL(ALL:ALL) ALL的意思是sudo组的成员在任何主机上实际就这一台能以任何用户身份执行任何命令。这是最宽泛的授权。如果你只想给某个用户有限的提权比如只允许他重启服务不给他改密码的权限# 允许deploy用户以root身份执行 systemctl restart/stop/start 和 reboot deploy ALL(root) /usr/bin/systemctl restart *, /usr/bin/systemctl stop *, /usr/bin/systemctl start *, /sbin/reboot这样写的好处是deploy用户没法执行sudo systemctl edit也没法sudo passwd root权限被牢牢圈在指定命令里。但注意命令路径要写绝对路径防止PATH劫持类攻击。为什么如果sudoers里写的是systemctl而不是/usr/bin/systemctl攻击者可以在deploy的PATH前置目录里放一个同名的恶意脚本sudo就可能执行到它。路径写全直接封死这个口子。还有一类特殊配置是无密码执行。比如CI/CD流水线里自动化用户经常需要免密重启服务# 允许jenkins用户免密执行systemctl命令 jenkins ALL(root) NOPASSWD: /usr/bin/systemctl restart *, /usr/bin/systemctl stop *, /usr/bin/systemctl start *NOPASSWD必须放在命令列表前面它只对紧跟其后的命令生效。如果后续还有其他需要密码的命令要单独再写一行。3.3 常见sudo配置场景整理场景配置写法sudoers片段说明把用户加入管理员组useradd -G sudo alice或写到/etc/sudoers.d/最常用一行命令搞定仅允许执行单个命令ops ALL(root) /usr/bin/tail /var/log/nginx/*.log查日志专用免密执行一组命令ci ALL(root) NOPASSWD: /usr/bin/systemctl restart *适合自动化禁止执行某些命令alice ALL(ALL) ALL, !/usr/bin/passwd root排除法授权为某个命令设置别名Cmnd_Alias SERVICES /usr/bin/systemctl *然后alice ALL(root) SERVICES便于多处引用需要特别提醒sudoers里“后出现的规则会覆盖前面的规则”而且越具体的规则优先级越高。所以上面那种“先ALL再排除”的写法在某些sudo版本里排除可能不生效。如果你要封禁某个命令更稳妥的做法是单独建文件放到/etc/sudoers.d/并靠文件后缀排序来控制优先级或者干脆不给那条命令的权限而不是给了再排除。还有个小坑sudo的“本机hostname”匹配是精确字符串匹配。如果你在sudoers第二列写了主机名但系统hostname解析有问题sudo可能直接拒绝。省心的写法就是写ALL。3.4 sudo -i、sudo -s、sudo su的区别网上的说法五花八门我按实际效果给你理清命令实际效果主要使用场景sudo cmd以root身份执行单条命令不切换Shell日常执行特权命令sudo -i以root身份模拟登录Shell家目录在/root加载完整root环境想进入root交互环境时首选sudo -s以root身份启动Shell但不加载root环境变量保留当前目录和环境需要root权限但不想环境被重置时sudo su等价于“先sudo到root再su”实际效果接近sudo -i但不完全一致老式写法部分脚本里常见sudo su -以root身份完整登录Shell和sudo -i基本相同个人建议日常直接sudo -i别再用sudo su这种叠罗汉写法了。它虽然能用但会产生一层多余的子Shell日志记录里看起来也更混乱。3.5 为什么默认要密码却又要配置tty有阵子网上很多人问“sudo需要tty”是什么意思。这其实是sudoers里Defaults requiretty这条配置在起作用。它要求sudo必须在有终端的环境里执行禁止在纯后台比如cron、远程命令里直接sudo。为什么要这么干因为sudo本身要交互式输入密码如果没有tty密码就没法正常交互而且攻击者也可以用脚本在后台静默执行sudo。开了requiretty等于强制让sudo操作“暴露在明面上”降低自动化攻击的成功率。但副作用也很明显你写个定时任务想sudo重启服务会因为“sudo: sorry, you must have a tty to run sudo”而失败。排查方法是先确认是不是requiretty在作祟sudo grep requiretty /etc/sudoers如果确实开了要么给特定用户加上Defaults:jenkins !requiretty要么在命令里加-t参数强制分配伪终端。这两个做法要权衡放开tty限制意味着自动化脚本可以静默执行sudo需要确保sudoers里的命令范围足够窄。4. 第三方工具与提权相关的那些“月虹”和“提权助手”4.1 为什么市面上会出现“提权助手”类工具热词里出现了“月虹提权助手”这种名字顺便聊一下。这类工具通常出现在Windows/APT渗透测试或CTF语境里目标是在拿到一个低权限Shell后通过各种系统漏洞或配置缺陷把权限提升为管理员/root。Linux方向的“提权工具”大多围绕这几类方向内核漏洞利用脏牛、OverlayFS、CVE-2022-0847等。工具内部尝试加载对应exp。错误配置利用sudoers配置错误、可写的PATH目录、SUID文件、定时任务、可写的/etc/passwd等。凭据获取从内存、日志、shell历史、内存镜像里找密码或密钥。但从运维/防护视角看关注点完全不同提权工具本身不可怕可怕的是你系统里有它可利用的条件。比如sudo授权过宽、某个二进制文件设置了SUID位、PATH里存在可写的目录这些才是真实风险。我看到热词里“月虹提权助手”这种工具大概率是商业化或半商业化的提权辅助工具常用于红队评估或防火墙规则验证。但这里必须讲清楚任何提权类工具在没有授权的情况下使用都是违规甚至违法的。运维人员了解这类工具重点是为了防守——知道攻击者拿到低权限后会做什么才能针对性加固。4.2 从“提权助手”反推安全加固措施既然聊到提权我干脆把Linux安全加固里跟权限强相关的几板斧列出来。这几条每一条都是实战里被“提权助手”反复利用的入口加固项具体做法防的是什么sudoers最小化命令用绝对路径避免ALL授权防止sudo权限滥用禁用root密码登录/etc/ssh/sshd_config里PermitRootLogin no防止暴力破解root严格SUID排查find / -perm -4000 -type f 2/dev/null定期审计防止SUID提权内核补丁及时打关注发行版安全通告用apt upgrade或dnf update防止内核漏洞利用PATH目录权限检查确保/usr/local/bin等目录组用户不可写防止PATH劫持定时任务权限收紧cron目录和任务文件属主为root且不可写防止定时任务投毒日志监控持续监控/var/log/auth.log里的sudo记录及时发现异常提权行为很多“提权助手”跑起来依赖的恰恰是这些没做好的项。你把这些项处理干净工具自然没得玩了。运维圈有句话“加固不是跑一次扫描就完事而是把攻击路径一条条封死。”5. 实操实录创建用户、加入sudo组、验证提权、输出审计5.1 完整案例从零创建一个可sudo的运维用户假设机器是Debian 12我们要创建一个叫ops的用户给它sudo权限并验证权限边界。全程用root执行# 1. 创建用户并指定家目录和Shell useradd -m -d /home/ops -s /bin/bash ops # 2. 设置密码 passwd ops # 3. 把用户加入sudo组 usermod -aG sudo ops # 4. 验证 su - ops sudo whoami # 输出: root到这里一个标准的可sudo用户就建好了。但如果我不希望这个用户能随便sudo -i后为所欲为我可以在/etc/sudoers.d/ops-limited里单独配置visudo -f /etc/sudoers.d/ops-limited写入# ops用户只能执行系统管理和日志相关命令 ops ALL(root) /usr/bin/systemctl status *, /usr/bin/tail /var/log/syslog, /usr/bin/cat /var/log/auth.log这里用了visudo -f直接编辑子文件好处是不动主配置避免写坏影响全局。文件写完记得检查语法visudo -c如果输出parsed OK说明配置没问题。然后你就可以用su - ops切过去测试了。我实测过这种场景ops用户执行sudo systemctl restart ssh立刻提示不在允许命令列表中执行sudo cat /var/log/auth.log正常输出日志。这就叫权限边界清晰。5.2 踩坑实录sudo命令路径被拒有一个特别常见的坑在sudoers里写了允许执行systemctl结果执行时报sudo: systemctl: command not found。原因基本是sudoers里没写绝对路径而sudo执行时会用固定的PATH去找命令如果这个PATH里没有systemctl就会失败。解决方法是改成绝对路径。另一个更隐蔽的坑sudoers里写的命令路径和你系统里实际命令路径不一致。比如有的系统systemctl在/usr/bin/systemctl有的在/bin/systemctl还有的发行版把它放在/usr/bin但做了符号链接。最稳妥的排查方式是先确定真实路径which systemctl然后把输出结果原样写进sudoers。别凭记忆写路径我就是因为想当然写了/sbin/systemctl结果在实际验证时才发现在我这个系统里它在/usr/bin下白折腾半天。5.3 sudo日志怎么排查一条命令定位谁在搞事团队环境里有人跑了sudo rm -rf第二天数据库没了第一时间要查日志。Debian系的sudo日志在/var/log/auth.log用grep sudo过滤sudo grep sudo /var/log/auth.log | tail -n 50会看到类似Nov 12 14:30:22 server sudo: ops : TTYpts/0 ; PWD/home/ops ; USERroot ; COMMAND/usr/bin/cat /var/log/auth.log这行信息量很大执行者、终端、工作目录、提权目标用户、执行的完整命令都有。如果机器上没有/var/log/auth.log比如某些精简镜像可以检查/etc/sudoers里是否配置了Defaults logfile或者在syslog里搜。CentOS/Rocky上则是/var/log/secure命令一样sudo grep sudo /var/log/secure | tail -n 506. sudo提权的隐藏坑环境变量、PATH与ssh告别6.1 为什么 sudo 后环境变量丢了很多人在脚本里执行sudo echo $JAVA_HOME结果输出为空百思不得其解。原因是sudo默认会重置环境变量——它只保留少数白名单变量如HOME、LOGNAME、PATH的默认值其余全清掉。这就是安全设计防止普通用户通过环境变量注入恶意代码到root环境里。如果你确实需要保留部分环境变量在sudoers里加Defaults env_keep JAVA_HOME或者在命令行用sudo VARvalue command但要注意这等于把环境变量注入root进程前提是你信任这个变量的来源。不推荐在管理环境里大规模放开env_keep除非你清楚那个变量是安全的。6.2 sudo 提权后 ssh-agent 失效日常开发场景里另一个经常遇到的问题本地有ssh密钥用ssh-agent管理。在普通用户下ssh连服务器一切正常但sudo ssh或sudo git pull会提示找不到身份。原因还是环境变量重置——SSH_AUTH_SOCK 这个环境变量在sudo环境里被清掉了ssh自然连接不上ssh-agent。解决方式是逐步缓解的要么不用sudo执行git要么在sudoers里保留SSH_AUTH_SOCKDefaults env_keep SSH_AUTH_SOCK但我更推荐前者——非必要不sudo。你想git pull这种操作本身就不需要特权错误使用sudo只会带来更多的安全隐患。7. 面试与实战场景Linux权限问题的标准应对路径高频面试题“Linux如何把普通用户加入sudo权限组”标准答案其实是两种路径命令行操作usermod -aG sudo alice然后alice重新登录生效。sudoers文件操作visudo添加alice ALL(ALL:ALL) ALL或放在/etc/sudoers.d/alice。注意-aG里的-a是append的意思不加-a的话会把用户从其他附属组里剔掉造成权限意外缩小或扩大。这个细节经常被忽略但出问题就是大问题。再一个面试高频考点sudo和su的区别。简洁版回答su需要知道目标用户密码提供目标用户的Shell环境。sudo需要的是自己的密码按sudoers规则按命令提权有日志审计。推荐组合是禁止root密码登录 普通用户sudo 审计日志。8. 个人实操心得如何优雅管理一台多用户机器的权限最后分享几个我在真实环境里沉淀下来的习惯谈不上方法论但能让你少踩很多坑。第一永远有一个非root的应急账号。有的管理员当天脑子一热把root密码改了结果第二天忘了密码服务器直接失联。我有一次就是这样最后只能通过带外管理重置折腾两小时。备份一个非root的sudo账号这类事故永远不会发生。第二/etc/sudoers.d/ 里的每个文件都做到“一条命令一个文件”。文件命名带上用户/业务名比如jenkins-service内容只写该账号真正需要的命令。这样团队交接时看一眼文件名就能知道整个权限设计脉络。第三sudo命令本身也值得配置别名。常用sudo -i可以设置成alias rootsudo -i减少敲击次数也避免在交互Shell里频繁误输密码。第四定期做权限审计。我通常是每月一次命令就三行# 列出所有可登录用户 grep -E sh$ /etc/passwd # 检查有多少sudo用户 grep -E sudo|wheel /etc/group # 检查异常SUID文件 find / -perm -4000 -type f 2/dev/null每次只要输出里出现意外的名字就立刻查。Linux用户切换和sudo提权说白了是一套权限管理的艺术——不是单纯“会用命令”而是能在正确的时间、给正确的人、刚刚好的权限。这东西越早想明白后面出的事故越少。