靶场实战 · 15
SSRF(服务端请求伪造)
Pikachu 靶场 · 2 关 · 难度 ★★★ · 预计 50 分钟
SSRF=让服务器替攻击者发请求。类比:攻击者打不进"内网"(比如公司内部系统),但内网里的服务器能访问内网。如果网站的某个功能允许"填一个 URL,我替你访问并显示结果",攻击者就把 URL 填成内网地址——服务器成了攻击者的"内应"。防火墙防外网,SSRF 从内网打内网。

第 1 关SSRF(curl)
入口:http://127.0.0.1/pikachu/vul/ssrf/ssrf_curl.php
过关标准:回显靶场"内网信息页"内容
💡 类比故事网站有个"URL 查看"工具:你给个网址,服务器用 curl 访问并把内容回显给你。你填自己电脑的网址 127.0.0.1——注意,这是服务器自己访问自己(服务器和你同一台机器)。填靶场内网信息页,就能看到"只有内网才能看"的内容。
原理白话:页面提供一个"URL 查看"工具,服务器用 curl 请求用户给的 URL 并回显——无任何目标校验。
看源码:
$url = $_GET['url'];
echo curl_exec($ch); // curl 用户可控的 URL
📋 详细步骤
- 输入
http://127.0.0.1/pikachu/ → 正常回显(注意:这是服务器自己访问自己,体会"服务器替你发请求") - 读靶场内网信息页:
http://127.0.0.1/pikachu/vul/ssrf/ssrf_info/info.php → 回显内部信息
📷 练习截图:SSRF 回显内网信息页内容
- macOS:
file:///etc/passwd 直接读本地文件(curl 支持 file 协议) - 了解内网探测思路:把 127.0.0.1 换成内网 IP 段(如 192.168.1.1)逐个探测端口——这就是打内网的入口(真实环境中这才是 SSRF 的完整用法,靶场里了解思路即可)
过关标准达成:内网资源被"借"服务器之手访问。
🧯 卡住了?对号入座
- 现象:请求没回显 → 原因:url 参数要传完整地址(含 http://);先试
http://127.0.0.1/pikachu 这种靶场自身地址 - 现象:返回错误/超时 → 原因:目标端口没开服务属正常;本关重点在"服务器替你去访问了内网地址"
- 现象:读不到内网其他机器 → 原因:靶场在你电脑上,"内网"就是本机各端口;换 127.0.0.1 的其他端口试
🤔 想一想:curl 这关能直接读服务器本机文件吗?
答:curl 默认打 http 协议;要读文件得配合 file:// 或靠下一关 file_get_contents,这正是两关能力的区别
🛡 防御视角URL 白名单 + 禁止内网地址段(127.0.0.0/8、10.0.0.0/8、192.168.0.0/16、169.254.0.0/16)+ 禁止 file/dict/gopher 等协议。
第 2 关SSRF(file_get_contents)
入口:http://127.0.0.1/pikachu/vul/ssrf/ssrf_fgc.php
过关标准:回显内网信息页内容
💡 类比故事同上,只是服务器"替你访问"用的函数换了一个(PHP 的 file_get_contents() 同样支持 URL 和 file 协议)。理解:危险的不是函数,而是"未校验的用户可控 URL"。
原理白话:同上,只是读取函数换成 PHP 的 file_get_contents(),它同样支持 URL 和 file 协议。
📋 详细步骤
?file=http://127.0.0.1/pikachu/vul/ssrf/ssrf_info/info.php → 内网信息回显- macOS:
?file=file:///etc/passwd → 本地文件读取 - 与 curl 版对照,理解"危险的不是函数,而是未校验的用户可控 URL"
过关标准达成:内网访问成立。
🧯 卡住了?对号入座
- 现象:file:// 协议失败 → 原因:确认 allow_url_fopen 开启;Windows 用
file:///C:/Windows/win.ini,Linux 用 file:///etc/passwd - 现象:返回空白 → 原因:文件不存在或路径错;先读一个确定存在的文本文件
- 现象:http 也不行 → 原因:与 3.15.1 相同,确认 url 参数完整(含协议头)
🛡 防御视角同 3.15.1。
🤔 想一想:SSRF 探测内网端口时,怎么判断端口是否开放?
答:看响应差异——返回内容/响应时间/错误信息不同
每通一关,在 □ 里打钩。建议配合"过关标准"自查,全部打钩后你就是这套靶场的全通选手了。
暴力破解(4 关)
- 3.1.1 表单暴力破解:Intruder 爆破出 123456
- 3.1.2 验证码绕过(on client):不理验证码爆破成功
- 3.1.3 验证码绕过(on server):复用验证码爆破成功
- 3.1.4 token 防爆破:脚本输出"密码是: 123456"
XSS(10 关)
- 3.2.1 反射型(get):F12 改 maxlength 或 Burp 改参数后弹窗
- 3.2.2 反射型(post):登录后提交 payload 弹窗
- 3.2.3 存储型:换浏览器访问同样弹窗
- 3.2.4 DOM 型:URL 构造 payload 弹窗
- 3.2.5 DOM 型-X:表单提交闭合 payload 弹窗
- 3.2.6 盲打:管理员后台中招,Cookie 被收走
- 3.2.7 过滤:img onerror 绕过弹窗
- 3.2.8 htmlspecialchars:javascript: 协议点链接弹窗
- 3.2.9 href 输出:javascript: 协议弹窗
- 3.2.10 js 输出:闭合引号弹窗
CSRF(3 关)
- 3.3.1 CSRF(get):点恶意链接资料被改
- 3.3.2 CSRF(post):本地钓鱼页自动提交成功
- 3.3.3 CSRF Token:错误 token 被服务器拒绝
SQL 注入(10 关)
- 3.4.1 数字型:or 1=1 查全表
- 3.4.2 字符型:引号闭合查全表
- 3.4.3 搜索型:%' or 1=1# 查全表
- 3.4.4 xx 型:') or 1=1# 查全表
- 3.4.5 insert/update:updatexml 报错带出库名
- 3.4.6 delete:报错带出库名
- 3.4.7 http header:改 User-Agent 报错带出库名
- 3.4.8 布尔盲注:真假差异猜出数据
- 3.4.9 时间盲注:sleep 延迟差异
- 3.4.10 宽字节:%df 吃掉反斜杠
RCE(2 关)
- 3.5.1 exec "ping":命令拼接执行 ipconfig/whoami
- 3.5.2 exec "eval":phpinfo() 页面出现
文件包含(2 关)
- 3.6.1 LFI:读出 win.ini / etc/passwd
- 3.6.2 RFI:远程 txt 代码被执行
文件上传(3 关)
- 3.7.1 client check:改包上传,蚁剑连上
- 3.7.2 MIME:改 Content-Type 上传,蚁剑连上
- 3.7.3 图片马:配合 LFI 执行代码
文件下载(1 关)
- 3.8 文件下载:下载到 config.inc.php
越权(2 关)
- 3.9.1 水平越权:lucy 看到 vince 信息
- 3.9.2 垂直越权:普通用户自封管理员
目录遍历(1 关)
敏感信息泄露(1 关)
PHP 反序列化(1 关)
XXE(1 关)
URL 跳转(1 关)
SSRF(2 关)
- 3.15.1 SSRF(curl):回显内网信息页
- 3.15.2 SSRF(file_get_contents):回显内网信息页
| 漏洞类型 | 一句话成因 | 一句话防御 |
|---|
| 暴力破解 | 无次数限制、验证码失效 | 失败锁定 + 服务端一次性验证码 + token |
| XSS | 用户输入进 HTML 未编码 | 输出按上下文编码(htmlspecialchars/JS转义/URL协议白名单) |
| CSRF | 浏览器自动带 Cookie + 无来源校验 | CSRF Token + SameSite + 关键操作二次确认 |
| SQL 注入 | 输入拼进 SQL 语句 | 参数化查询(一切注入的正解) |
| RCE | 输入拼进命令/eval | 白名单 + 禁危险函数 + 最小权限 |
| 文件包含 | 文件名参数可控 | 白名单 + 关闭 allow_url_include |
| 文件上传 | 校验可绕过、脚本可执行 | 服务端内容校验 + 上传目录禁执行 + 重命名 |
| 文件下载/目录遍历 | 路径参数可控 | id 映射 + 拒绝 ../ |
| 越权 | 只验登录不验归属/角色 | 对象级授权(用 session 身份取数)+ 接口级 RBAC |
| 信息泄露 | 注释/备份/报错藏敏感信息 | 上线前敏感扫描 + 统一错误页 |
| 反序列化 | 反序列化用户输入 | 不反序列化不可信输入 / 白名单类 |
| XXE | XML 外部实体未禁用 | 禁用 DTD/外部实体 |
| URL 跳转 | 跳转目标未校验 | 域名白名单 + 协议白名单 |
| SSRF | 服务器代发请求目标未校验 | URL 白名单 + 禁内网地址/危险协议 |
暴力破解
- 简述验证码绕过(on server)关卡为什么同一个验证码能反复用?(要点:session 未销毁,一次性机制缺失)
- token 防爆破关卡的 token 从哪来?为什么爆破工具不能直接重用?(要点:服务端生成、每次刷新、攻击者拿不到新值)
- 设计一个登录接口的三个防爆破措施。(要点:锁定/限流/验证码/token 任选三)
XSS
- 反射型、存储型、DOM 型三种 XSS 的区别?(要点:是否入库、是否经服务器、危害范围)
- 为什么过滤
<script> 关键字防不住 XSS?举两个绕过例子。(要点:img onerror、svg onload、大小写等) htmlspecialchars 使用正确(ENT_QUOTES)但输出在 href 里,还有风险吗?(要点:javascript: 协议,需协议白名单)- 盲打 XSS 的目标是谁?为什么选择打后台?(要点:管理员权限高、后台防护常被忽视)
CSRF
- 用一句话解释 CSRF 为什么能成立?(要点:浏览器自动携带 Cookie,服务器无法区分"本人操作"与"被伪造请求")
- GET 改 POST 能防 CSRF 吗?为什么?(要点:不能,POST 也能被自动提交表单伪造)
- CSRF Token 为什么攻击者拿不到?(要点:随机生成、同源策略保护、不在攻击者可读处)
SQL 注入
- 字符型注入 payload
1' or '1'='1 中每个部分的作用?(要点:闭合、恒真、语法补全) - 报错注入利用了什么机制把数据带出来?(要点:updatexml 等函数参数不合法→报错信息包含数据)
- 布尔盲注和时间盲注分别靠什么"信使"传数据?(要点:页面真假差异 / 响应时间)
- 宽字节注入为什么能绕过 addslashes?(要点:GBK 多字节吞掉反斜杠)
- 为什么参数化查询能防所有 SQL 注入?(要点:语句结构与数据分离,数据不再被解析为代码)
RCE / 文件包含 / 文件上传
- 命令注入里
; & && | 分别是什么作用?(要点:顺序/后台/与/管道) - 图片马为什么直接访问不执行、配合文件包含就执行?(要点:后缀不交 PHP 解释器 vs include 强制解析)
- 文件上传的三道正确防线?(要点:服务端内容校验、目录禁执行、重命名存储)
越权 / 信息泄露
- 水平越权和垂直越权的区别?(要点:同级别横向 vs 低权限上探高权限)
- "前端隐藏按钮"为什么不算权限控制?(要点:前端内容攻击者全可见,必须后端校验)
进阶漏洞
- XXE 中的 DTD 和实体是什么?(要点:DTD 定义结构、ENTITY 声明引用,外部实体可指向文件/URL)
- SSRF 为什么能突破防火墙?(要点:请求由内网服务器发出,防火墙放行)
- PHP 反序列化漏洞的根源是什么?(要点:unserialize 执行魔术方法,数据可控即代码可控)
期末实操考核说明(供参考):随机抽 3 关独立通关(不允许看手册),提交通关报告(截图 + 原理 + 修复建议)。
- 只能在本地靶场练习。对任何非授权系统(包括学校官网、同学电脑、云主机)测试漏洞,均可能触犯《刑法》第 285 条(非法侵入计算机信息系统罪)、第 286 条(破坏计算机信息系统罪)和《网络安全法》第 27 条
- 练习限
127.0.0.1 和本机局域网靶场;不得把攻击流量发到互联网真实网站 - 不传播、不出售攻击工具与手册给非课程同学;通关报告不公开发布
- 将来参与 SRC(漏洞赏金)平台时,须遵守平台授权范围,越界即违法
- 强调:学习攻击技术是为了防御,安全从业者的第一素质是底线意识
- Pikachu 源码仓库:https://github.com/zhuifengshaonianhanlu/pikachu
- PHPStudy 官网:https://www.xp.cn
- Burp Suite 社区版:https://portswigger.net/burp/communitydownload
- 中国蚁剑:https://github.com/AntSwordProject/antSword
- OWASP Top 10:https://owasp.org/www-project-top-ten/
本手册全部 payload 均针对本地 Pikachu 靶场环境,仅用于学习练习。使用时请按实际部署路径/端口微调。