目录
概述
CSRF(Cross-Site Request Forgery,跨站请求伪造) 是一种网络攻击方式。
通过伪造当前用户的行为,让目标服务器误以为请求由当前用户发起,并利用当前用户权限实现业务请求伪造。
例如,假设用户登录了一个银行网站,并且该网站存在 CSRF 漏洞。攻击者可以创建一个恶意网页,其中包含一个指向银行网站的隐藏表单,表单中的操作可能是转账、修改密码等。当用户访问攻击者的恶意网页时,浏览器会自动携带用户在银行网站的登录凭证,向银行网站发送请求并执行表单中的操作,而用户可能完全不知情。
CSRF 攻击通常利用了网站对用户浏览器的信任。为了防范 CSRF 攻击,可以采取以下措施:
- 验证请求的来源,例如通过
Referer
头或Origin
头。 - 在请求中添加不可预测的令牌(token),并在服务器端进行验证。
- 限制请求的方法(如只允许
POST
操作进行关键操作)。
CSRF 是一种具有一定危害性的网络攻击手段,网站开发者需要采取有效的防范措施来保障用户的安全和网站的正常运行。
Low
查看源代码:
php
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$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)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$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>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
代码分析:
先通过GET方法获取Change参数并判空,同样的方式获取password_new和password_conf并进行等值判断。
然后对新密码做转义处理,放置可能的SQL注入,并对其MD5处理。
接着执行一个update语句更新数据库中当前用户的密码。并给出密码已修改的反馈。
当我正常通过页面修改密码时,正常用户视角会产生这么一个链接:
http://192.168.1.24/dvwa/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#
此链接我们可以看到:password_new=123,即新密码是123。password_conf=123,即确认密码是123。
于是我们可以构造一个链接:
此链接我们可以看到是新密码是123456,确认密码是123456,
也就是说这条来链接的作用同样是修改密码,不同的是这条链接是由攻击者视角执行的,攻击者精心构造链恶意链接,通过某些手段发送到用户手上,不知情的用户则会点击该链接,于是在用户合法操作下账户信息悄无声息的被改掉了,而正确的账户信息则在攻击者手里(密码123456)。
在该靶场内,执行此链接,重新登录,账户密码已由123被修改为123456。
Medium
源代码分析:
php
<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Checks to see where the request came from
if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$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)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$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>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
}
else {
// Didn't come from a trusted source
echo "<pre>That request didn't look correct.</pre>";
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
?>
代码分析:
stripos():此函数用来查照字符串在另一字符串第一次出现的位置,stripos(string,start)
该代码主要是在SERVER_NAME中对$_SERVER['HTTP_REFERER']校验,HTTP_REFERER字段实际上表明了该网页原生链接,通常为了提高安全,当直接通过浏览器直接输入URL,可以选择不去发送HTTP_REFERER字段,很明显这里使用该手段。
我们现在以正常用户操作视角下抓包看看:
接下来我们对粘贴的构造的恶意链接进行抓包:
不拿看出两者的区别在于,被粘贴的恶意链接没有出现referer字段,于是插入点就发现了,在我们抓到的包里构造Referer字段。
右键,选择"发送给repeater",并添加referer字段,如下:
我们退出重新登录,此时密码被成功修改。