目录
本系列为通过《pikachu靶场通关笔记》的CSRF关卡(共3关)渗透集合,通过对CSRF关卡源码的代码审计找到安全风险的真实原因,讲解CSRF原理并进行渗透实践,本文为CSRF03关卡XSS之Token关卡的渗透部分。
一、CSRF原理
CSRF(Cross - Site Request Forgery)跨站请求伪造是一种常见的网络攻击手段,攻击者利用用户已登录的身份,诱使用户在不知情的情况下,向目标网站发送恶意请求。
项目 | 详情 |
---|---|
全称 | Cross - Site Request Forgery(跨站请求伪造) |
攻击原理 | 利用用户已登录目标网站的身份,诱使浏览器在用户不知情时发送恶意请求,借助用户会话信息让网站误认为是合法请求从而执行恶意操作 |
攻击手段 | 通过诱导用户点击恶意链接、加载恶意图片等方式触发恶意请求 |
危害 | 导致用户隐私泄露、财产损失,损害网站信誉 |
防范措施 | 添加 CSRF 令牌,在用户请求中加入唯一标识,服务器端验证其有效性;验证请求来源;使用验证码等 |
二、CSRF Token
CSRF Token 是一种用于防范跨站请求伪造攻击的安全机制。它是一个在用户登录或访问特定页面时,由服务器生成并发送给客户端的唯一随机字符串。当客户端向服务器发送请求时,会将该 Token 包含在请求中。服务器接收到请求后,会验证 Token 的有效性。如果 Token 存在且与服务器端存储的 Token 匹配,那么服务器就认为该请求是合法的;如果 Token 不存在或不匹配,服务器则拒绝处理该请求。
通过这种方式,CSRF Token 能够有效防止攻击者利用用户的身份在用户不知情的情况下发送恶意请求。因为攻击者无法获取到用户合法的 Token,也就无法构造出有效的请求来欺骗服务器。CSRF Token 为 Web 应用程序提供了一层额外的安全保护,增强了系统的安全性和可靠性,是防范 CSRF 攻击的重要手段之一。
三、源码分析
进入pikachu靶场CSRF-Token关卡,登陆后进入个人资料页面,点击修改资料,进入到编辑资料的页面,完整URL如下所示。
http://127.0.0.1/pikachu/vul/csrf/csrfget/csrf_token_edit.php
接下来查看csrf_token_edit.php的源码内容,详细注释后如下所示。
<?php
/**
* Created by runner.han
* There is nothing new under the sun
*/
// 获取当前脚本的文件名,通过 substr 和 strrpos 函数截取 $_SERVER['PHP_SELF'] 中从最后一个 '/' 之后的部分
$SELF_PAGE = substr($_SERVER['PHP_SELF'], strrpos($_SERVER['PHP_SELF'], '/') + 1);
// 此处存在错误,应该使用比较运算符 '==' 而非赋值运算符 '='。
// 若当前页面是 'csrf_get_edit.php',则设置 $ACTIVE 数组用于标记页面的激活状态
if ($SELF_PAGE == "csrf_get_edit.php") {
$ACTIVE = array(
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'active open', '', '', '', 'active', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''
);
}
// 定义项目根目录的相对路径
$PIKA_ROOT_DIR = "../../../";
// 包含项目的头部文件,通常包含一些公共的 HTML 头部信息和样式引用
include_once $PIKA_ROOT_DIR . 'header.php';
// 包含项目的配置文件,可能包含数据库连接信息、常量定义等
include_once $PIKA_ROOT_DIR . "inc/config.inc.php";
// 包含项目的函数库文件,包含一些常用的自定义函数
include_once $PIKA_ROOT_DIR . "inc/function.php";
// 包含项目的 MySQL 操作文件,包含数据库连接和操作的函数
include_once $PIKA_ROOT_DIR . "inc/mysql.inc.php";
// 调用 connect 函数建立数据库连接,并将连接对象赋值给 $link 变量
$link = connect();
// 检查用户是否已登录,调用 check_csrf_login 函数进行验证
// 如果未登录,重定向到登录页面
if (!check_csrf_login($link)) {
// echo "<script>alert('登录后才能进入会员中心哦')</script>";
header("location:token_get_login.php");
}
// 初始化一个空字符串 $html1,用于存储错误提示信息
$html1 = '';
// 检查是否通过 GET 请求提交了'submit' 参数
if (isset($_GET['submit'])) {
// 检查用户是否填写了性别、电话号码、地址、电子邮件并且提交的 token 与 session 中的 token 一致
if ($_GET['sex'] != null && $_GET['phonenum'] != null && $_GET['add'] != null && $_GET['email'] != null && $_GET['token'] == $_SESSION['token']) {
// 调用 escape 函数对 $_GET 数组中的所有数据进行转义处理,防止 SQL 注入
$getdata = escape($link, $_GET);
// 构建 SQL 更新语句,用于更新会员表中的用户信息
// 根据当前用户的用户名更新其性别、电话号码、地址和电子邮件
$query = "update member set sex='{$getdata['sex']}', phonenum='{$getdata['phonenum']}', address='{$getdata['add']}', email='{$getdata['email']}' where username='{$_SESSION['csrf']['username']}'";
// 执行 SQL 更新语句
$result = execute($link, $query);
// 检查 SQL 语句执行后受影响的行数
// 如果受影响的行数为 1 或 0,表示更新成功,重定向到 token_get.php 页面
if (mysqli_affected_rows($link) == 1 || mysqli_affected_rows($link) == 0) {
header("location:token_get.php");
} else {
// 如果更新失败,向 $html1 变量中追加错误提示信息
$html1 .= "<p>修改失败,请重新登录</p>";
}
}
}
// 调用 set_token 函数生成 token
set_token();
?>
其中set_token函数的主要功能是生成一个唯一的 token,并将其存储在 PHP 的会话变量中。每次调用该函数时,它会先检查会话中是否已经存在一个 token,如果存在则将其删除,然后生成一个新的 token。生成的 token 是由一个 5 位的随机数前缀和当前时间的微秒数组成,并且去除了其中的点号。这样可以确保每个 token 都是唯一的,并且难以被猜测或伪造,从而提高了应用程序的安全性,可用于防范 CSRF 攻击等安全场景。set_token定义如下所示。
// 定义一个名为 set_token 的函数,用于生成一个 token
function set_token() {
// 检查 $_SESSION 数组中是否已经存在名为 'token' 的元素
if (isset($_SESSION['token'])) {
// 如果存在,使用 unset 函数删除该元素
unset($_SESSION['token']);
}
// 生成一个新的 token,并将其存储在 $_SESSION['token'] 中
// uniqid 函数用于生成一个唯一的标识符,格式为当前时间的微秒数加上一个可选的前缀
// mt_rand(10000, 99999) 生成一个 5 位的随机数作为前缀
// true 参数表示使用微秒数的完整形式
// str_replace('.', '',...) 用于去除生成的唯一标识符中的点号(.),以确保生成的 token 是一个连续的字符串
$_SESSION['token'] = str_replace('.', '', uniqid(mt_rand(10000, 99999), true));
}
这段 PHP 代码的主要功能是会员信息修改页面,用于处理用户信息的修改操作,具体步骤如下。
- 获取当前页面信息:通过substr和strrpos函数获取当前脚本的文件名,并根据文件名设置页面的激活状态。
- 加载必要文件并建立数据库连接:包含项目所需的各种文件,如头部文件、配置文件、函数库文件和 MySQL 操作文件,并建立与数据库的连接。
- 用户登录验证:检查用户是否已登录,如果未登录则重定向到登录页面。
- 处理用户信息修改请求:当用户通过 GET 请求提交包含submit参数的表单时,检查用户输入的性别、电话号码、地址、电子邮件等信息是否完整,并且检查提交的token是否与session中的token一致。如果所有条件满足,对用户输入的数据进行转义处理,然后执行 SQL 更新语句来更新用户在数据库中的信息。根据 SQL 更新操作的结果,要么重定向到指定页面,要么显示错误提示信息。
- 生成 CSRF Token:调用set_token函数生成 CSRF Token,用于防止 CSRF 攻击。
四、CSRF Token tracker插件
1、插件简介
CSRF Token Tracker 是一款常用于 Burp Suite 的插件,主要用于在渗透测试过程中自动更新 CSRF Token。
- 功能作用:在 Web 应用程序中,CSRF 攻击是一种常见的安全威胁。CSRF Token Tracker 插件的核心功能就是帮助测试人员应对这种攻击。它能够根据预设的规则,从服务器的响应报文中自动提取 CSRF Token,并在后续的请求中自动更新该 Token,确保每个请求都携带正确有效的 Token,从而避免因 Token 过期或无效导致的请求失败,方便测试人员对存在 CSRF Token 验证机制的应用程序进行安全测试。
- 使用方法:一般来说,在 Burp Suite 中安装并启用该插件后,需要在插件的配置界面添加规则。通常需要填写目标应用的 Host 头值以及 CSRF Token 的参数名。如果 Token 在请求和响应中的位置或名称不同,还需要进行相应的配置,以告知插件如何正确提取和更新 Token。例如,对于某些应用,Token 可能存在于特定的 HTTP 头中,或者是隐藏的 HTML 输入字段中,插件都可以通过配置来正确处理这些情况。
- 实际应用场景:在对各种 Web 应用进行安全测试时,如果应用使用了 CSRF Token 来防止跨站请求伪造攻击,那么 CSRF Token Tracker 插件就会发挥重要作用。比如在Pikachu 靶场中的 CSRF(token)题目中的修改用户信息功能时,该插件可以自动处理 Token 的更新,让测试人员专注于其他方面的测试,而无需手动不断更新 Token。
2、插件安装
在extender-bapp store中找到CSRF Token Tracer,双击后右侧点击Install,安装后效果如下。
五、渗透实战
1、用户登录
打开pikachuCSRF(token)题目页面,如下所示是一个登陆页面,如下所示。
http://192.168.59.1/pikachu/vul/csrf/csrftoken/token_get_login.php
输入用户名kobe,密码123456并登录进入到个人会员中心页面,如下所示。
2、修改个人信息
点击修改个人信息,同时bp开启抓包(inception off),具体如下所示。
点击submit,bp截获报文发送到repeater,提交后页面信息如下所示,修改成功。
3、bp拦截报文
bp抓包,再http历史记录中找到修改报文,将修改页面的token_get_edit.php报文发送到repeater。
4、bp改报文探测
将sex改为ljn1022后发包重试,查看网页端信息,发现并没有修改成功,说明服务器后台对token进行校验,导致修改失败。
5、配置CSRF-Token-Tracer
当前访问host为192.168.59.1,token参数赋值为token=4864967170f9942ced091260525,把包中的token值复制到CSRF Token Tracker中实现自动识别token值。特别注意 sync requests based on the following rules部分的勾要选上,如下所示。
6、bp改包成功
再次重放报文,为确保是csrf-token tracer自动获取到token值,配置完成后,第一次重放需要点击两次send,第二次即可修改成功。
7、查看CSRF Token Tracker配置
查看CSRF Token Tracker自动识别到的Token值,之后每次提交的重放都会自动识别并填充token值来实现绕过的目的。