CSRF 漏洞测试
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 漏洞测试的更多相关文章
- DedeCMS flink_add Getshell漏洞 管理员CSRF漏洞
DedeCMS flink_add Getshell漏洞 管理员CSRF漏洞 1.漏洞利用 由于tpl.php中的$action,$content,$filename变量没有初始化,从而能操纵这些变量 ...
- web端常见安全漏洞测试结果分析-- appscan
基于appscan测试结果分析: 一.XSS跨站脚本 指的是攻击者往Web页面里插入恶意html代码,通常是JavaScript编写的恶意代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被 ...
- 浅谈CSRF漏洞
前言: 看完小迪老师的CSRF漏洞讲解.感觉不行 就自己百度学习.这是总结出来的. 歌曲: 正文: CSRF与xss和像,但是两个是完全不一样的东西. xss攻击(跨站脚本攻击)储存型的XSS ...
- 从Java的角度修复CSRF漏洞
漏洞挖掘中,说实话挖过最多的漏洞就属CSRF漏洞了,提交CSRF漏洞很多次,绕过CSRF防御进行攻击也有很多次.CSRF漏洞是一个很容易引发的问题,今天我从Java的角度来说下这个安全漏洞的修复方案. ...
- 【代码审计】YzmCMS_PHP_v3.6 CSRF漏洞分析
0x00 环境准备 YzmCMS官网:http://www.yzmcms.com/ 程序源码下载:http://pan.baidu.com/s/1pKA4u99 测试网站首页: 0x01 代码分析 ...
- 用代码来细说Csrf漏洞危害以及防御
开头: 废话不多说,直接进主题. 0x01 CSRF介绍:CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session ...
- CSRF漏洞原理说明与利用方法
翻译者:Fireweed 原文链接:http://seclab.stanford.edu/websec/ 一 .什么是CSRF Cross-Site Request Forgery(CSRF),中文一 ...
- csrf漏洞攻击手段和影响详解
针对web应用安全中csrf漏洞两种典型的攻击方式:即输入和执行,这种简单模式下的攻击手段以及中途包含确认页面的攻击方法. 图解什么是csrf漏洞 我们先进行约束,比如存在csrf漏洞的网站叫webA ...
- CSRF漏洞详细说明
CSRF漏洞详细说明 通常情况下,有三种方法被广泛用来防御CSRF攻击:验证token,验证HTTP请求的Referer,还有验证XMLHttpRequests里的自定义header.鉴于种种原因,这 ...
随机推荐
- [R]R包版本更迭【持续更新】
由于R版本更迭,网上或旧的教材上的包可能没有在维护,或者被其他包替代. 做一个表记录碰到的一些替代方案.个人向,非完整指南. * mvpart 2014年之后不再更新,R 3.0版本后无法安装, 提示 ...
- centos7 安装python3.7.11 笔记
安装python依赖包yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-deve ...
- hadoop fs -put 报错
[hadoop@master ~]$ ll total -rw-rw-r-- hadoop hadoop Apr : aaa drwxr-xr-x hadoop hadoop Jun Desktop ...
- Response输出excel设置文本样式
在网上查了些Response导出excel然后设置样式的方法,发现没有一个可行的于是开始自己研究, 发现可以通过输出样式的方式进行配置,我要设置的是全文本格式在excel样式是这样的mso-numbe ...
- [POJ1193][NOI1999]内存分配(链表+模拟)
题意 时 刻 T 内存占用情况 进程事件 0 1 2 3 4 5 6 7 8 9 进程A申请空间(M=3, P=10)<成功> 1 A 2 A B 进程B申请空间(M=4, P=3)< ...
- django用户认证系统——拓展 User 模型
Django 用户认证系统提供了一个内置的 User 对象,用于记录用户的用户名,密码等个人信息.对于 Django 内置的 User 模型, 仅包含以下一些主要的属性: username,即用户名 ...
- Android中ListView的简单使用
动态添加单行列表: 首先前提是你的布局文件里有一个ListView 单行列表的添加只需要一个list集合即可,使用ArrayAdapter数组适配器绑定更新就行了 首先声明一个ArrayAdapter ...
- Linux系统如何添加IP别名
IP别名可以在一块物理网卡上绑定多个IP地址,这样就能够在使用单一网卡的同一个服务器上运行多个基于IP的虚拟主机,简单来说,IP别名就是一张物理网卡上配置多个IP,实现类似子接口之类的功能. 那么IP ...
- anaconda安装opencv(python)
1.win10 win10没有安装python,只安装了anaconda,然后使用pip安装opencv-python,版本很新,opencv_python4.0.0的. 网速有点莫名其妙,时快时慢 ...
- 如何使用微信小程序云函数发送短信验证码
其实微信小程序前端和云端都是可以调用短信平台接口发送短信的,使用云端云函数的好处是无需配置域名,也没有个数限制. 本文使用的是榛子云短信平台(http://smsow.zhenzikj.com) ,S ...