csrf(Cross-site request forgery)跨站请求伪造:攻击者诱导用户访问第三方网站,在第三方网站中携带恶意代码,向被攻击者发送请求

原理可以这样来说

用户在访问了一个后台管理网站后,例如用户更改密码,但是更改密码需要登录认证的,用户在登录后,浏览器会保存认证一段时间,叫做cookie,保证下次访问不在弹出登录框

这个时候攻击者恶意伪造一个网站,这个网站的功能是更改用户的密码,但是攻击者没有用户的cookie,是无法更改密码的,攻击者通过诱导用户点击恶意网页,由于用户浏览器带有后台管理网站的cookie,恶意网页这是请求更改密码就会执行成功,导致用户什么都不知道,密码就被修改了

LOW

审计源码

<?php
// 判断有没有接收到Change
if( isset( $_GET[ 'Change' ] ) ) {
// 获取输入的两次密码
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ]; // 两次输入密码是否相同
if( $pass_new == $pass_conf ) {
// 相同
$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加密新密码
$pass_new = md5( $pass_new ); // 更新数据库密码
$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>' ); // 密码更改成功
echo "<pre>Password Changed.</pre>";
}
else {
// 两次密码输入不相同,密码更改失败
echo "<pre>Passwords did not match.</pre>";
} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
} ?>

通过代码可以看出,Low没有做任何过滤,并且是一个更改密码操作

首先更改一次密码,获取更改密码的url



http://172.16.1.103/dvwa/vulnerabilities/csrf/?password_new=Admin123&password_conf=Admin123&Change=Change#

这里可以看到将密码更改为了Admin123

再次打开一个firefox,将链接粘贴的url中

http://172.16.1.103/dvwa/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#



退出DVWA登录,使用123456登录靶场





可以看到,密码已经被更改成功

构造恶意网页

kali另一台机器上写入恶意网页

<img src="http://172.16.1.103/dvwa/vulnerabilities/csrf/?password_new=Admin123&password_conf=Admin123&Change=Change#" style="display:none"/>
<h1>Test HTML</h1>



使用登录DVWA靶场的firefox访问恶意网页



在访问后,回到DVWA退出登录,查看密码是否更改成功



可以看到,只有使用Admin123才可以登录成功

Medium

审计源码

<?php

if( isset( $_GET[ 'Change' ] ) ) {
// 检查 http_referer 是否是 访问服务器的访问名称
// stripos() 查找字符串首次出现的位置
// $_SERVER变量 获取 http_referer 的值,server_name获取服务端的名称例如:www.baidu.com
if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
// 获取两次输入的密码
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ]; // 判断两次密码是否相同
if( $pass_new == $pass_conf ) {
// 相同
$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 加密输入新密码
$pass_new = md5( $pass_new ); // 更改密码
$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>' ); // 更改密码成功
echo "<pre>Password Changed.</pre>";
}
else {
// 更改密码失败
echo "<pre>Passwords did not match.</pre>";
}
}
else {
// rerfer值不正确
echo "<pre>That request didn't look correct.</pre>";
} ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
} ?>

通过观察,使用

stripos()查找一个字符串时第一次出现的位置,

HTTP_REFERER是获取HTTP请求头中的REferer值,用来告诉服务端来自哪里的请求

SERVER_NAME访问目标的主机名

总体来说就是检查header中的Referer中是否含有服务端主机名

修改密码抓包查看数据包结构



可以看到,Referer中默认就是来自http://172.16.1.103/dvwa/vulnerabilities/csrf/

所以密码可以修改成功,这里密码修改,只要是Referer中含有服务器主机名就可以成功

我们直接修改为Referer:172.16.1.103





可以看到密码是可以修改成功的

但是,真正的CSRF是,诱导点击,访问恶意网页进行修改,我们这里只是通过burpsuite更改密码成功

恶意文件修改密码

这里我已失败告终了,学术不精,到底该如何在点击访问时更改Referer的值呢?

High

审计源码

<?php

// 定义改变默认为 false
$change = false;
// 定义请求类型默认为 html
$request_type = "html";
// 定义返回信息默认为 返回失败
$return_message = "Request Failed"; // 判断 change 是否为true
if ($_SERVER['REQUEST_METHOD'] == "POST" && array_key_exists ("CONTENT_TYPE", $_SERVER) && $_SERVER['CONTENT_TYPE'] == "application/json") {
$data = json_decode(file_get_contents('php://input'), true);
$request_type = "json";
if (array_key_exists("HTTP_USER_TOKEN", $_SERVER) &&
array_key_exists("password_new", $data) &&
array_key_exists("password_conf", $data) &&
array_key_exists("Change", $data)) {
$token = $_SERVER['HTTP_USER_TOKEN'];
$pass_new = $data["password_new"];
$pass_conf = $data["password_conf"];
$change = true;
}
} else {
if (array_key_exists("user_token", $_REQUEST) &&
array_key_exists("password_new", $_REQUEST) &&
array_key_exists("password_conf", $_REQUEST) &&
array_key_exists("Change", $_REQUEST)) {
$token = $_REQUEST["user_token"];
$pass_new = $_REQUEST["password_new"];
$pass_conf = $_REQUEST["password_conf"];
$change = true;
}
} if ($change) {
// 检查 user_token
checkToken( $token, $_SESSION[ 'session_token' ], 'index.php' ); // 判断输入的两次密码是否相同
if( $pass_new == $pass_conf ) {
// 使用md5加密输入的新密码
$pass_new = mysqli_real_escape_string ($GLOBALS["___mysqli_ston"], $pass_new);
$pass_new = md5( $pass_new ); // 更新用户的密码
$insert = "UPDATE `users` SET password = '" . $pass_new . "' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ); // 密码更改成功提示
$return_message = "Password Changed.";
}
else {
// 提示密码更改失败
$return_message = "Passwords did not match.";
} mysqli_close($GLOBALS["___mysqli_ston"]); if ($request_type == "json") {
generateSessionToken();
header ("Content-Type: application/json");
print json_encode (array("Message" =>$return_message));
exit;
} else {
echo "<pre>" . $return_message . "</pre>";
}
} // 生成token
generateSessionToken(); ?>

通过观察这里引入了一个user_token,防止点击修改密码,但是可以通过抓包的方式修改user_token

更改密码为Admin123抓包查看



这里的user_token在每一次更改密码服务器都会刷新返回一个;

通过同等级XSS (Reflected)漏洞获取user_token,然后通过获取的user_token更改密码,

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



这样确实可以获取user_token.

上述这个方法其实和在CSRF页面查看源代码获取user_token的方法类似



上述两个方法确实都获取到了user_token,但是并没有点击就可以修改用户密码,还是需要通过抓包更改密码;

所以如果要实现真正的CSRF,需要写一个javascript诱导用户点击,获取其user_token,然后通过获取的user_token更改密码

到底该怎么实现?由于我没有学过javascript,所以如何获取就不得而知,后续再来补坑吧。

Impossible

审计源码


<?php if( isset( $_GET[ 'Change' ] ) ) {
// 获取并检查 user_token 是否正常
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // 获取 上次密码 和 两次输入的新密码
$pass_curr = $_GET[ 'password_current' ];
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ]; // 去除获取当前密码中的 /
$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)) ? "" : ""));
// 使用 md5 加密获取的当前密码
$pass_curr = md5( $pass_curr ); // 检查当前密码是否正确
$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(); // 判断输入两次新密码是否相同 和 输入当前密码是否正确
if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {
// 正确
// 去除新密码中的 /
$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)) ? "" : ""));
// 使用 md5 加密新密码
$pass_new = md5( $pass_new ); // 更新数据库中的密码为新密码
$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(); // 返回更改密码成功
echo "<pre>Password Changed.</pre>";
}
else {
// 否则返回错误
echo "<pre>Passwords did not match or current password incorrect.</pre>";
}
} // 生成 user_token 认证
generateSessionToken(); ?>

可以看到这里既引入了user_token认证,也去除了密码中的/,最重要的是需要输入当前的密码,才可以更改密码。

