目录
一、CSRF Token
二、代码审计(High级别)
1、渗透准备
2、源码分析
三、渗透实战
1、渗透准备
2、修改URL重放失败
3、burpsuite尝试重放失败
4、安装CSRF Token Tracker
5、安装logger插件
6、配置CSRF Token Tracker
7、bp再次重放报文
8、查看CSRF Token Tracker效果
本系列为通过《DVWA靶场通关笔记》的CSRF关卡(low,medium,high,impossible共4关)渗透集合,通过对相应关卡源码的代码审计找到讲解渗透原理并进行渗透实践,本文为跨站请求伪造CSRF High关卡的渗透部分。
一、CSRF Token
CSRF(Cross-Site Request Forgery,跨站请求伪造)Token 是一种安全机制,用于防止恶意网站利用用户已认证的会话来执行未经授权的操作,核心原理如下所示。
-
服务器为每个会话或表单生成唯一的随机令牌(Token)。
-
令牌嵌入表单或HTTP请求头中。
-
服务器在处理请求时验证令牌的有效性。
-
令牌通常是一次性的或有时效性。
即使攻击者诱使用户访问恶意页面,由于无法获取有效Token,伪造的请求会被服务器拒绝。这种机制有效阻断了CSRF攻击链,是目前最可靠的CSRF防护方案之一。
二、代码审计(High级别)
1、渗透准备
配置security为中等High级别,如下图所示。
进入到CSRF关卡High页面,发现这是一个修改密码的页面,与Low关卡相似,没有确认旧密码的输入框,只有新密码和确认新密码的输入框,具体如下所示。
http://127.0.0.1/DVWA/vulnerabilities/csrf/
2、源码分析
进入DVWA靶场源目录,找到High.php源码,如下所示。
打开源码High.php,分析可知这段代码实现了一个不安全的密码修改功能:该代码实现了用户密码修改的功能。当检测到Change参数存在时,先验证防 CSRF 令牌的有效性。若令牌验证通过,获取用户输入的新密码和确认密码,检查两者是否匹配。若匹配,对新密码进行转义及哈希处理,构建 SQL 语句更新数据库中当前用户的密码,并向用户反馈密码修改成功;若不匹配,则反馈密码不一致的信息。最后关闭数据库连接,并生成新的防 CSRF 令牌。它通过以下步骤实现:
- 检查请求参数:通过 isset($_GET['Change']) 检查是否存在名为 Change 的 GET 参数,以确定是否处理密码更改请求。
- 验证 Anti-CSRF 令牌:调用 checkToken 函数,验证用户提交的 CSRF 令牌是否与会话中的令牌一致,防止 CSRF 攻击。
- 获取用户输入:从 $_GET 中获取用户输入的新密码和确认密码。
- 验证密码一致性:检查新密码和确认密码是否一致。
- 转义和加密密码:对新密码进行转义处理,防止 SQL 注入,然后使用 MD5 加密。
- 更新数据库:将加密后的密码更新到数据库中。
- 反馈用户:根据操作结果,给用户相应的提示信息。
- 生成新的 CSRF 令牌:调用 generateSessionToken 函数,生成新的 CSRF 令牌,用于后续的表单提交。
本关卡相对于low级别增加了token验证,相对于medium级别则是缺少refer字段校验但是增加了token验证。CSRF 令牌验证是指使用checkToken函数验证请求中的user_token与会话中的session_token是否匹配。这要求攻击者必须获取用户的有效令牌,而这在跨站请求中是无法实现的。本关卡也实现了令牌刷新机制,在每次请求后调用generateSessionToken()生成新的令牌,确保每个令牌只能使用一次,增强了安全性。详细注释后的代码如下所示。
<?php
if( isset( $_GET[ 'Change' ] ) ) {// 检查Change参数是否存在,确认用户提交了密码修改请求// 验证CSRF令牌:检查请求中的user_token与会话中的session_token是否匹配// 第三个参数是验证失败时的跳转页面checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// 从GET参数获取新密码和确认密码$pass_new = $_GET[ 'password_new' ];$pass_conf = $_GET[ 'password_conf' ];// 验证两次输入的密码是否一致if( $pass_new == $pass_conf ) {// 密码匹配,准备更新数据库// 使用mysqli_real_escape_string防止SQL注入// 注意:此函数仅对字符串中的特殊字符进行转义$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));// 使用md5哈希密码(注意:md5已不安全,建议使用更安全的哈希算法如password_hash)$pass_new = md5( $pass_new );// 构建SQL查询更新用户密码// dvwaCurrentUser()函数获取当前用户名$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";// 执行SQL查询并处理可能的错误$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );// 显示密码修改成功的消息$html .= "<pre>Password Changed.</pre>";}else {// 密码不匹配,显示错误消息$html .= "<pre>Passwords did not match.</pre>";}// 关闭数据库连接((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
// 生成新的CSRF令牌并存储在会话中
// 用于下次请求时验证
generateSessionToken();
?>
三、渗透实战
1、渗透准备
进入DVWA靶场的CSRF关卡High级别,将密码改为admin,如下所示。
bp开启拦截功能,点击change后,页面URL变为如下所示,包含刚刚修改的密码和确认密码值,还包含了一个新的参数token值,这与我们之前代码分析一致,本关卡还会验证token值。
http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=mooyuan&password_conf=mooyuan&Change=Change&user_token=a6257416ef53bed0a1d1ad062a1d0465#
同时页面信息也发生改变提示修改密码成功(Password changed),如下图红框所示。
bp拦截报文后,在http history中找到这个报文,计划右键将报文发送到repeater模块,具体的效果如下所示。
将报文发送到repeater模块,尝试是否可以进行CSRF攻击伪造,具体效果如下所示。
2、修改URL重放失败
修改URL参数的密码,将新密码和确认密码均修改为000000,完整的URL如下所示。
http://127.0.0.1/dvwa/vulnerabilities/csrf/?password_new=000000&password_conf=000000&Change=Change&user_token=a6257416ef53bed0a1d1ad062a1d0465#
将URL输入到hackbar的地址栏中并点击执行后修改密码失败,提示“CSRF token is incorrect”,如下所示。
这是因为使用token验证后,此时token发生变化校验token失败导致。
3、burpsuite尝试重放失败
由于在地址栏直接修改失败,我们使用bp的CSRF token Tracer来尝试渗透。为了对比CSRF token Tracer的效果,首先展示没有使用CSRF token Tracer的情况下修改密码效果。
在第一步的bp repeater中修改密码,将GET参数中的新密码和确认密码均修改为000000,修改后GET部分内容如下所示。
GET /dvwa/vulnerabilities/csrf/?password_new=000000&password_conf=000000&Change=Change&user_token=a6257416ef53bed0a1d1ad062a1d0465 HTTP/1.1
如下所示,这次http返回的状态值为302,HTTP/1.1 302 Moved Temporarily。故而点击follow redirection如下图左上角的红框所示。
点击follow redirection后,重定向返回结果为CSRF token is incorrect,具体如下所示。
4、安装CSRF Token Tracker
在 Burp Suite 的 BApp Store 中直接安装 CSRF Token Tracker 插件,如下所示。
CSRF Token Tracker 是一款用于渗透测试的 Burp Suite 插件,主要用于自动获取和更新 CSRF Token,从而绕过网站的 CSRF 防护机制。CSRF Token 是一种常见的防御机制,通过在每个请求中添加一个唯一的令牌来验证请求的合法性。CSRF Token Tracker的主要功能如下所示。
- 自动获取 CSRF Token:插件能够自动从服务器响应中提取 CSRF Token,并将其添加到后续的请求中。
- 自动更新 Token:在多次请求中,Token 会自动更新,确保每次请求都使用最新的 Token。
- 绕过 CSRF 防护:通过自动处理 Token,该插件可以帮助测试人员绕过网站的 CSRF 防护,进行诸如暴力破解、数据包重放等测试。
5、安装logger插件
Logger++ 是 Burp Suite 中一款功能强大的日志记录和分析插件,提供了比 Burp 自带日志更强大的记录、过滤和搜索功能,可以记录所有经过 Burp 的 HTTP/HTTPS 流量,为查看repeater修改密码后的报文,安装logger插件,效果如下所示。
6、配置CSRF Token Tracker
当前访问host为127.0.0.1,token参数名为user_token,把包中的user_token值复制到CSRF Token Tracker中实现自动识别token值。特别注意 sync requests based on the following rules部分的勾要选上,如下所示。
7、bp再次重放报文
再次重放3.3部分的报文,为确保是csrf-token tracer自动获取到token值,配置完成后,第一次重放需要点击两次send,第二次即可修改成功。在Logger中找到这个报文,查看token如下所示。
8、查看CSRF Token Tracker效果
查看CSRF Token Tracker自动识别到的user_token值,之后每次提交的重放都会自动识别并填充token值来实现绕过的目的。如下所示,user_token 已经更改为最新的token值。