1. 项目概述与核心思路
最近在带新人做安全测试练习,发现很多朋友对“越权漏洞”这个概念理解得比较模糊,尤其是垂直越权。理论看了一大堆,一到实战就不知道怎么下手。正好,Pikachu靶场里有一个非常经典的垂直越权漏洞场景,非常适合用来练手。今天我就结合这个靶场,手把手带你走一遍完整的流程,核心就是教你如何用BurpSuite这个“瑞士军刀”去抓包、分析、并修改Cookie,最终实现从普通用户权限“越级”到管理员权限的操作。这不仅仅是完成一个靶场练习,更是理解Web应用权限控制缺陷的绝佳案例。无论你是刚入门安全测试的新手,还是想巩固基础的老手,跟着这个流程走一遍,你都能对Cookie在身份认证中的作用、越权漏洞的成因和利用方法有一个非常直观和深刻的认识。
简单来说,这个实战的目标很明确:在一个模拟的Web系统(Pikachu靶场)中,我们首先会以普通用户“lucy”的身份登录。然后,通过BurpSuite拦截系统发出的HTTP请求,找到其中用于标识用户身份的Cookie。最关键的一步来了——我们会尝试将这个Cookie的值,修改为另一个更高权限用户(比如管理员“admin”)的会话标识。如果系统在设计时,仅仅依赖客户端传来的Cookie来判断用户身份,而没有在服务端做严格的二次校验,那么我们的修改就可能欺骗服务器,让它误以为我们是管理员,从而执行一些原本只有管理员才能进行的操作,比如添加新用户。这就是一次典型的垂直越权攻击。整个过程的精髓在于对HTTP协议交互的观察和操控,而BurpSuite正是实现这种操控的利器。
2. 环境准备与工具配置
2.1 Pikachu靶场搭建
Pikachu靶场是一个使用PHP/MySQL开发的、专门用于Web漏洞学习和演练的开源项目。它集成了SQL注入、XSS、CSRF、越权等常见漏洞,环境依赖简单,非常适合在本地搭建。
首先,你需要一个基础的Web运行环境。我推荐使用PHPStudy、XAMPP或WAMP这类集成环境包,它们一键安装Apache、PHP和MySQL,省去大量配置时间。这里以PHPStudy为例:
- 下载与安装:从PHPStudy官网下载最新版本并安装。安装路径建议不要有中文和空格,比如
D:\phpstudy_pro。 - 启动服务:打开PHPStudy,在“首页”标签页,启动Apache和MySQL服务。确保它们的状态显示为绿色“运行中”。
- 部署靶场:下载Pikachu靶场的源码压缩包(通常是一个ZIP文件)。解压后,将整个
pikachu文件夹复制到PHPStudy的网站根目录下。对于PHPStudy V8版,这个目录通常是D:\phpstudy_pro\WWW\。 - 初始化数据库:打开浏览器,访问
http://localhost/pikachu。首次访问时,页面会提示你“数据库没有连接,请先进行初始化安装”。点击该链接或按钮,进入初始化页面。通常,你只需要点击“安装/初始化”按钮即可。Pikachu会自动创建所需的数据库和表,并插入演示数据。 - 验证安装:初始化成功后,刷新页面,你应该能看到Pikachu靶场的主界面,左侧是漏洞分类菜单。找到并点击“越权漏洞”->“垂直越权”,我们的实战舞台就准备好了。
注意:如果初始化失败,请检查PHPStudy中的MySQL服务是否真的启动成功,以及PHP的版本。Pikachu对PHP 5.4+和7.x版本兼容性较好,遇到问题可以尝试切换PHP版本。
2.2 BurpSuite配置与浏览器代理设置
BurpSuite是本次实战的核心工具,它是一个用于攻击Web应用程序的集成平台。我们主要用到它的代理(Proxy)和重放(Repeater)功能。
- 获取BurpSuite:从PortSwigger官网下载社区版(免费)或专业版。社区版功能对于本次学习和大多数基础测试已经足够。
- 启动与基础配置:首次启动BurpSuite,它会让你选择临时项目或保存项目,按默认选择即可。进入主界面后,我们需要先配置代理监听。
- 切换到Proxy标签页,然后进入Options子标签。
- 确保
Proxy Listeners中有一条监听器,默认是127.0.0.1:8080且状态为Running。如果没有,可以点击“Add”添加,绑定地址(Bind to address)选127.0.0.1,端口(Port)用8080。
- 浏览器代理设置:要让浏览器的流量经过BurpSuite,需要配置浏览器代理。以Chrome为例(Firefox配置类似):
- 安装浏览器插件如
SwitchyOmega或直接使用系统代理设置。 - 我更喜欢用SwitchyOmega,配置一个情景模式,代理协议为
HTTP,代理服务器为127.0.0.1,端口为8080。然后将其设置为活动模式。 - 简单方法:也可以直接在Windows系统设置中搜索“代理”,手动设置HTTP代理为
127.0.0.1:8080。
- 安装浏览器插件如
- 安装BurpSuite证书(重要):配置好代理后,用浏览器访问任意HTTP网站(如
http://example.com),BurpSuite会拦截到请求。但访问HTTPS网站(如https://google.com)会显示证书错误,因为BurpSuite在中间对HTTPS流量进行了解密和再加密。为了解决这个问题,需要安装BurpSuite的CA证书到浏览器受信任的根证书颁发机构。- 在浏览器中访问
http://burp或http://127.0.0.1:8080。 - 点击 “CA Certificate” 按钮下载证书文件(
cacert.der)。 - 将证书导入到操作系统或浏览器的受信任根证书存储中。具体步骤因操作系统和浏览器而异,网上有详细教程,这一步至关重要,否则无法拦截HTTPS流量。
- 在浏览器中访问
- 验证代理:完成证书安装后,确保BurpSuite的
Intercept is on按钮是按下状态(拦截开启),然后访问http://localhost/pikachu。你应该能在BurpSuite的Proxy -> Intercept标签页看到拦截到的HTTP请求。点击“Forward”可以放行请求。这说明代理配置成功。
3. 漏洞原理与场景深度解析
3.1 什么是垂直越权?
在深入操作之前,我们必须把原理吃透。越权漏洞主要分为水平越权和垂直越权两类。
- 水平越权:指相同权限级别的用户之间,能够非法访问或操作本不属于自己的数据。例如,用户A能查看或修改用户B的订单、个人信息等。问题出在服务端没有对数据访问进行“属主”校验。
- 垂直越权:这是我们本次实战的重点。它指的是低权限用户能够执行高权限用户才能执行的操作。例如,一个普通论坛会员,通过某种手段获得了版主或管理员的权限,可以进行删帖、封禁用户等操作。垂直越权的危害通常比水平越权更大,因为它直接破坏了整个系统的权限层级体系。
垂直越权的根本原因在于:服务端对客户端提交的请求,在处理敏感操作时,完全信任或过度依赖客户端提供的信息(如Cookie、参数)来判断用户的权限,而没有在服务端会话(Session)中重新、严格地校验当前执行操作的用户是否真正拥有该权限。
3.2 Cookie、Session与身份认证
要理解如何利用Cookie实现越权,必须清楚Cookie和Session在Web登录中的作用。
- Session(会话):当用户成功登录后,服务器端会为该用户创建一个唯一的Session对象,里面存储了该用户的登录状态、用户ID、角色权限等信息。这个Session有一个唯一的ID,称为Session ID。
- Cookie:因为HTTP协议是无状态的,服务器需要一种方式在多次请求中识别同一个用户。于是,在创建Session后,服务器会将这个Session ID通过响应头
Set-Cookie发送给用户的浏览器。 - 身份维持:浏览器收到这个Cookie(里面包含了Session ID)后,会将其保存起来。之后,该浏览器向同一网站发起的每一个HTTP请求,都会自动通过请求头
Cookie将这个Session ID带回给服务器。 - 权限判定:服务器收到请求后,通过请求中的Session ID找到对应的服务器端Session对象,然后从Session中读取用户的身份和权限信息,从而决定是否允许执行当前请求的操作。
漏洞产生的关键点:如果系统在判断用户是否有权进行“添加用户”这个操作时,逻辑是这样的:
// 错误示范:直接从客户端Cookie取用户名判断权限 $username = $_COOKIE['username']; if ($username == 'admin') { // 允许添加用户 } else { // 拒绝操作 }这段代码的致命缺陷是,它信任了客户端传来的Cookie: username=admin。攻击者完全可以修改这个Cookie值。正确的做法应该是:
// 正确示范:从服务端Session取用户名判断权限 session_start(); $username = $_SESSION['username']; // Session中的信息存储在服务器,用户无法直接修改 if ($username == 'admin') { // 允许添加用户 }Pikachu靶场的垂直越权模块,模拟的就是第一种错误逻辑。它可能将用户名直接明文放在了Cookie里,或者使用了一个可预测、可篡改的Token来标识用户身份和权限。
3.3 Pikachu靶场垂直越权场景分析
进入Pikachu靶场的“垂直越权”模块,我们通常会看到两个功能链接:“查看用户列表”和“添加用户”。页面上可能还会显示当前登录的用户,比如“lucy”。
- 正常流程:
- 用户“lucy”登录,服务器设置一个Cookie,例如
Cookie: username=lucy; level=user。 - “lucy”点击“查看用户列表”,可以正常查看。
- “lucy”点击“添加用户”,提交请求。服务器检查请求中的Cookie,发现
username=lucy, level=user,于是拒绝该操作,返回“权限不足”。
- 用户“lucy”登录,服务器设置一个Cookie,例如
- 攻击流程(目标):
- 用户“lucy”登录。
- 在发起“添加用户”请求时,使用BurpSuite拦截该请求。
- 将请求中的Cookie修改为管理员的标识,例如
Cookie: username=admin; level=admin。 - 将修改后的请求发送给服务器。
- 服务器检查Cookie,看到
username=admin,便认为这是管理员在操作,于是执行添加用户的逻辑。越权成功。
我们的实战,就是要完整再现这个攻击流程,并理解其中每一个环节。
4. 实战操作:手把手利用BurpSuite实现越权
4.1 第一步:正常登录与观察
首先,我们以普通用户身份进行正常操作,目的是熟悉流程并捕获关键的请求数据。
- 在浏览器中,访问Pikachu的垂直越权页面 (
http://localhost/pikachu/vul/overpermission/vertical/vertical.php)。 - 使用提供的测试账号登录。在Pikachu中,通常会有预设账号,比如普通用户
lucy/password,管理员admin/123456。我们先用lucy登录。 - 登录成功后,注意观察页面变化。页面上可能会显示“欢迎,lucy”之类的提示。更重要的是,打开浏览器的开发者工具(F12),切换到“网络(Network)”或“应用程序(Application)”标签,查看当前站点的Cookie。你应该能看到一个或多个由
localhost设置的Cookie。记录下它们的名称和值,例如你可能看到username=lucy,或者一个看起来像乱码的PHPSESSID=abc123def...。这一步是了解系统如何标识用户的关键。
4.2 第二步:配置BurpSuite进行抓包
现在,我们要让BurpSuite开始工作。
- 确保BurpSuite的代理监听已开启,浏览器代理已正确指向BurpSuite。
- 在BurpSuite的Proxy -> Intercept标签页,确认Intercept is on按钮是红色按下状态,表示拦截功能开启。
- 回到浏览器,在已登录的状态下,点击页面上那个“添加用户”的按钮或链接。注意,先不要填写任何添加用户的信息,只是点击这个链接,让它触发一个请求。
- 此时,BurpSuite的Intercept界面会立即捕获到这个HTTP请求,并暂停转发。你看到的就是浏览器发出的“请求添加用户页面”的GET请求。
实操心得:很多新手在这一步会直接去填表单提交,然后抓不到想要的包。原因是“点击添加用户链接”和“提交添加用户表单”是两个独立的请求。前者通常是GET请求,用于加载表单页面;后者是POST请求,包含了你填写的用户名、密码等数据。我们首先要分析的是第一个GET请求,看看Cookie是如何传递的。如果这个页面加载时就已经根据Cookie判断了权限并返回了不同的页面内容(比如直接返回无权限提示),那我们的攻击点可能就在这个GET请求上。如果它返回了表单,那么攻击点就在后续的POST请求上。Pikachu的漏洞通常设计在POST请求的处理逻辑中。
4.3 第三步:分析请求与定位关键Cookie
在BurpSuite拦截到的请求中,我们需要仔细研究请求头。
GET /pikachu/vul/overpermission/vertical/vertical_add.php HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0... Accept: text/html,application/xhtml+xml... Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7... Accept-Encoding: gzip, deflate Connection: close Cookie: username=lucy; level=user; PHPSESSID=6f5q7s8t9u0v1w2x3y4z Upgrade-Insecure-Requests: 1重点关注Cookie:这一行。在这个例子中(模拟Pikachu可能的情况),我们看到三个Cookie项:
username=lucy:这很可能就是系统用来判断用户身份的字段。太明显了!level=user:这直接表明了用户的权限等级。PHPSESSID=...:这是PHP的标准会话ID。如果系统正确使用了Session,权限信息应该存储在服务器端与该PHPSESSID对应的Session中,那么只修改客户端的username和level是没用的。但Pikachu为了演示漏洞,其代码逻辑可能直接读取了username这个Cookie值,而忽略了PHPSESSID对应的真实Session。
我们的假设:这个靶场的漏洞代码逻辑是,在处理vertical_add.php的请求时(无论是GET还是POST),直接从$_COOKIE[‘username’]或$_COOKIE[‘level’]中取值来判断权限,而不是从$_SESSION中取。
4.4 第四步:修改Cookie并重放请求
这是攻击的核心步骤。我们将尝试把低权限的Cookie替换成高权限的。
在BurpSuite的Intercept界面,直接修改请求头中的Cookie值。将
username=lucy改为username=admin,将level=user改为level=admin。修改后请求头如下:Cookie: username=admin; level=admin; PHPSESSID=6f5q7s8t9u0v1w2x3y4z注意:PHPSESSID保持不变,因为我们不确定服务端是否同时验证了Session。先尝试只修改明显的身份标识字段。
修改完成后,点击Forward按钮,将这个修改后的请求发送给服务器。
切换到浏览器,观察页面变化。可能会出现几种情况:
- 情况A(成功):浏览器直接显示了一个“添加用户”的表单页面,而之前用lucy账号点击时可能显示的是“权限不足”或直接跳转。这说明GET请求的权限校验已经绕过。
- 情况B(仍需POST):页面显示了表单,但提交表单时还需要再次绕过校验。这很正常,我们继续。
4.5 第五步:实施越权操作(添加用户)
如果上一步成功看到了添加用户的表单,那么最关键的权限关卡已经过了。现在我们来完成添加用户的操作。
在浏览器显示的表单中,填写你想要添加的新用户信息,例如:用户名
test_user,密码test_pass。在点击表单的“提交”或“添加”按钮之前,再次确保BurpSuite的拦截是开启的(Intercept is on)。
点击提交按钮。BurpSuite会拦截到这次POST请求。
分析拦截到的POST请求。它应该长这样:
POST /pikachu/vul/overpermission/vertical/vertical_add.php HTTP/1.1 Host: localhost Content-Type: application/x-www-form-urlencoded Content-Length: 35 Cookie: username=lucy; level=user; PHPSESSID=6f5q7s8t9u0v1w2x3y4z username=test_user&password=test_pass注意,这个POST请求的Cookie,依然是lucy的!这是因为浏览器自动携带了当前站点的Cookie。我们需要再次修改它。
将POST请求中的Cookie也修改为管理员的值:
Cookie: username=admin; level=admin; PHPSESSID=6f5q7s8t9u0v1w2x3y4z请求体(
username=test_user&password=test_pass)保持不变。点击Forward发送修改后的POST请求。
4.6 第六步:验证攻击结果
发送请求后,切换到浏览器查看响应。
- 直接观察响应:BurpSuite在拦截模式下,你可以在Proxy -> HTTP history标签页找到刚才发送的POST请求,查看其响应(Response)。如果响应中包含了“添加成功”、“用户创建成功”等字样,或者没有明显的错误信息,则很可能成功了。
- 功能验证:回到Pikachu靶场的“查看用户列表”页面。刷新页面,看看列表中是否出现了你刚刚添加的
test_user。如果出现了,那么恭喜你,垂直越权攻击成功完成!你以普通用户lucy的身份,通过篡改Cookie,成功执行了管理员才能做的“添加用户”操作。
5. 漏洞根因分析与修复建议
5.1 漏洞代码逻辑推测
基于我们的攻击过程,可以反向推断出Pikachu靶场中漏洞代码的大致逻辑(仅为教学模拟):
存在漏洞的vertical_add.php处理逻辑可能如下:
// vertical_add.php (漏洞版本) // 判断是否有权限执行添加操作 $username = $_COOKIE['username']; // 错误:直接从Cookie取用户身份 $level = $_COOKIE['level']; // 错误:直接从Cookie取用户等级 if ($level != 'admin') { die('权限不足!'); } // 执行添加用户的数据库操作 if ($_SERVER['REQUEST_METHOD'] == 'POST') { $new_user = $_POST['username']; $new_pass = md5($_POST['password']); // 简单MD5加密,仅作示例 // ... 执行INSERT语句 ... echo "用户 $new_user 添加成功!"; }这段代码的致命问题在于,它完全信任了客户端传来的Cookie。攻击者可以轻易伪造Cookie。
5.2 正确的权限校验方式
安全的做法必须基于服务器端会话(Session)。
修复后的vertical_add.php逻辑应如下:
// vertical_add.php (安全版本) session_start(); // 开启会话 // 判断用户是否登录(检查Session中是否存在登录标识) if (!isset($_SESSION['is_login']) || $_SESSION['is_login'] !== true) { header('Location: login.php'); exit(); } // 判断用户是否为管理员(从Session中读取用户角色) if ($_SESSION['user_role'] != 'admin') { // ‘user_role’在登录时存入Session die('权限不足!'); } // 执行添加用户的数据库操作 if ($_SERVER['REQUEST_METHOD'] == 'POST') { // 这里还可以增加CSRF Token校验,防止跨站请求伪造 if (!validate_csrf_token($_POST['token'])) { die('非法请求!'); } $new_user = $_POST['username']; $new_pass = password_hash($_POST['password'], PASSWORD_DEFAULT); // 使用强哈希 // ... 使用参数化查询防止SQL注入 ... echo "用户 $new_user 添加成功!"; }核心修复点:
- 使用Session而非Cookie存储敏感信息:用户登录状态(
is_login)、用户ID、角色(user_role)等关键信息应存储在服务器端的Session中。 - Session ID是唯一桥梁:客户端仅通过Cookie持有无法被篡改的Session ID(如PHPSESSID)。服务器通过这个ID找到对应的Session数据进行校验。
- 关键操作双重校验:对于任何敏感操作(增删改查),服务端在处理请求时,都必须从当前请求关联的Session中重新获取用户身份和权限进行校验,绝不能依赖URL参数、POST表单字段或Cookie中的用户标识。
- 补充安全措施:如使用CSRF Token防止跨站请求伪造,使用预处理语句防止SQL注入,使用强密码哈希算法等。
6. 实战扩展与防御思考
6.1 使用BurpSuite的Repeater模块进行高效测试
在实战中,我们使用了Intercept(拦截)模式。但在更复杂的测试中,频繁开关拦截会影响正常浏览。BurpSuite的Repeater(重放器)模块是更强大的工具。
- 在Proxy的HTTP history中,找到你感兴趣的请求(比如lucy的添加用户POST请求)。
- 右键点击该请求,选择Send to Repeater。
- 切换到Repeater标签页,你可以看到这个请求被完整地复制过来了。
- 在这里,你可以随意修改请求的任何部分(URL、参数、Cookie、Headers),然后点击Send按钮,右侧会立即显示服务器的响应。
- 你可以多次修改、多次发送,对比响应结果,无需拦截浏览器流量,效率极高。这对于测试不同Cookie值、参数组合非常方便。
6.2 自动化测试思路:Intruder模块
如果我们需要批量测试多个可能的Cookie值(例如,猜测管理员的用户名或Session ID),手动修改效率太低。BurpSuite的Intruder(入侵者)模块可以自动化这个过程。
- 将目标请求发送到Intruder。
- 在Positions标签页,清除所有自动标记的变量,然后手动选中Cookie中你想要爆破的部分(比如
username=后面的值lucy),点击“Add”将其设为攻击变量。 - 在Payloads标签页,设置Payload。例如,我们可以用一个简单的字典,包含
admin,root,administrator,superuser等常见管理员用户名。 - 点击“Start attack”。Intruder会自动用字典中的每个值替换变量,发送大量请求,并记录每个请求的响应状态码、长度、内容等。
- 通过分析响应(比如,响应长度突然变长、内容里出现了“添加成功”等关键字),我们可以快速判断哪个Payload(即哪个用户名)让服务器返回了成功的页面。
6.3 针对越权漏洞的防御 checklist
作为一名开发者,在设计和评审代码时,应时刻警惕越权漏洞。以下是一份简单的自查清单:
| 检查项 | 安全做法 | 风险做法 |
|---|---|---|
| 身份认证 | 所有敏感操作前,必须从服务器端Session中校验用户登录状态 ($_SESSION[‘is_login’])。 | 通过Cookie、URL参数、隐藏表单字段传递用户ID。 |
| 权限校验 | 执行操作前,从Session中获取当前用户的角色/权限,与操作所需权限进行比对。 | 根据客户端上传的用户ID或角色参数进行权限判断。 |
| 数据归属 | 查询、修改、删除数据时,SQL语句中必须包含当前用户ID作为条件(如WHERE user_id = :current_user_id)。 | 仅根据客户端提供的目标数据ID进行操作,不校验该数据是否属于当前用户。 |
| 直接对象引用 | 避免使用连续的、可预测的ID(如1,2,3)。使用随机、不可预测的UUID或对ID进行加密混淆。 | 使用?id=123这样的参数直接访问资源。 |
| 日志与监控 | 记录所有敏感操作的日志,包括操作者、时间、IP、具体动作。定期审计异常操作。 | 没有操作日志或日志不完整,无法追溯攻击行为。 |
6.4 从攻击者视角到防御者视角的转变
完成这个实战练习,最大的收获不仅仅是学会了一个攻击技巧。更重要的是,它强制你从“数据流”的角度去思考一个Web应用:
- 请求从哪里来?(浏览器)
- 请求里带了什么?(URL、Headers、Cookie、Body)
- 服务器相信了什么?(它选择信任了请求中的哪些部分?)
- 服务器根据什么做决定?(是根据它自己内存(Session)里的数据,还是客户端送来的数据?)
当你习惯用这种视角去审视一个功能时,无论是进行安全测试还是开发,你都能一眼看出那些“信任了不该信任的东西”的代码。这才是学习漏洞利用的真正价值——不是为了攻击,而是为了在构建系统时,能主动避免这些陷阱,写出更健壮、更安全的代码。