资讯详情

资讯详情

sudo提权原理与实战:从权限配置到渗透测试的完整指南

先别急着打flag把sudo读透再提权CTF里最容易让人上头的瞬间就是把sudo -l的黑框输出拉到屏幕上那一刻。权限提升尤其是基于sudo命令的提权几乎是每台Linux靶机绕不开的关卡。我见过太多新手在拿到一个www-data的shell后盯着sudo -l的输出发愣不知道该挑哪条命令下手最后只能拖着一条不能读flag的权限反复撞墙。这篇文章把sudo提权从原理到实战拆开讲怎么看配置、怎么选路径、怎么避免自己踩坑同时也会站在出题人的角度解释这类题为什么存在。适合正在刷CTF的入门玩家也适合刚接触内网渗透评估的同学参考内容全部基于授权靶机和模拟环境中的常见设计。sudo本身不是什么神奇东西它只是一扇门。门开多大、给谁开、开多久都写在/etc/sudoers里。CTF的出题人通常不会把门锁死而是故意留一条缝让玩家去发现“这条命令虽然不能随便跑但可以借助它拿到一个root shell”。问题在于这个“缝”有很多种形态有的藏在命令参数里有的藏在外挂动态库里有的甚至藏在文件名的通配符里。下面这几节我会把最常见的几种形态逐个说透每一步都配上能直接拿来复现的操作。1. 为什么sudo提权在CTF里总是避不开1.1 sudo的职责边界先把这个工具放回原位理解。sudo是Linux下授权普通用户执行特权命令的机制它的核心逻辑就是系统管理员在/etc/sudoers里定义“谁能用什么身份执行什么命令”普通用户敲下sudo后系统会按照既定规则去匹配这条请求匹配成功就放行失败就拒绝。规则颗粒度可以很细。比如可以只允许某个用户执行/usr/bin/systemctl restart xxx不允许执行/usr/bin/systemctl stop xxx可以要求输入当前用户密码也可以设置NOPASSWD全部免密甚至可以把某个命令的某些参数固定死比如只允许以root身份执行特定的备份脚本。这些规则的设计原本都是为了隔离权限、降低风险但在CTF题目里这些细颗粒度配置恰好成了提权的表演舞台。从本质上看sudo提权题考的是两件事第一你能不能读对sudoers规则的语法和含义第二你能不能找到规则所允许的命令与“无法无天的shell”之间的桥梁。只要桥搭对了root就是你的了。1.2 提权链路中的sudo定位在常见的CTF提权链路里一级权限通常是从Web漏洞拿到的常见的是www-data这样的低权限账户。这个账户没有sudo规则配置它想读/root/flag、想读写系统敏感文件处处受挫。此时就需要找到一条路径切换到另一个具备权限的账户或者直接提到root。sudo在这条链路里的位置非常微妙。很多低权限账户的配置其实不直接可见/etc/sudoers里允许哪个用户执行哪些命令往往才是真正的突破口。一旦你发现当前用户被允许以root身份执行某个程序就相当于拿到了一个“最小特权”的窗口。接下来要做的事就是利用这个程序自身的功能把它从一个黑盒工具变成一个能够执行shell命令的通道。这也是我坚持在拿到shell之后第一件事就跑sudo -l的原因它往往能直接展示出题人预设的所有“善意”也就是你最需要的信息。2. 开局第一件事把sudo -l读透2.1 权限列表的解读套路许多初学朋友输完sudo -l看到一大堆英文输出就慌了。其实输出的结构很固定记牢几个关键词就行。核心是当前用户被允许以哪些身份、免不免密、执行哪些命令。$ sudo -l Matching Defaults entries for www-data on ctf-box: env_reset, mail_badpass, secure_path/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin User www-data may run the following commands on ctf-box: (root) NOPASSWD: /usr/bin/vim (ALL) NOPASSWD: /usr/bin/python3解读第一步先看Matching Defaults entries。这块定义的是环境相关的默认行为比如env_reset表示sudo会重置环境变量secure_path表示sudo会使用指定的PATH来执行命令而不是继承你当前的环境变量。这两行对后面判断能否利用LD_PRELOAD非常关键。第二步看命令列表。(root) NOPASSWD: /usr/bin/vim表示当前用户能免密以root身份执行vim/usr/bin/python3类似但身份是所有主机上的所有用户。读懂这一条就清楚自己可用的资源边界了。2.2 需要留神的五种配置模式见过足够多的题目之后你会发现出题人常用的配置模式就那么几种。照着这个思路去检查sudo -l的输出效率会高很多。配置了编辑器类程序vim、nano、less、more、man这类程序自带交互式命令行或者翻页功能很多可以直接通过内部命令逃逸到shell。配置了脚本解释器python3、perl、ruby、node这些解释器天然就有获取shell的能力只要给一句代码就能生成一个交互式shell。配置了文件管理类工具find、tar、cp、rsync这类工具本身不支持直接执行命令但它们支持参数、支持外部调用存在被利用的可能。配置了二进制文件某些系统自带小工具可能有特殊参数能够调用系统命令需要逐个尝试。配置了自定义脚本出题人写了一个/usr/local/bin/backup.sh之类的脚本虽然脚本本身看起来无害但里面可能调用了内部命令可以被符号链接或环境变量劫持。上面这五类模式不是穷举但覆盖了市面上大部分基于sudo的CTF提权题。看到输出先对照着分个类再决定走哪条路会比直接猜测高效得多。3. 五个最常考的sudo提权路径3.1 编辑器类的交互式逃逸最常见的例子sudo -l给出(root) NOPASSWD: /usr/bin/vim。先把命令跑起来进入vim编辑器后接着在普通模式下输入:进入命令行模式再输入!bash即可弹出root shell。$ sudo vim # 在vim里输入::!bash原理很简单vim的:!指令允许执行外部命令而这个外部命令在执行时继承了vim进程的权限也就是root。提示符变成#之后可以直接读取flag也可以进一步执行任意命令。less和more相关的情况也类似。这两个分页器都内置了在浏览文件内容时执行命令的机制。进入界面后按!再输入想执行的命令即可。比如$ sudo less /etc/passwd # 在less界面按! !id uid0(root) gid0(root) ...有一个容易忽略的点是less首次启动时会尝试打开文件如果文件不存在会提示这不影响后续的提权操作。另外man命令本身也带有!转义功能sudo man man进去后按!照样能执行命令。3.2 让解释器帮忙起shellsudo -l里出现解释器时直接利用它们的功能即可。Python和Perl都有专门生成shell的模块$ sudo python3 -c import pty; pty.spawn(/bin/bash)$ sudo perl -e exec /bin/bash;Ruby则可以用$ sudo ruby -e exec /bin/bash对很多人来说记住这三条命令就够了。但如果题目环境里只有某个不常见的解释器比如Lua也别急着放弃。Lua同样可以执行系统命令$ sudo lua -e os.execute(/bin/bash)用解释器提权有两个注意点。第一有些解释器启动后不会直接变成交互式shell比如python的pty.spawn()只会在当前终端内产生一个bash进程这个bash还是挂在sudo进程下的退出时会回到原始shell这并不影响命令执行。第二如果sudo配置了env_reset环境变量被重置了但解释器本身的功能不受影响。所以这个路径的成功率非常高。3.3 环境变量注入实现提权这是相对隐蔽的一类。常见前提是sudo -l里出现env_keepLD_PRELOAD或者Defaults配置中没有启用env_reset。LD_PRELOAD的作用是一个程序启动时动态链接器会优先加载这个指定的共享库文件哪怕程序本身没有显式要求加载它。思路是写一个包含自定义函数的共享库把函数名写成程序运行时会调用的函数然后通过LD_PRELOAD让目标程序加载这个库最终在库的构造函数里执行我们想要的命令。先写一个C文件#include stdio.h #include sys/types.h #include stdlib.h void _init() { remove(/tmp/pwned); setuid(0); unsetenv(LD_PRELOAD); system(/bin/bash); }然后编译$ gcc -shared -fPIC -o /tmp/pwn.so /tmp/pwn.c运行目标程序时带上LD_PRELOAD$ sudo LD_PRELOAD/tmp/pwn.so /usr/bin/find /tmp利用的关键在于sudo执行find时会以root身份启动动态链接器先加载pwn.so在_init构造器里直接起了bash于是我们就得到了一个root shell。判断能否走这条路需要额外确认两件事一是sudo配置是否启用了env_keepLD_PRELOAD二是目标环境是否对C编译做了限制。CTF靶机一般不会阉割gcc所以这条路在训练环境里非常稳定。如果是真机评估要额外注意目标是否需要编译工具链。除了LD_PRELOADPYTHONPATH也是一个切入点。如果sudo允许在当前环境变量下运行python而python脚本导入了某个自定义模块我们可以通过覆盖PYTHONPATH来劫持模块。不过CTF里相对少见属于进阶路径遇到再深入去看也不迟。3.4 通配符与文件匹配陷阱这一条考的是Linux shell的通配符展开机制。假设sudo -l里允许root执行/usr/bin/tar而常见的备份脚本可能是这种形态$ sudo tar -czf /tmp/backup.tgz *关键点在于通配符*由当前shell展开展开后的文件名会传给tar。如果当前目录下有一个文件名为--checkpoint1另一个文件名为--checkpoint-actionexec/bin/shtar就会把它们当成参数来解读而不是普通文件名。构造文件$ touch -- --checkpoint1 $ touch -- --checkpoint-actionexec/bin/bash $ sudo tar -czf /tmp/backup.tgz *生成的bash是root权限。tar会按参数解析自己的行为遇到--checkpoint参数后在执行到检查点时调用exec指定的命令。这个手法在旧版tar上非常稳定新版tar对这个参数的控制更严格但CTF题目里通常刻意保留旧版环境所以值得掌握。同理rsync也有类似的利用方式。rsync的--e参数可以指定远端的shell如果匹配到特殊的文件名也能触发命令执行。这类题的价值在于提醒玩家不要把过长的注意力放在命令本身要看到文件名的OS层面展开机制。匹配规则是由shell做的命令本身只是被动的接收者。3.5 从文件读取到明文密码的被动提权之前的几条路径都是主动冲击shell还有一类是被驱动的。某些sudo配置允许你以root身份读取某个文件该文件里可能直接存放了root的密码哈希或者是某个高权限用户的SSH私钥。举个例子sudo -l输出(root) NOPASSWD: /bin/cat /etc/shadow这条规则虽然看起来限制了cat只允许读取/etc/shadow但/etc/shadow里本身就有所有用户的密码哈希。把root的哈希拿出来用在线工具或者本地john跑字典如果root的密码恰好是弱口令那就白拿了一台root权限。这看起来不像是“提权”但却是最省事的方式。很多CTF题目把flag藏在root家目录下而读取权限就藏在sudo的cat规则里先读一波敏感文件再去决定是否硬提成功率更高。另一个常见组合是sudo -l允许/usr/bin/teetee可以把内容附加到任意文件。此时可以往/etc/passwd里塞一个自定义的root权限用户或者往/root/.ssh/authorized_keys里塞一把自己的公钥然后平滑登入root。这类方式需要的操作更多但在无shell的题目里反而是关键解法。4. 出题人视角这个洞是怎么被设计出来的4.1 一个常规模拟题的设计流程很多玩家困惑“为什么会允许一个用户用vim这配置也太蠢了”。但如果你站到出题人的角度看这个“蠢”本身就是核心考点。一个常规的sudo提权题设计流程大致是先确定玩家已经处于什么权限默认www-data然后确定目标是读取root的flag最后在两者之间搭建一条可发现、可利用的路径。路径的选择遵循一个原则命令是常见的配置是错误的利用是不需要复杂工具的。出题人会在/etc/sudoers里写一行www-data ALL(ALL:ALL) NOPASSWD: /usr/bin/vim这行配置放到真实服务器上确实危险但在CTF里就成了一场“发现并利用”的智力游戏。为了让玩家有迹可循出题人一般会在sudo -l的输出里保留明显的痕迹比如权限项里没有使用通配符去固定参数或者完全忽略env_reset对环境变量的影响。只要你能读懂输出就等于竞赛开始。另一种设计思路是把命令伪装得很严格。例如www-data ALL(ALL) NOPASSWD: /usr/bin/systemctl restart nginx看起来只允许重启nginx服务但systemctl本身支持调用外部脚本或者可以通过trace、inspect等方式接触到内部执行逻辑一样能扩展成shell。出题人把“看似安全”的命令作为陷阱考的是选手是否会去查手册、查在线提权清单。4.2 防御侧与加固思路从防守方角度看这些题反过来就是一份加固检查表。给sudoers配置时先问自己几个问题这条命令是否需要普通用户以root执行执行时是否需要保留完整参数是否真的需要NOPASSWD默认情况下Defaults env_reset必须开启且不要轻易把环境变量加入env_keep。在真实生产环境里优先考虑的做法是把需要特权的操作封装成独立脚本并用sudoers限制该脚本的参数不要直接把vim、python、perl这类交互式程序暴露给用户。如果一个运维同学真需要在服务器上编辑某个配置文件正确的姿势是让他使用sudo -e以便调用策略编辑器而不是直接放权给vim。在CTF题目设计里防御思维的考察也会反向出现。出题人可能会做成“限制参数”的题目比如只允许/usr/bin/less /var/log/app.log看玩家能不能通过路径绕过拿到其他文件。实测下来less读取别的文件虽然会被规则拦但绕过方式同样存在例如利用软链接指向敏感文件。5. 现场排错与复盘记录5.1 常见问题速查表在实操过程中我经常在几个节点卡住。把这些经验整理成一张表建议存下来对照排查。现象可能原因排查思路执行sudo命令提示当前会话没有tty新拿到的shell为只读终端sudo默认要求tty使用python -c import pty; pty.spawn(/bin/bash)获取一个伪终端或用script /dev/null占用一个ttysudo -l输出里没有可执行命令当前用户权限很低可能不在sudoers里尝试其他低权限账户切换文件如~/.bash_history、数据库配置文件、web目录里的备份文件按:!bash后命令未执行编辑器版本较新或配置限制了转义尝试更直接的路径在vim里执行/bin/bash的绝对路径或换用python等其他工具LD_PRELOAD注入后没反应sudo启用了env_reset且未保留该环境变量检查sudoers配置中Defaults env_keep部分是否含有LD_PRELOAD没有的话此路不通换路tar通配符触发失败文件名参数顺序或tar版本校验不匹配确认两个文件名称准确确认通配符展开后的第一个特殊参数能被tar识别找不到可写目录执行临时脚本系统将临时目录挂载为noexec尝试写入/tmp以外的目录如/var/tmp、/dev/shm用mount查看挂载选项这个表只收录了我在模拟环境下踩过的高频坑。每一条背后都对应着一次试错如果你在自己的靶机里遇到类似报错先走表格里的排查路线往往几分钟就能解开。5.2 一次失败案例的复盘之前在某台模拟靶机里我拿到www-data权限后跑sudo -l看到允许执行/usr/bin/find。当时第一反应是直接跑$ sudo find / -exec /bin/bash \;但执行后返回了一个权限错误。我立刻去查/etc/sudoers发现规则写的是www-data ALL(ALL) NOPASSWD: /usr/bin/find /var/www -exec *意思是只允许在/var/www目录下使用-exec参数列表虽然用了通配符但无法对系统根目录执行。此时如果硬跑就会被规则拒绝。后来我转换思路利用find的-exec在当前用户允许的目录里把/bin/bash以root身份启动实际上还是被限制住因为target不是root权限下的find吗复盘时我意识到这里真正有效的方式可能是利用find的-exec加载一个具有SUID位的副本或者结合其他文件权限漏洞。传统的find -exec /bin/bash用法在这个规则约束下失效说明出题人专门卡了这个点。这个失败案例给我的教训是不要只背命令要先读懂sudoers里对参数范围的限制。最终这台靶机的解法换成去检查web目录里的备份文件从数据库配置里翻到一个高权限用户的密码再用su切换过去最终通过该用户的sudo规则读到flag。整个过程虽然绕但更贴近真实评估场景普通玩家容易在第一步就卡住。结尾个人在实际操作中最深的体会是sudo提权题拼的不是命令数量而是对“权限配置边界”的判断力。拿到sudo -l输出后不急着抄命令先花三分钟想想这个命令能碰文件系统吗能碰环境变量吗能交互吗如果一个都不沾思考它是否有子命令能间接完成这些动作。多经历几次“差一步就成功”的失败反而比顺风顺水拿多少台靶机都更有收获。最后再分享一个小技巧在自己的练习环境里把所有提权路径整理成一张速查笔记记录每条命令生效的前提条件和典型报错。实际比赛时会特别赶笔记能帮你跳过一半的试错过程。老话重提但真的管用。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →