CSRF简介

CSRF中文名:跨站请求伪造,英文译为:Cross-site request forgery,CSRF攻击就是attacker(攻击者)利用victim(受害者)尚未失效的身份认证信息(cookie、session等),以某种方式诱骗victim点击attacker精心制作的恶意链接或者访问包含恶意攻击代码的页面,当victim触发成功之后,恶意代码会被执行,浏览器默默的向目标service发出请求加载着victim尚未失效的身份认证信息,导致victim替attacker完成了非法操作比如:在某些论坛上发布大量的恶意言论、网站用户密码被恶意篡改、账户金额被盗取、删除网站个人信息~~~~~

漏洞测试

通过DVWA平台,对CSRF漏洞进行测试,让大家走进CSRF的世界

环境:dvwa服务IP      :192.168.43.146

attacker服务IP :192.168.43.150

low level

查看源码:

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

代码审计之后发现:网站没有对CSRF做出防范,只对网站进行了SQL防御(通过mysqli_real_escape_string()函数的过滤作用,将用户传入的数据中的特殊字符进行转义,有效预防了attacker对网站的SQL注入攻击)

mysqli_real_escape_string()函数详细介绍:

定义和用法
mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。 下列字符受影响: \x00
\n
\r
\
'
"
\x1a
如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。 语法
mysql_real_escape_string(string,connection) 参数 描述
string 必需。规定要转义的字符串。
connection 可选。规定 MySQL 连接。如果未规定,则使用上一个连接。 //有效预防了数据库攻击

既然网站没有对CSRF保护那么attacker就可以直接进行攻击

用户正常修改密码:

用户非正常修改密码:

attacker制作含有恶意攻击代码网页

恶意代码:

<iframe hidden src="http://192.168.43.146/dvwa/vulnerabilities/csrf/?password_new=attacker&password_conf=attacker&Change=Change#"></iframe>

attacker将代码嵌入自己的钓鱼网页中,当victim受害者被诱导访问该网页时,恶意代码就会自动被浏览器所执行并携带着victim未失效的身份认证信息向目标服务器发出请求,而victim却毫无察觉,自己的用户密码已经被attacker恶意篡改

victim被attacker诱导浏览自己网站上的图片(恶意代码就隐藏在该网页中)

你会发现该网站一切好像很正常&很美好,但自己却不知道已经被攻击了,网站密码已经被修改为attacker

此时victim再去登陆时会发现自己已经login不上了

medium level

查看源码:

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

代码审计发现:该网站进行了referer字段检测,该字段限制了不是同一个域的不能跨域访问,attacker要想进行CSRF攻击只要绕过if条件就可以,接下来分析该if条件

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

$_SERVER[ 'HTTP_REFERER' ] 获取网页请求的来源URL

$_SERVER[ 'SERVER_NAME' ] 获取目标服务器的域名

$_SERVER[ 'HTTP_REFERER' ]和$_SERVER[ 'SERVER_NAME' ]通过stripos()进行匹配,查看$_SERVER[ 'SERVER_NAME' ]字符串是否包含在$_SERVER[ 'HTTP_REFERER' ]中,从而判断用户的服务请求是否是跨域请求,若是跨域请求则会被目标服务器所拒绝访问

attacker可以有两种方法进行绕过:

第一种:将网页的名字改为$_SERVER[ 'SERVER_NAME' ].html
第二种:添加网页父目录包含$_SERVER[ 'SERVER_NAME' ]

在这里使用第一种方法进行绕过:

victim浏览该网页,恶意代码被成功执行,victim的网站密码被恶意篡改

high level

查看源码:

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

代码审计发现:该网站进行了user_token的检测

user_token:

当用户每次访问修改用户密码页面时,服务器会先返回一个随机的token,接下来当用户向服务器发起修改密码请求时,需要提交user_token,当请求到达服务器时,服务器会优先检查token,判断客户端的token和服务端的token是否匹配,若不匹配,服务器则会拒绝客户端的请求

在这里attacker是不能伪造token的,因为token是一个很长的随机数,attacker要想CSRF攻击成功,只有通过利用网站的XSS漏洞获取用户的token

XSS利用代码获取user_token:

<iframe src="../csrf" onload=alert(document.getElementsByName('user_token'))></iframe>

有关XSS的利用可以查看笔者的这篇文章(https://www.cnblogs.com/qftm/p/10317166.html)

利用user_token进行CSRF攻击

构造恶意代码:

victim浏览存在恶意攻击的网页

攻击成功

impossible level

查看源码:

<?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(); ?>
代码审计发现:用户修改网站密码不仅需要user_token的验证还需要用户输入当前密码进行验证,因此,attacker不能对用户进行CSRF攻击

总结

学过CSRF和XSS之后,你可能会有疑惑,它们两个一样吗,不用多说,相信大家看名字就知道不一样

CSRF攻击是直接利用用户尚未失效的cookie,并伪造特殊的请求对用户造成危害的一种攻击手段

XSS攻击是直接盗取用户的cookie,所造成的一种攻击手段

两者看似相似,当又有一些不一样的地方

CSRF 漏洞测试的更多相关文章

  1. DedeCMS flink_add Getshell漏洞 管理员CSRF漏洞

    DedeCMS flink_add Getshell漏洞 管理员CSRF漏洞 1.漏洞利用 由于tpl.php中的$action,$content,$filename变量没有初始化,从而能操纵这些变量 ...

  2. web端常见安全漏洞测试结果分析-- appscan

    基于appscan测试结果分析: 一.XSS跨站脚本 指的是攻击者往Web页面里插入恶意html代码,通常是JavaScript编写的恶意代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被 ...

  3. 浅谈CSRF漏洞

    前言: 看完小迪老师的CSRF漏洞讲解.感觉不行 就自己百度学习.这是总结出来的.   歌曲:   正文: CSRF与xss和像,但是两个是完全不一样的东西. xss攻击(跨站脚本攻击)储存型的XSS ...

  4. 从Java的角度修复CSRF漏洞

    漏洞挖掘中,说实话挖过最多的漏洞就属CSRF漏洞了,提交CSRF漏洞很多次,绕过CSRF防御进行攻击也有很多次.CSRF漏洞是一个很容易引发的问题,今天我从Java的角度来说下这个安全漏洞的修复方案. ...

  5. 【代码审计】YzmCMS_PHP_v3.6 CSRF漏洞分析

      0x00 环境准备 YzmCMS官网:http://www.yzmcms.com/ 程序源码下载:http://pan.baidu.com/s/1pKA4u99 测试网站首页: 0x01 代码分析 ...

  6. 用代码来细说Csrf漏洞危害以及防御

    开头: 废话不多说,直接进主题. 0x01 CSRF介绍:CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session ...

  7. CSRF漏洞原理说明与利用方法

    翻译者:Fireweed 原文链接:http://seclab.stanford.edu/websec/ 一 .什么是CSRF Cross-Site Request Forgery(CSRF),中文一 ...

  8. csrf漏洞攻击手段和影响详解

    针对web应用安全中csrf漏洞两种典型的攻击方式:即输入和执行,这种简单模式下的攻击手段以及中途包含确认页面的攻击方法. 图解什么是csrf漏洞 我们先进行约束,比如存在csrf漏洞的网站叫webA ...

  9. CSRF漏洞详细说明

    CSRF漏洞详细说明 通常情况下,有三种方法被广泛用来防御CSRF攻击:验证token,验证HTTP请求的Referer,还有验证XMLHttpRequests里的自定义header.鉴于种种原因,这 ...

随机推荐

  1. 再回首数据结构—数组(Golang实现)

    数组为线性数据结构,通常编程语言都有自带了数组数据类型结构,数组存放的是有个相同数据类型的数据集: 为什么称数组为线性数据结构:因为数组在内存中是连续存储的数据结构,数组中每个元素最多只有左右两个方向 ...

  2. node06

    1.数据库: server端:数据存在 client端:管理工具,node mysql内有两个单位: 库:类似文件夹,容纳表 表:存储数据 行:一条数据 列(字段,域):一个数据项 主键:数据的唯一标 ...

  3. [Lyft Level 5 Challenge 2018 - Elimination Round][Codeforces 1033D. Divisors]

    题目链接:1033D - Divisors 题目大意:给定\(n\)个数\(a_i\),每个数的约数个数为3到5个,求\(\prod_{i=1}^{n}a_i\)的约数个数.其中\(1 \leq n ...

  4. php使用protobuf3

    protoc的介绍,安装 1.定义一个protoc 文件 示例:person.proto syntax="proto3"; //声明版本,3x版本支持php package tes ...

  5. anaconda安装opencv(python)

    1.win10 win10没有安装python,只安装了anaconda,然后使用pip安装opencv-python,版本很新,opencv_python4.0.0的. 网速有点莫名其妙,时快时慢 ...

  6. 三、糖醋鲤鱼(Sweet and sour carp)

    糖醋鲤鱼是用鲤鱼制作的一道山东济南传统名菜,为鲁菜的代表菜品之一 ,色泽金黄,外焦内嫩,酸甜可口,香鲜味美. 菜品历史 <诗经>载:岂食其鱼,必河之鲤.<济南府志>上早有&qu ...

  7. 34 文件地理数据库(GDB)变文件夹了怎么办

    我们都知道文件地理数据库(GDB)是ArcGIS软件特有的格式,有其独特的设计之处,在文件资源管理器中显示为.gdb的文件夹,但是里面的文件却看不明白,而且将gdb文件夹在Windows资源管理器中直 ...

  8. 根据excel表格字段生成sql语句

    根据excel表格字段生成sql语句 1.1 前言 根据excel表格字段生成sql语句主要是利用了excel的拼接函数 CONCATENATE .该实例主要以mysql脚本支持.实例需求如下:exc ...

  9. Javascript高级编程学习笔记(90)—— Canvas(7) 绘制图像

    绘制图像 2D绘图上下文内置了对图像的支持 如果希望将一幅图绘制到画布上,可以使用 drawImage() 的方法 该方法有三种不同的参数数组合以对应不同的应用场景 将<img>绘制到画布 ...

  10. [Swift]LeetCode78. 子集 | Subsets

    Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The solut ...