提权这个词,圈外人听着像黑话,圈内人听得耳朵起茧,但真到靶场里实操,很多人还是卡在"拿到 www-data 之后不知道下一步该干嘛"。这篇是我在某个 Linux 提权靶场里的完整通关复盘(上篇),覆盖从拿到普通用户权限开始,到成功拿下 root 的全部思路和关键操作。相比单纯列一堆命令,我更想讲清楚每一步背后的判断逻辑:为什么这个信息要收集、这个 SUID 文件怎么看有没有问题、那个内核漏洞为什么选它不选别的。适合刚入门想系统训练提权思路的朋友,也适合做过一些靶场但总感觉在"碰运气"的人。
1. 提权靶场到底在练什么:搞清楚目标再动手
1.1 从"有权限"到"够权限"的一步之遥
提权,英文叫 privilege escalation,本质就是你在目标机器上已经有了一个非 root 用户的 shell,比如常见的 www-data,或者靶场里故意放给你的一个低权限账号,然后想尽办法把权限提升到 root。
这套东西在真实渗透里是后半程的关键——漏洞利用拿到的往往只是 Web 服务的低权限 shell,后面所有"有价值操作"(读 shadow 文件、安装后门、横向移动前的本地铺垫)全都卡在权限门口,迈不过去就白折腾。
靶场因为目标明确、环境可控,是练提权手感的绝佳场地。你在里面做的一切操作,都不会被真实业务干扰,也不存在什么"不能打扰线上环境"的顾虑。我打的那个 Linux 提权靶场,第一关就是典型的"给你一个高权限但没到 root 的普通账号",目标只有两个字:root。
1.2 先看一眼靶场的地图,别上来就乱翻
很多新手拿到 shell 的第一反应是到处找 flag,或者顺手敲一长串"看起来厉害"的命令,结果收集的信息互相矛盾,反而把自己绕晕。
我的习惯是先把靶场给定信息理清楚:
- 拿到了什么用户?密码是已知的还是需要自己找?
- 系统里有没有专门提示的"提权入口"文件?
- 当前 shell 的交互性好不好?还是被限制成了非交互式?
这些决定了后续用"手动排查"还是"跑脚本批量收集"。正规靶场一般会给你一个初始账号,密码就是提示里的那个,登录后就是普通用户。信息理清楚了,才轮到侦察。
2. 开局不是打,是摸:系统侦察的五个关键面
提权第一步不是找漏洞,是摸清这台机器的"底细"。侦察越细,后面的选择越准。
2.1 先看自己是谁:用户身份与当前权限
登录以后第一件事,我向来是:
id whoami sudo -lid能告诉你当前用户属于哪些组,有时候"当前用户没权限"但"所在组有权限"就是突破口。sudo -l是重中之重——它列出当前用户能免密或以特定身份执行哪些 sudo 命令,很多靶场的第一道提权口就藏在里面。
我打这个靶场时,sudo -l一开始返回的是"用户不能运行 sudo",也就是没有 sudo 授权,但这不代表结束,只是说明这条路暂时堵死,得往别的方向看。
2.2 再看系统底牌:内核、发行版与架构
uname -a cat /etc/os-release内核版本是用来比对内核漏洞库的,发行版信息则帮你判断这个系统大概"老到什么程度",从而缩小漏洞搜索范围。举例说明:一个内核版本号停留在多年前的 Ubuntu 系统,存在经典内核提权漏洞的概率就相当高;而一个刚更新的系统,内核漏洞路线基本不用想,老老实实回过来翻配置错误。
架构也很关键。x86_64 还是 ARM?编译 exploit 的时候选错架构,直接白编译。
2.3 找出隐藏的"钥匙":SUID 文件、可写脚本与计划任务
这三样是提权思路里的"三件套",侦察阶段一次性摸清:
find / -perm -4000 -type f 2>/dev/null find / -writable -type f 2>/dev/null | grep -v proc | grep -v sys cat /etc/crontab ls -la /etc/cron.d/SUID 文件列表可以让你知道系统里哪些程序以"其他用户身份"运行(后面专门讲);可写文件列表能帮你找到"我能不能篡改某个系统脚本";计划任务则决定"有没有定时脚本可以被利用"。三个方向同时铺开,后续选择合适的路线才有依据。
侦察阶段不需要急着执行任何"看起来像攻击"的动作,它就是一次全面体检。我见过很多人在这个阶段漏看了一个目录下的可写脚本,结果在 SUID 路线上死磕了两个小时,后来回头发现计划任务里早就有现成的口子。
3. 内核漏洞提权:老系统的经典打法
3.1 版本识别与漏洞检索的思路
内核漏洞提权,核心逻辑就是:目标系统内核版本号对应某个已有公开漏洞,而这个漏洞又恰好可以让你本地提权到 root。
侦察阶段拿到的uname -a输出,这时候派上用场。把内核版本号记下来,然后去漏洞库里按版本检索,看有没有匹配的提权漏洞。
这里有个非常容易踩的坑:内核版本号和漏洞的适配不是简单"看到版本号就去找 exp"。很多时候漏洞影响的是某个版本区间,同一个版本可能有多个不同漏洞,不同漏洞利用的稳定性天差地别。我的做法是:
- 先把内核版本和发行版绑在一起判断(Ubuntu 要看内核编号,还要看 Ubuntu 本身版本号)
- 看到多个候选 exp 时,优先选"最近被验证有效的",而不是选"名声最大的"
- 把 exp 的说明文档通读一遍,确认它要的内核配置和靶机一致
3.2 编译与运行的现实问题
找到 exp 只是开始,真正动手编译又是另一道坎。靶机上不一定装了 gcc,就算装了,版本也可能不对,编译报错能把人折腾到崩溃。
我的习惯是:
which gcc先确认有没有编译器。要是没有,可以考虑:
- 在本地用同样的内核架构和相近的 libc 版本静态编译,然后把二进制传上去
- 找现成的预编译版本,但这东西得擦亮眼睛,来历不明的二进制在任何环境下都不建议随手运行
编译之后运行,正常情况会直接拿到 root shell。如果没反应或者报错,第一步不是改代码,而是看输出信息——很多 exp 在编译阶段会警告"可能需要特定内核配置",这种警告往往比运行崩溃更值得注意。
3.3 为什么说内核提权是"双刃剑"
内核类 exp 是所有提权路线里最"重"的,原因有两个:
一是效率不稳定。同一个 exp,在 A 机器上一次成功,在 B 机器上可能要重试很多次,因为内核的竞争条件、内存布局这些细节会直接影响成功率。
二是有崩机风险。改内核态的东西,万一手滑了就是系统重启,靶场里的进度直接归零。我每次跑内核 exp 之前,都会先确认靶场支不支持快照回滚,能回滚再跑,这习惯是从第一次"跑崩了从头再来"的惨痛经历里换来的。
所以要给我的建议是:不要一上来就急着走内核路线。先把 SUID、计划任务、sudo 配置这些"软柿子"捏完,实在没路了再回来考虑内核。
4. SUID 提权:系统基因里的突破口
4.1 SUID 机制听懂一次就够
SUID(Set User ID)是 Linux 文件权限里的一个特殊位。普通情况下,程序运行时以"执行者的身份"运行;但一个带 SUID 位的文件,运行时是以"文件所有者的身份"运行。
这设计本来是为了让普通用户能临时用 root 权限执行某些特定程序,比如passwd就需要改/etc/shadow,所以被设置了 SUID。问题在于:如果系统里某个能被你控制的程序也带着 SUID 位,那就等于系统自己开了一扇门,你只是找到了钥匙。
4.2 值得留意的常见 SUID 程序
侦察阶段那行find / -perm -4000 -type f 2>/dev/null,把结果拉出来后,需要逐个判断哪些是可利用的。
常见的可利用程序有:
- 具有交互式功能的编辑器:vim、nano、less、more
- 能执行系统命令的:find、python、perl、ruby、php
- 网络工具:nmap(老版本带交互模式)
- 文件读取/管理类:cp、cat、base64
这些程序的特点就是"在执行自己功能的同时,还能让你进一步执行其他命令"。判断逻辑也很简单:这个程序本身能不能让我执行 shell 或者读文件。
4.3 SUID 提权实操:从找到到拿下的完整路径
我在这套靶场的 SUID 环节里,找出来的是一份名叫find的 SUID 文件。系统里find平时是用来找文件的,但要是它以 root 身份运行,就存在利用空间。
比较通用的操作思路是:
find / -exec whoami \;如果返回root,说明find继承的是 root 权限。接下来就想办法用它执行 shell:
find / -exec /bin/sh -p \;注意那个-p参数,在 SUID 环境下,/bin/sh需要以"不重置有效用户ID"的形态运行,不加-p,有些 shell 自己会把高权限降回去,提权就会静默失败。这是很多人试了没效果的第一号原因。
拿到 root shell 之后,整个 SUID 路线就算打通了。整个过程不涉及内核、不需要编译,只要你对"这个程序能替我做哪些事"有清晰的概念,速度会非常快。
5. 计划任务与PATH注入:借刀杀人的绅士玩法
5.1 计划任务中的"定时炸弹"
计划任务(cron job)是系统按预定时间自动执行脚本的机制。如果某个脚本是以 root 身份调度执行的,而你又恰好能改这个脚本,那你只需要在原地写一段反向 shell 或者修改系统认证文件,等它下次执行,权限就来了。
查看计划任务有几个要点:
cat /etc/crontab ls -la /etc/cron.d/ crontab -l我在靶场上看到/etc/crontab里有一条任务,指向某个脚本,脚本的路径在/opt下。随手看了下脚本权限:
ls -la /opt/backup.sh发现这个脚本是全局可写的——也就是说,启动它的进程是 root,但文件所有者写权限没限制好,任何本地用户都能改内容。这种配置错误在真实系统里并不算罕见,靶场里更是重点考察项。
把内容替换成一段自己的命令后,我等了大概一两分钟,计划任务触发,权限直接到手。整个过程没有攻击任何有防御机制的程序,纯属利用系统自己的"定时行为"。
5.2 PATH劫持:让系统替你执行"意外"
如果脚本内容不能改,别急着放弃,还有一个更"绅士"的思路——PATH 劫持。
原理是这样的:脚本里如果写的是不带绝对路径的命令,比如执行tar或者ls,系统就会按PATH环境变量里列出的目录顺序去查找这个命令。如果脚本的 PATH 里包含了一个当前用户可写的目录,那就可以在那个目录里放一个同名假命令,让脚本执行的时候优先找到你的假命令。
这个手法的前提比较苛刻:脚本必须以 root 身份跑,且脚本内部用了相对命令而不是绝对路径,而且脚本执行环境里 PATH 中包含可写目录。三个条件缺一个都走不通。我在这个靶场没有实际用到这个路径,因为可写脚本那条路已经通了,但这是个值得记住的思路,换个环境可能就成了。
5.3 结合可写目录的联动利用
还有一个容易忽略的细节:如果你当前用户对某个目录有写权限,而这个目录出现在 root 的计划任务脚本路径里,同样能玩联动。比如备份脚本要打包/var/www/html/data,而你正好对这个目录有写权,那把打包目标里的文件换成软链或者放一个特殊的 payload,就可能影响备份结果。
当时我额外确认了一遍可写文件清单,发现系统里还有几个零散的临时目录可以写,只是没到用得上的程度。靶场价值就在这里:思路和判断力是通用的,但在具体机器上要学会"有主次地尝试,不死磕单一方向"。
6. 通关复盘:容易踩的坑和必须养成的习惯
6.1 我见过最多的五个失败原因
第一个,"找到 SUID 文件就盲目尝试,不看程序类型"。不是所有 SUID 都能提权,很多是系统正常程序,或者设置后并没有额外可利用能力。先确认"它能让我做什么",再决定要不要花时间。
第二个,跑内核 exp 前不做版本和配置核对。同一个 exp 在不同内核版本上行为差距很大,运行起来报错不是程序的错,是你没看清说明。
第三个,忽略非交互式 shell 的尴尬。拿到的是一个不能正常交互的 shell 时,很多需要 TTY 的利用手法会失败,建议先想办法升级成完整 shell。
第四个,被"过程成功"骗了。比如find -exec whoami返回root,但不代表你能执行任意命令,有些环境只是命令上下文不同,得真正尝试读/etc/shadow或者进入 root 的 bash 才能验证。
第五个,不注重日志清理和痕迹管理。靶场虽然不强制,但养成习惯对自己有好处,至少在真实演练里不会留下明显的"操作记录"。
6.2 一份可以直接对照的自查清单
我把整个上篇的流程浓缩成了下面这份清单,每次打类似靶场,按照它过一遍基本不会漏东西:
- [ ] 明确当前用户名、uid、gid 和所属组
- [ ] 执行
sudo -l确认 sudo 授权 - [ ] 记录内核版本号、发行版名称与架构
- [ ] 全盘查找 SUID 文件并逐一判断可利用性
- [ ] 查看
/etc/crontab与/etc/cron.d/下的计划任务及其脚本权限 - [ ] 检查全局可写文件,关注
/opt、/tmp、/var/tmp等常见目录 - [ ] 回顾历史命令记录,有时前一个"入侵者"留下的内容就是提示
- [ ] 只有在以上全部排查完毕后,才考虑内核漏洞路线
这份清单相当于提权的"穷举法",虽然不花哨,但胜在不会漏。真要论核心技术能力,我觉得熟练度是一方面,"按清单走、按输出读、按经验判断"这十二个字才是关键。
最后再分享一个个人体会。打这个靶场之前,我也经历过一段"刷了很多教程但到了实战依然懵"的时期,原因就是想得太复杂,忽略了侦察阶段的价值。后来我每次拿到 shell 都强迫自己先花五分钟把该看的全看一遍,哪怕已经知道下一步要干什么也不跳步,提权成功率反而明显提升。这个习惯现在保留了下来,算是这篇上篇讲的所有手法里,最基础也最重要的一条。下篇如果有机会,我会专门把 sudo 规则绕过、capabilities 异常配置、容器逃逸这类进阶路线再拆开讲讲。