唯一不好的就是更改密码为GET请求方式,换为POST更好,可能是作者想方便测试吧

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

  1. python CSRF跨站请求伪造

    python CSRF跨站请求伪造 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...

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

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

  3. ajax向Django前后端提交请求和CSRF跨站请求伪造

    1.ajax登录示例 urls.py from django.conf.urls import url from django.contrib import admin from app01 impo ...

  4. python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)

    一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 from app01 import views urlpatterns = [ path('admin/', admi ...

  5. 第三百一十五节,Django框架,CSRF跨站请求伪造

    第三百一十五节,Django框架,CSRF跨站请求伪造  全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.midd ...

  6. Django中的CSRF(跨站请求伪造)

    Django中的CSRF(跨站请求伪造) Django CSRF  什么是CSFR 即跨站请求伪装,就是通常所说的钓鱼网站. 钓鱼网站的页面和正经网站的页面对浏览器来说有什么区别? (页面是怎么来的? ...

  7. Django框架 之 基于Ajax中csrf跨站请求伪造

    Django框架 之 基于Ajax中csrf跨站请求伪造 ajax中csrf跨站请求伪造 方式一 1 2 3 $.ajaxSetup({     data: {csrfmiddlewaretoken: ...

  8. 十三 Django框架,CSRF跨站请求伪造

     全局CSRF 如果要启用防止CSRF跨站请求伪造,就需要在中间件开启CSRF #中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMidd ...

  9. Web框架之Django_09 重要组件(Django中间件、csrf跨站请求伪造)

    摘要 Django中间件 csrf跨站请求伪造 一.Django中间件: 什么是中间件? 官方的说法:中间件是一个用来处理Django的请求和响应的框架级别的钩子.它是一个轻量.低级别的插件系统,用于 ...

  10. django上课笔记3-ORM补充-CSRF (跨站请求伪造)

    一.ORM补充 ORM操作三大难点: 正向操作反向操作连表 其它基本操作(包含F Q extra) 性能相关的操作 class UserInfo(models.Model): uid = models ...

随机推荐

  1. jmeter参数化时最常用随机函数

    邮箱类: ${__RandomString(8,abcdefghijklmnopqrstuvwxyz,)}@126.com 手机号类: ${__Random(18000000000,189999999 ...

  2. 疫情实时大数据报告(利用nodejs)

    一转眼2020年,工作三年是时候向全栈工程师出发了,大家放心头发还在.话不多少进入正题 一.看一下效果 二.看一下代码 相关的node代码: 这里主要利用node的爬虫技术,爬的别人的数据.cheer ...

  3. pandas的数据结构--Series创建使用

    # 1. 使用Series创建一个空的系列:import pandas as pds=pd.Series()print(s)输出结果为:Series([], dtype: float64) # 2. ...

  4. 天龙八部<三联版>四 终

    叶二娘与虚竹相认,但黑衣僧却一语道破天机,原来虚竹乃是叶二娘与少林一位高僧的私生子,而黑衣僧,便是三十年前雁门关外的男主演萧远山,虚竹是萧远山所盗,而原因是因为虚竹的父亲乃是当年的带头大哥.迫于压力玄 ...

  5. 关于JDK1.8 java HashMap的tableSizeFor的解析:一个数最近2的幂次数方法

    简介 一个数的最近2的幂次数,是java hashmap初始化方法指定容量里面对容量进行处理采用的方法 1.位运算符号介绍 符号 描述 运算规则 & 与 两个位都为1时,结果才为1 | 或 两 ...

  6. LeetCode 删除数组中重复项 26 80

    26(80) 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素只出现一次(使得出现次数超过两次的元素只出现两次 ) ,返回删除后数组的新长度.元素的 相对顺序 应该保 ...

  7. openSUSE 15.4 安装 Deepin Wine QQ

    1. 准备: deepin-wine5 deepin-wine-qq deepin-wine-helper 这三个包我是在openSUSE网站上搜索到的,https://software.opensu ...

  8. Flutter showModalBottomSheet 自适应高度

    showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRad ...

  9. Email Windows发送成功,Linux却发送失败的可能原因

    一.linux端口被禁用,通过telnet查看.(我这里没问题) 二.排查环境参数是否一致(我这里没问题) 三.查看jdk版本原因,因为jdk1.8有的版本禁用了ssl 参阅文档:https://bl ...

  10. vue 打包后可放置在任意名称的文件夹下

    1. build->utils.js: 2. build->webpack.prod.conf.js: 3. config->index.js: